diff --git a/bids/tsvParser.js b/bids/tsvParser.js index e7938c4c..e7bc228b 100644 --- a/bids/tsvParser.js +++ b/bids/tsvParser.js @@ -15,7 +15,7 @@ const isContentfulRow = (row) => row && !/^\s*$/.test(row) * @param {string} contents The contents of a TSV file. * @returns {Map} The parsed contents of the TSV file. */ -function parseTSV(contents) { +export function parseTSV(contents) { const columns = new Map() const rows = stripBOM(normalizeEOL(contents)) .split('\n') @@ -36,5 +36,27 @@ function parseTSV(contents) { } return columns } +/** + * Convert parsed TSV file data from the old BIDS format to the new BIDS format. + * + * @param {{headers: string[], rows: string[][]}} oldParsedTsv Parsed TSV data using the old format + * @returns {Map} The parsed contents of the TSV file, using the new format. + */ +export function convertParsedTSVData(oldParsedTsv) { + const columns = new Map() + + oldParsedTsv.headers.forEach((x) => { + columns.set(x, []) + }) + for (let i = 1; i < oldParsedTsv.rows.length; i++) { + for (let j = 0; j < oldParsedTsv.headers.length; j++) { + columns.get(oldParsedTsv.headers[j])?.push(oldParsedTsv.rows[i][j]) + } + } + for (const [key, value] of columns) { + columns.set(key, value) + } + return columns +} export default parseTSV diff --git a/bids/types.js b/bids/types.js index 3a0edc82..f0cdf965 100644 --- a/bids/types.js +++ b/bids/types.js @@ -1,6 +1,6 @@ import { sidecarValueHasHed } from './utils' import { generateIssue, Issue } from '../common/issues/issues' -import parseTSV from './tsvParser' +import { parseTSV, convertParsedTSVData } from './tsvParser' import { parseHedString } from '../parser/main' /** @@ -110,17 +110,22 @@ export class BidsTsvFile extends BidsFile { * @todo This interface is provisional and subject to modification in version 4.0.0. * * @param {string} name The name of the TSV file. - * @param {Map|string} tsvData This file's TSV data. + * @param {{headers: string[], rows: string[][]}|Map|string} tsvData This file's TSV data. * @param {object} file The file object representing this file. * @param {string[]} potentialSidecars The list of potential JSON sidecars. * @param {object} mergedDictionary The merged sidecar data. */ constructor(name, tsvData, file, potentialSidecars = [], mergedDictionary = {}) { super(name, file) + let parsedTsvData if (typeof tsvData === 'string') { - tsvData = parseTSV(tsvData) + parsedTsvData = parseTSV(tsvData) + } else if (tsvData === Object(tsvData)) { + parsedTsvData = convertParsedTSVData(tsvData) + } else { + parsedTsvData = tsvData } - this.parsedTsv = tsvData + this.parsedTsv = parsedTsvData this.potentialSidecars = potentialSidecars this.mergedSidecar = new BidsSidecar(name, mergedDictionary, null) diff --git a/bids/validate.js b/bids/validate.js index a34f5db9..427c0970 100644 --- a/bids/validate.js +++ b/bids/validate.js @@ -362,7 +362,7 @@ class BidsHedValidator { */ _generateTsvSidecarRows(sidecarHedColumns) { const sidecarHedRows = [] - for (const [header, data] of sidecarHedColumns.parsedTsv.entries()) { + for (const [header, data] of sidecarHedColumns.entries()) { data.forEach((value, index) => { if (sidecarHedRows[index] === undefined) { sidecarHedRows[index] = new Map()