Replace the path->parts setup map with an ordered list of placements, each moving its parts to a path. Entries apply in order, so a part listed in a later placement ends up on that placement's path.
89 lines
4.0 KiB
TypeScript
89 lines
4.0 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import * as path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { loadDefs, collectPackages } from './collect.js';
|
|
|
|
const fixtureRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '__fixtures__', 'harbor');
|
|
const multiRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '__fixtures__', 'vite-build', 'games');
|
|
|
|
describe('collectPackages', () => {
|
|
it('collects the harbor package from markdown code blocks', () => {
|
|
const defMap = loadDefs('', fixtureRoot);
|
|
const packages = collectPackages(defMap, fixtureRoot);
|
|
|
|
expect(packages).toHaveLength(1);
|
|
const harbor = packages[0]!;
|
|
expect(harbor.meta).toMatchObject({ id: 'harbor', title: 'Harbor', designer: 'Jane Doe' });
|
|
|
|
// Two tokens from two yaml blocks sharing a `file=` name.
|
|
expect([...harbor.parts.keys()].sort()).toEqual(['token#grain', 'token#wood']);
|
|
const wood = harbor.parts.get('token#wood')!;
|
|
expect(wood).toMatchObject({
|
|
type: 'token',
|
|
id: 'wood',
|
|
size: [20, 20, 3],
|
|
fillet: 2,
|
|
});
|
|
expect(wood.face).toBe('./assets/tokens.png');
|
|
expect(wood.faceCrop).toEqual([1, 0, 5, 2]);
|
|
// Relative assets resolve against the source file's directory. The fixture
|
|
// markdown sits at the games root, so the virtual file is `parts/tokens.yaml`.
|
|
expect(wood.baseUrl).toBe('parts/');
|
|
|
|
// Two surfaces: the table board and its child player board.
|
|
expect([...harbor.surfaces.keys()].sort()).toEqual(['board#harbor', 'board#player']);
|
|
const board = harbor.surfaces.get('board#harbor')!;
|
|
expect(board.size).toEqual([300, 200]);
|
|
expect(board.mount).toEqual({ kind: 'table', x: 0, y: 0, rotation: 0 });
|
|
expect(board.children).toEqual(['board#player']);
|
|
expect(board.layout).toHaveLength(2);
|
|
const dock = board.layout[0]!;
|
|
expect(dock.route).toBe('/dock/:seat');
|
|
expect(dock.candidates).toEqual([
|
|
{ seat: '0', x: 40, y: 0, rotation: 0 },
|
|
{ seat: '1', x: 40, y: 20, rotation: 0 },
|
|
]);
|
|
const deck = board.layout[1]!;
|
|
expect(deck.route).toBe('/deck');
|
|
expect(deck).toMatchObject({ x: -100, y: 0, rotation: 0 });
|
|
|
|
const player = harbor.surfaces.get('board#player')!;
|
|
expect(player.mount).toEqual({ kind: 'child', x: 100, y: 50, rotation: 0 });
|
|
expect(player.layout).toHaveLength(1);
|
|
|
|
// One setup, declaring the enabled surfaces.
|
|
expect([...harbor.setups.keys()]).toEqual(['game#main']);
|
|
const setup = harbor.setups.get('game#main')!;
|
|
expect(setup.surfaces).toEqual(['board#harbor', 'board#player']);
|
|
expect(setup.setup).toEqual([
|
|
{ path: '/dock/0', parts: 'harbor:token#wood' },
|
|
{ path: '/deck', parts: 'harbor:token#grain' },
|
|
]);
|
|
});
|
|
|
|
it('scopes include patterns to the package declaration directory', () => {
|
|
// Two packages share a games root. Each uses the default `./**/*.yaml`
|
|
// include, which must resolve relative to its own folder so neither
|
|
// absorbs the other's defs (both define a `game#main` setup).
|
|
const defMap = loadDefs('', multiRoot);
|
|
const packages = collectPackages(defMap, multiRoot);
|
|
|
|
expect(packages).toHaveLength(2);
|
|
const azul = packages.find((p) => p.meta.id === 'azul')!;
|
|
const harbor = packages.find((p) => p.meta.id === 'harbor')!;
|
|
|
|
expect([...azul.parts.keys()]).toEqual(['tile#blue']);
|
|
expect([...azul.setups.keys()]).toEqual(['game#main']);
|
|
expect([...harbor.parts.keys()]).toEqual(['token#wood']);
|
|
expect([...harbor.setups.keys()]).toEqual(['game#main']);
|
|
});
|
|
|
|
it('throws on a duplicate type#id', () => {
|
|
const defMap = loadDefs('', fixtureRoot);
|
|
// Inject a duplicate part into the map under a new file name.
|
|
const tokensKey = [...defMap.defs.keys()].find((k) => k.endsWith('parts/tokens.yaml'))!;
|
|
const tokens = defMap.defs.get(tokensKey)!;
|
|
defMap.defs.set(tokensKey.replace('tokens.yaml', 'dup.yaml'), [tokens[0]!]);
|
|
expect(() => collectPackages(defMap, fixtureRoot)).toThrow(/Duplicate part/);
|
|
});
|
|
}); |