import { parseCSV } from '@datamoc/mw_games/core';
import type { AffixDef, AffixTable } from '@datamoc/mw_games/actors';
const csv = `id,trigger,weight,curse,description
blazing,strike,3,,Ignites the victim
wayward,strike,1,true,"Cursed: -3 accuracy"`;
const table: AffixTable = {
entries: parseCSV<AffixDef>(csv, { columns: { weight: 'number', curse: 'boolean' } }),
};
console.log(table.entries[1]); // { id: 'wayward', trigger: 'strike', weight: 1, curse: true, description: 'Cursed: -3 accuracy' }
A header-row CSV into an array of typed row objects - so a content designer edits a spreadsheet instead of a
.tsobject literal for a table shaped likeactors.AffixTable,actors.LootTable, or any other array-of-records a game defines. The same precedenti18n'sparseFTLalready set: this takes a raw string and has no opinion on how that string reached the game (a small table can sit in a.tstemplate literal; a larger one loads through a bundler's raw-text import - Vite resolves a?raw-suffixed path to its file's contents as a plain string - or through a game's own asset pipeline) -mwgsupplies the parsing, not the loading.Every cell is a string until a column says otherwise:
columnsnames which fields are'number'/'boolean'/'list'(semicolon-separated by default, for a field shaped likeAffixDef.kinds) /'map'(semicolon-separatedkey=valuepairs, for a per-row property bag such as{ str: '2', dex: '-1' }a game reads its own way) - and an undeclared column stays a plain string. An empty cell omits that field from the row entirely, the same as never setting an optional property - so a blankcursecolumn reads exactly like thecurse?: booleanit fills never being set.Follows RFC 4180 far enough for real game-data text: a quoted field may contain the delimiter, a newline, or an escaped
""for a literal quote, which a naivesplit(',')cannot survive the moment a description contains a comma.What this cannot hold: a
core.ReactionTablerule'swhen/actionare executable code, not data, so no cell format expresses them - the same boundaryAffixDef.idalready draws (a string the game interprets,mwgnever does). A CSV row can drive which reactions a game builds at startup (an id, a comparison string like'hp<=0.25', a threshold number a'number'column already coerces) with the game's own code turning each row into a realReactionRule; it cannot hold the rule's logic itself.