Split out of #60, whose short-term part (one module per convention under src/conventions/) is done.
Longer term: add a parsed Instrument model: groups, questions, choice lists, and an expression AST. Each pipeline then becomes parse → Instrument → emit, which means N parsers plus N emitters instead of one module per direction.
xlsform2ddi/variables.ts already does half of this. Its Variable[] is the DDI-side model.
xlsform2lstsv and lstsv2xlsform still map rows to rows. They re-derive structure (groups, grids, other patterns) each time.
This is a design change, not a cleanup. Worth doing once #61–#63 have settled the module boundaries and the converter's state.
Split out of #60, whose short-term part (one module per convention under
src/conventions/) is done.Longer term: add a parsed
Instrumentmodel: groups, questions, choice lists, and an expression AST. Each pipeline then becomes parse →Instrument→ emit, which means N parsers plus N emitters instead of one module per direction.xlsform2ddi/variables.tsalready does half of this. ItsVariable[]is the DDI-side model.xlsform2lstsvandlstsv2xlsformstill map rows to rows. They re-derive structure (groups, grids, other patterns) each time.This is a design change, not a cleanup. Worth doing once #61–#63 have settled the module boundaries and the converter's state.