feat(bgm): allow $variants to take multiple csv sources

Expand $variants to accept an array of csv paths, concatenating their
rows. Detect a path by a .csv suffix on the first line instead of a
newline, so inline csv and paths are self-documenting and the rule
applies uniformly to single values and array elements.
This commit is contained in:
2026-08-10 14:06:36 +08:00
parent 3aa48058f7
commit 9b5223686e
3 changed files with 73 additions and 16 deletions
+18 -3
View File
@@ -48,7 +48,7 @@ describe('parseCsvData', () => {
});
describe('expandVariants', () => {
it('parses inline CSV when the value contains a newline', () => {
it('parses inline CSV when the first line does not end in .csv', () => {
const rows = expandVariants('a,b\nstring,number\nx,1', 'pkg/def.yaml', new Map(), 'src');
expect(rows).toEqual([{ a: 'x', b: 1 }]);
});
@@ -61,15 +61,30 @@ describe('expandVariants', () => {
expect(rows).toEqual([{ seat: 0 }, { seat: 1 }]);
});
it('concatenates rows from an array of csv paths', () => {
const defs = new Map<string, DefFile[]>([
['pkg/parts/a.csv', [defFile('pkg/parts/a.csv', 'id\nstring\nred')]],
['pkg/parts/b.csv', [defFile('pkg/parts/b.csv', 'id\nstring\nblack')]],
]);
const rows = expandVariants(['./a.csv', './b.csv'], 'pkg/parts/board.yaml', defs, 'src');
expect(rows).toEqual([{ id: 'red' }, { id: 'black' }]);
});
it('throws when the referenced csv is missing', () => {
expect(() => expandVariants('./nope.csv', 'pkg/def.yaml', new Map(), 'src')).toThrow(
/CSV not found/,
);
});
it('throws when $variants is not a string', () => {
it('throws when $variants is not a string or string array', () => {
expect(() => expandVariants(42, 'pkg/def.yaml', new Map(), 'src')).toThrow(
/must be a path or inline CSV/,
/must be a path or inline CSV string, or an array of them/,
);
});
it('throws on an empty $variants array', () => {
expect(() => expandVariants([], 'pkg/def.yaml', new Map(), 'src')).toThrow(
/must not be empty/,
);
});
});