Source: dialects/ztree/export.js

/*
 * A z-Tree treatment's tables as z-Tree writes them (its .xls file: tab-separated text): for each
 * period and table, a line of the table's variables, then a line for each record, each line
 * starting with the session, the treatment's number, the table and the period.
 */

/** The run's tables as text. */
function exportTables(run, session) {
    const lines = [];
    // Infinities and NaN (by z-Tree's rules, 1/0 and the like) as z-Tree 5 writes them.
    const number = (v) => (Number.isNaN(v) ? '-nan(ind)' : v === Infinity ? 'inf' : v === -Infinity ? '-inf' : String(v));
    const cell = (v) => (v == null ? '' : typeof v === 'number' ? number(v) : typeof v === 'object' ? (v.zArray ? v.values.map(number).join(' ') : '') : String(v).replace(/[\t\n\r]/g, ' '));
    run.periods.forEach((state, p) => {
        if (state == null) return;
        const tables = [['globals', [state.globals]], ['subjects', state.subjects], ['summary', [state.summary]], ['contracts', state.contracts]];
        for (const [name, other] of Object.entries(state.other)) tables.push([name, other]);
        if (p === run.periods.length - 1) tables.push(['session', run.sessionRecords]);
        for (const [name, records] of tables) {
            const vars = [];
            for (const rec of records) {
                for (const k of Object.keys(rec)) {
                    if (k !== '_id' && k !== 'Period' && !vars.includes(k)) vars.push(k);
                }
            }
            lines.push([session.id, 1, name, 'Period', ...vars].join('\t'));
            for (const rec of records) lines.push([session.id, 1, name, p + 1, ...vars.map((k) => cell(rec[k]))].join('\t'));
        }
    });
    return lines.join('\r\n') + '\r\n';
}

module.exports = exportTables;