From 0503ac84a73cc10d17f1fac1e8ce33a9212a52fa Mon Sep 17 00:00:00 2001 From: hypercross Date: Sun, 9 Aug 2026 21:19:37 +0800 Subject: [PATCH] feat(bgm): resolve relative part assets against source dir --- packages/bgm/src/collect.test.ts | 3 +++ packages/bgm/src/collect.ts | 9 ++++++++- packages/bgm/src/types.ts | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/bgm/src/collect.test.ts b/packages/bgm/src/collect.test.ts index bfb2e5c..fc51a53 100644 --- a/packages/bgm/src/collect.test.ts +++ b/packages/bgm/src/collect.test.ts @@ -25,6 +25,9 @@ describe('collectPackages', () => { }); 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']); diff --git a/packages/bgm/src/collect.ts b/packages/bgm/src/collect.ts index ef1b2ed..2335fb0 100644 --- a/packages/bgm/src/collect.ts +++ b/packages/bgm/src/collect.ts @@ -13,6 +13,7 @@ * * See docs/bgm-format.md for the format's concrete behavior. */ +import * as path from 'node:path'; import picomatch from 'picomatch'; import { collectVirtualFiles } from './markdown.js'; import { parseDefText, readDefFiles } from './parse.js'; @@ -218,7 +219,13 @@ function asPackage(def: ParsedDef, source: string): PackageDef { function asPart(obj: Record, source: string): Part { try { - return validatePart(obj) as unknown as Part; + const part = validatePart(obj) as unknown as Part; + // Resolve relative asset paths against the directory of the source file + // (path-style name relative to the games root, e.g. `harbor/parts/`). + // Real files may carry a leading slash from an empty root; strip it. + const dir = path.posix.dirname(source).replace(/^\/+/, ''); + part.baseUrl = dir ? `${dir}/` : ''; + return part; } catch (err) { throw wrapZod(err, source); } diff --git a/packages/bgm/src/types.ts b/packages/bgm/src/types.ts index 419f3a1..4898a85 100644 --- a/packages/bgm/src/types.ts +++ b/packages/bgm/src/types.ts @@ -69,6 +69,11 @@ export interface Part { size?: Size; /** Fillet radius in mm; defaults to `0`. */ fillet?: number; + /** + * Directory of the part's source file (json/yaml/markdown), for resolving + * relative asset paths. Set by the loader; not authored. + */ + baseUrl?: string; /** Extra fields from the source definition, kept for forwards compatibility. */ [key: string]: unknown; }