refactor: entity -> MutableSignal
This commit is contained in:
parent
b1b059de8c
commit
86714e7837
|
|
@ -1,4 +1,4 @@
|
||||||
import {entity, Entity} from "@/utils/entity";
|
import {MutableSignal, mutableSignal} from "@/utils/mutable-signal";
|
||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
CommandRegistry,
|
CommandRegistry,
|
||||||
|
|
@ -12,16 +12,16 @@ import {
|
||||||
} from "@/utils/command";
|
} from "@/utils/command";
|
||||||
|
|
||||||
export interface IGameContext<TState extends Record<string, unknown> = {} > {
|
export interface IGameContext<TState extends Record<string, unknown> = {} > {
|
||||||
state: Entity<TState>;
|
state: MutableSignal<TState>;
|
||||||
commands: CommandRunnerContextExport<Entity<TState>>;
|
commands: CommandRunnerContextExport<MutableSignal<TState>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createGameContext<TState extends Record<string, unknown> = {} >(
|
export function createGameContext<TState extends Record<string, unknown> = {} >(
|
||||||
commandRegistry: CommandRegistry<Entity<TState>>,
|
commandRegistry: CommandRegistry<MutableSignal<TState>>,
|
||||||
initialState?: TState | (() => TState)
|
initialState?: TState | (() => TState)
|
||||||
): IGameContext<TState> {
|
): IGameContext<TState> {
|
||||||
const stateValue = typeof initialState === 'function' ? initialState() : initialState ?? {} as TState;
|
const stateValue = typeof initialState === 'function' ? initialState() : initialState ?? {} as TState;
|
||||||
const state = entity('state', stateValue);
|
const state = mutableSignal(stateValue);
|
||||||
const commands = createCommandRunnerContext(commandRegistry, state);
|
const commands = createCommandRunnerContext(commandRegistry, state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -36,7 +36,7 @@ export function createGameContext<TState extends Record<string, unknown> = {} >(
|
||||||
*/
|
*/
|
||||||
export function createGameContextFromModule<TState extends Record<string, unknown> = {} >(
|
export function createGameContextFromModule<TState extends Record<string, unknown> = {} >(
|
||||||
module: {
|
module: {
|
||||||
registry: CommandRegistry<Entity<TState>>,
|
registry: CommandRegistry<MutableSignal<TState>>,
|
||||||
createInitialState: () => TState
|
createInitialState: () => TState
|
||||||
},
|
},
|
||||||
): IGameContext<TState> {
|
): IGameContext<TState> {
|
||||||
|
|
@ -44,12 +44,12 @@ export function createGameContextFromModule<TState extends Record<string, unknow
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createGameCommandRegistry<TState extends Record<string, unknown> = {} >() {
|
export function createGameCommandRegistry<TState extends Record<string, unknown> = {} >() {
|
||||||
const registry = createCommandRegistry<Entity<TState>>();
|
const registry = createCommandRegistry<MutableSignal<TState>>();
|
||||||
return {
|
return {
|
||||||
registry,
|
registry,
|
||||||
add<TResult = unknown>(
|
add<TResult = unknown>(
|
||||||
schema: CommandSchema | string,
|
schema: CommandSchema | string,
|
||||||
run: (this: CommandRunnerContext<Entity<TState>>, command: Command) => Promise<TResult>
|
run: (this: CommandRunnerContext<MutableSignal<TState>>, command: Command) => Promise<TResult>
|
||||||
){
|
){
|
||||||
createGameCommand(registry, schema, run);
|
createGameCommand(registry, schema, run);
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -58,9 +58,9 @@ export function createGameCommandRegistry<TState extends Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createGameCommand<TState extends Record<string, unknown> = {} , TResult = unknown>(
|
export function createGameCommand<TState extends Record<string, unknown> = {} , TResult = unknown>(
|
||||||
registry: CommandRegistry<Entity<TState>>,
|
registry: CommandRegistry<MutableSignal<TState>>,
|
||||||
schema: CommandSchema | string,
|
schema: CommandSchema | string,
|
||||||
run: (this: CommandRunnerContext<Entity<TState>>, command: Command) => Promise<TResult>
|
run: (this: CommandRunnerContext<MutableSignal<TState>>, command: Command) => Promise<TResult>
|
||||||
) {
|
) {
|
||||||
registerCommand(registry, {
|
registerCommand(registry, {
|
||||||
schema: typeof schema === 'string' ? parseCommandSchema(schema) : schema,
|
schema: typeof schema === 'string' ? parseCommandSchema(schema) : schema,
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ export { parseCommand, parseCommandSchema, validateCommand, parseCommandWithSche
|
||||||
export type { CommandRunner, CommandRunnerHandler, CommandRunnerContext, PromptEvent, CommandRunnerEvents } from './utils/command';
|
export type { CommandRunner, CommandRunnerHandler, CommandRunnerContext, PromptEvent, CommandRunnerEvents } from './utils/command';
|
||||||
export { createCommandRegistry, registerCommand, unregisterCommand, hasCommand, getCommand, runCommand, runCommandParsed, createCommandRunnerContext, type CommandRegistry, type CommandRunnerContextExport } from './utils/command';
|
export { createCommandRegistry, registerCommand, unregisterCommand, hasCommand, getCommand, runCommand, runCommandParsed, createCommandRunnerContext, type CommandRegistry, type CommandRunnerContextExport } from './utils/command';
|
||||||
|
|
||||||
export type { Entity } from './utils/entity';
|
export type { MutableSignal } from './utils/mutable-signal';
|
||||||
export { createEntityCollection, entity } from './utils/entity';
|
export { mutableSignal, createEntityCollection } from './utils/mutable-signal';
|
||||||
|
|
||||||
export type { RNG } from './utils/rng';
|
export type { RNG } from './utils/rng';
|
||||||
export { createRNG, Mulberry32RNG } from './utils/rng';
|
export { createRNG, Mulberry32RNG } from './utils/rng';
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import {createGameCommandRegistry, Part, Entity, createRegion} from '@/index';
|
import {createGameCommandRegistry, Part, MutableSignal, createRegion} from '@/index';
|
||||||
|
|
||||||
const BOARD_SIZE = 6;
|
const BOARD_SIZE = 6;
|
||||||
const MAX_PIECES_PER_PLAYER = 8;
|
const MAX_PIECES_PER_PLAYER = 8;
|
||||||
|
|
@ -48,7 +48,7 @@ export type BoopState = ReturnType<typeof createInitialState>;
|
||||||
const registration = createGameCommandRegistry<BoopState>();
|
const registration = createGameCommandRegistry<BoopState>();
|
||||||
export const registry = registration.registry;
|
export const registry = registration.registry;
|
||||||
|
|
||||||
export function getPlayer(host: Entity<BoopState>, player: PlayerType): Player {
|
export function getPlayer(host: MutableSignal<BoopState>, player: PlayerType): Player {
|
||||||
return host.value.players[player];
|
return host.value.players[player];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,23 +152,23 @@ function isValidMove(row: number, col: number): boolean {
|
||||||
return !isNaN(row) && !isNaN(col) && row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE;
|
return !isNaN(row) && !isNaN(col) && row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBoardRegion(host: Entity<BoopState>) {
|
export function getBoardRegion(host: MutableSignal<BoopState>) {
|
||||||
return host.value.board;
|
return host.value.board;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCellOccupied(host: Entity<BoopState>, row: number, col: number): boolean {
|
export function isCellOccupied(host: MutableSignal<BoopState>, row: number, col: number): boolean {
|
||||||
const board = getBoardRegion(host);
|
const board = getBoardRegion(host);
|
||||||
return board.partMap[`${row},${col}`] !== undefined;
|
return board.partMap[`${row},${col}`] !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPartAt(host: Entity<BoopState>, row: number, col: number): BoopPart | null {
|
export function getPartAt(host: MutableSignal<BoopState>, row: number, col: number): BoopPart | null {
|
||||||
const board = getBoardRegion(host);
|
const board = getBoardRegion(host);
|
||||||
const partId = board.partMap[`${row},${col}`];
|
const partId = board.partMap[`${row},${col}`];
|
||||||
if (!partId) return null;
|
if (!partId) return null;
|
||||||
return host.value.pieces.find(p => p.id === partId) || null;
|
return host.value.pieces.find(p => p.id === partId) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function placePiece(host: Entity<BoopState>, row: number, col: number, player: PlayerType, pieceType: PieceType) {
|
export function placePiece(host: MutableSignal<BoopState>, row: number, col: number, player: PlayerType, pieceType: PieceType) {
|
||||||
const board = getBoardRegion(host);
|
const board = getBoardRegion(host);
|
||||||
const playerData = getPlayer(host, player);
|
const playerData = getPlayer(host, player);
|
||||||
const count = playerData[pieceType].placed + 1;
|
const count = playerData[pieceType].placed + 1;
|
||||||
|
|
@ -188,7 +188,7 @@ export function placePiece(host: Entity<BoopState>, row: number, col: number, pl
|
||||||
decrementSupply(playerData, pieceType);
|
decrementSupply(playerData, pieceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyBoops(host: Entity<BoopState>, placedRow: number, placedCol: number, placedType: PieceType) {
|
export function applyBoops(host: MutableSignal<BoopState>, placedRow: number, placedCol: number, placedType: PieceType) {
|
||||||
const board = getBoardRegion(host);
|
const board = getBoardRegion(host);
|
||||||
const pieces = host.value.pieces;
|
const pieces = host.value.pieces;
|
||||||
|
|
||||||
|
|
@ -237,7 +237,7 @@ export function applyBoops(host: Entity<BoopState>, placedRow: number, placedCol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removePieceFromBoard(host: Entity<BoopState>, part: BoopPart) {
|
export function removePieceFromBoard(host: MutableSignal<BoopState>, part: BoopPart) {
|
||||||
const board = getBoardRegion(host);
|
const board = getBoardRegion(host);
|
||||||
const playerData = getPlayer(host, part.player);
|
const playerData = getPlayer(host, part.player);
|
||||||
board.childIds = board.childIds.filter(id => id !== part.id);
|
board.childIds = board.childIds.filter(id => id !== part.id);
|
||||||
|
|
@ -297,7 +297,7 @@ export function hasWinningLine(positions: number[][]): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkGraduation(host: Entity<BoopState>, player: PlayerType): number[][][] {
|
export function checkGraduation(host: MutableSignal<BoopState>, player: PlayerType): number[][][] {
|
||||||
const pieces = host.value.pieces;
|
const pieces = host.value.pieces;
|
||||||
const posSet = new Set<string>();
|
const posSet = new Set<string>();
|
||||||
|
|
||||||
|
|
@ -316,7 +316,7 @@ export function checkGraduation(host: Entity<BoopState>, player: PlayerType): nu
|
||||||
return winningLines;
|
return winningLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processGraduation(host: Entity<BoopState>, player: PlayerType, lines: number[][][]) {
|
export function processGraduation(host: MutableSignal<BoopState>, player: PlayerType, lines: number[][][]) {
|
||||||
const allPositions = new Set<string>();
|
const allPositions = new Set<string>();
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
for (const [r, c] of line) {
|
for (const [r, c] of line) {
|
||||||
|
|
@ -338,12 +338,12 @@ export function processGraduation(host: Entity<BoopState>, player: PlayerType, l
|
||||||
incrementSupply(playerData, 'cat', count);
|
incrementSupply(playerData, 'cat', count);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function countPiecesOnBoard(host: Entity<BoopState>, player: PlayerType): number {
|
export function countPiecesOnBoard(host: MutableSignal<BoopState>, player: PlayerType): number {
|
||||||
const pieces = host.value.pieces;
|
const pieces = host.value.pieces;
|
||||||
return pieces.filter(p => p.player === player).length;
|
return pieces.filter(p => p.player === player).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkWinner(host: Entity<BoopState>): WinnerType {
|
export function checkWinner(host: MutableSignal<BoopState>): WinnerType {
|
||||||
const pieces = host.value.pieces;
|
const pieces = host.value.pieces;
|
||||||
|
|
||||||
for (const player of ['white', 'black'] as PlayerType[]) {
|
for (const player of ['white', 'black'] as PlayerType[]) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import {createGameCommandRegistry, Part, Entity, createRegion, moveToRegion} from '@/index';
|
import {createGameCommandRegistry, Part, MutableSignal, createRegion, moveToRegion} from '@/index';
|
||||||
|
|
||||||
const BOARD_SIZE = 3;
|
const BOARD_SIZE = 3;
|
||||||
const MAX_TURNS = BOARD_SIZE * BOARD_SIZE;
|
const MAX_TURNS = BOARD_SIZE * BOARD_SIZE;
|
||||||
|
|
@ -90,7 +90,7 @@ function isValidMove(row: number, col: number): boolean {
|
||||||
return !isNaN(row) && !isNaN(col) && row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE;
|
return !isNaN(row) && !isNaN(col) && row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCellOccupied(host: Entity<TicTacToeState>, row: number, col: number): boolean {
|
export function isCellOccupied(host: MutableSignal<TicTacToeState>, row: number, col: number): boolean {
|
||||||
const board = host.value.board;
|
const board = host.value.board;
|
||||||
return board.partMap[`${row},${col}`] !== undefined;
|
return board.partMap[`${row},${col}`] !== undefined;
|
||||||
}
|
}
|
||||||
|
|
@ -103,7 +103,7 @@ export function hasWinningLine(positions: number[][]): boolean {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkWinner(host: Entity<TicTacToeState>): WinnerType {
|
export function checkWinner(host: MutableSignal<TicTacToeState>): WinnerType {
|
||||||
const parts = Object.values(host.value.parts);
|
const parts = Object.values(host.value.parts);
|
||||||
|
|
||||||
const xPositions = parts.filter((p: TicTacToePart) => p.player === 'X').map((p: TicTacToePart) => p.position);
|
const xPositions = parts.filter((p: TicTacToePart) => p.player === 'X').map((p: TicTacToePart) => p.position);
|
||||||
|
|
@ -116,7 +116,7 @@ export function checkWinner(host: Entity<TicTacToeState>): WinnerType {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function placePiece(host: Entity<TicTacToeState>, row: number, col: number, player: PlayerType) {
|
export function placePiece(host: MutableSignal<TicTacToeState>, row: number, col: number, player: PlayerType) {
|
||||||
const board = host.value.board;
|
const board = host.value.board;
|
||||||
const moveNumber = Object.keys(host.value.parts).length + 1;
|
const moveNumber = Object.keys(host.value.parts).length + 1;
|
||||||
const piece: TicTacToePart = {
|
const piece: TicTacToePart = {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import {Signal, signal, SignalOptions} from "@preact/signals-core";
|
import {Signal, signal, SignalOptions} from "@preact/signals-core";
|
||||||
import {create} from 'mutative';
|
import {create} from 'mutative';
|
||||||
|
|
||||||
export class Entity<T> extends Signal<T> {
|
export class MutableSignal<T> extends Signal<T> {
|
||||||
public constructor(public readonly id: string, t?: T, options?: SignalOptions<T>) {
|
public constructor(t?: T, options?: SignalOptions<T>) {
|
||||||
super(t, options);
|
super(t, options);
|
||||||
}
|
}
|
||||||
produce(fn: (draft: T) => void) {
|
produce(fn: (draft: T) => void) {
|
||||||
|
|
@ -10,19 +10,19 @@ export class Entity<T> extends Signal<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function entity<T = undefined>(id: string, t?: T, options?: SignalOptions<T>) {
|
export function mutableSignal<T>(initial?: T, options?: SignalOptions<T>): MutableSignal<T> {
|
||||||
return new Entity<T>(id, t, options);
|
return new MutableSignal<T>(initial, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EntityCollection<T> = {
|
export type EntityCollection<T> = {
|
||||||
collection: Signal<Record<string, Entity<T>>>;
|
collection: Signal<Record<string, MutableSignal<T>>>;
|
||||||
remove(...ids: string[]): void;
|
remove(...ids: string[]): void;
|
||||||
add(...entities: (T & {id: string})[]): void;
|
add(...entities: (T & {id: string})[]): void;
|
||||||
get(id: string): Entity<T>;
|
get(id: string): MutableSignal<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createEntityCollection<T>(): EntityCollection<T> {
|
export function createEntityCollection<T>(): EntityCollection<T> {
|
||||||
const collection = signal({} as Record<string, Entity<T>>);
|
const collection = signal({} as Record<string, MutableSignal<T>>);
|
||||||
const remove = (...ids: string[]) => {
|
const remove = (...ids: string[]) => {
|
||||||
collection.value = Object.fromEntries(
|
collection.value = Object.fromEntries(
|
||||||
Object.entries(collection.value).filter(([id]) => !ids.includes(id)),
|
Object.entries(collection.value).filter(([id]) => !ids.includes(id)),
|
||||||
|
|
@ -32,7 +32,7 @@ export function createEntityCollection<T>(): EntityCollection<T> {
|
||||||
const add = (...entities: (T & {id: string})[]) => {
|
const add = (...entities: (T & {id: string})[]) => {
|
||||||
collection.value = {
|
collection.value = {
|
||||||
...collection.value,
|
...collection.value,
|
||||||
...Object.fromEntries(entities.map((e) => [e.id, entity(e.id, e)])),
|
...Object.fromEntries(entities.map((e) => [e.id, mutableSignal(e)])),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ import {
|
||||||
PlayerType,
|
PlayerType,
|
||||||
getBoardRegion,
|
getBoardRegion,
|
||||||
} from '@/samples/boop';
|
} from '@/samples/boop';
|
||||||
import {Entity} from "@/utils/entity";
|
import {MutableSignal} from "@/utils/entity";
|
||||||
import {createGameContext} from "@/";
|
import {createGameContext} from "@/";
|
||||||
import type { PromptEvent } from '@/utils/command';
|
import type { PromptEvent } from '@/utils/command';
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ function createTestContext() {
|
||||||
return { registry, ctx };
|
return { registry, ctx };
|
||||||
}
|
}
|
||||||
|
|
||||||
function getState(ctx: ReturnType<typeof createTestContext>['ctx']): Entity<BoopState> {
|
function getState(ctx: ReturnType<typeof createTestContext>['ctx']): MutableSignal<BoopState> {
|
||||||
return ctx.state;
|
return ctx.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ function waitForPrompt(ctx: ReturnType<typeof createTestContext>['ctx']): Promis
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getParts(state: Entity<BoopState>) {
|
function getParts(state: MutableSignal<BoopState>) {
|
||||||
return state.value.pieces;
|
return state.value.pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import {
|
||||||
TicTacToeState,
|
TicTacToeState,
|
||||||
WinnerType, PlayerType
|
WinnerType, PlayerType
|
||||||
} from '@/samples/tic-tac-toe';
|
} from '@/samples/tic-tac-toe';
|
||||||
import {Entity} from "@/utils/entity";
|
import {MutableSignal} from "@/utils/mutable-signal";
|
||||||
import {createGameContext} from "@/";
|
import {createGameContext} from "@/";
|
||||||
import type { PromptEvent } from '@/utils/command';
|
import type { PromptEvent } from '@/utils/command';
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ function createTestContext() {
|
||||||
return { registry, ctx };
|
return { registry, ctx };
|
||||||
}
|
}
|
||||||
|
|
||||||
function getState(ctx: ReturnType<typeof createTestContext>['ctx']): Entity<TicTacToeState> {
|
function getState(ctx: ReturnType<typeof createTestContext>['ctx']): MutableSignal<TicTacToeState> {
|
||||||
return ctx.state;
|
return ctx.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import { createEntityCollection, Entity, entity } from '@/utils/entity';
|
import { createEntityCollection, MutableSignal, mutableSignal } from '@/utils/mutable-signal';
|
||||||
|
|
||||||
type TestEntity = {
|
type TestEntity = {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -82,16 +82,6 @@ describe('createEntityCollection', () => {
|
||||||
expect(collection.get('nonexistent')).toBeUndefined();
|
expect(collection.get('nonexistent')).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have correct accessor id', () => {
|
|
||||||
const collection = createEntityCollection<TestEntity>();
|
|
||||||
const testEntity: TestEntity = { id: 'e1', name: 'Entity 1', value: 10 };
|
|
||||||
|
|
||||||
collection.add(testEntity);
|
|
||||||
|
|
||||||
const accessor = collection.get('e1');
|
|
||||||
expect(accessor.id).toBe('e1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle removing non-existent entity', () => {
|
it('should handle removing non-existent entity', () => {
|
||||||
const collection = createEntityCollection<TestEntity>();
|
const collection = createEntityCollection<TestEntity>();
|
||||||
const testEntity: TestEntity = { id: 'e1', name: 'Entity 1', value: 10 };
|
const testEntity: TestEntity = { id: 'e1', name: 'Entity 1', value: 10 };
|
||||||
|
|
@ -116,20 +106,19 @@ describe('createEntityCollection', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Entity', () => {
|
describe('MutableSignal', () => {
|
||||||
it('should create entity with id and value', () => {
|
it('should create signal with initial value', () => {
|
||||||
const e = entity('test', { count: 1 });
|
const s = mutableSignal({ count: 1 });
|
||||||
expect(e.id).toBe('test');
|
expect(s.value.count).toBe(1);
|
||||||
expect(e.value.count).toBe(1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should produce immutable updates', () => {
|
it('should produce immutable updates', () => {
|
||||||
const e = entity('test', { count: 1, items: [1, 2, 3] });
|
const s = mutableSignal({ count: 1, items: [1, 2, 3] });
|
||||||
e.produce(draft => {
|
s.produce(draft => {
|
||||||
draft.count = 2;
|
draft.count = 2;
|
||||||
draft.items.push(4);
|
draft.items.push(4);
|
||||||
});
|
});
|
||||||
expect(e.value.count).toBe(2);
|
expect(s.value.count).toBe(2);
|
||||||
expect(e.value.items).toEqual([1, 2, 3, 4]);
|
expect(s.value.items).toEqual([1, 2, 3, 4]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
Loading…
Reference in New Issue