feat(bgm): resolve relative part assets against source dir

This commit is contained in:
2026-08-09 21:19:37 +08:00
parent 43b69133cc
commit 0503ac84a7
3 changed files with 16 additions and 1 deletions
+3
View File
@@ -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']);
+8 -1
View File
@@ -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<string, unknown>, 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);
}
+5
View File
@@ -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;
}