1
1
import { BidsHedSidecarValidator } from './bidsHedSidecarValidator'
2
2
import { BidsHedIssue } from '../types/issues'
3
- import { BidsTsvRow } from '../types/tsv'
3
+ import { BidsTsvEvent , BidsTsvRow } from '../types/tsv'
4
4
import { parseHedString } from '../../parser/main'
5
5
import ColumnSplicer from '../../parser/columnSplicer'
6
6
import ParsedHedString from '../../parser/parsedHedString'
7
7
import { generateIssue } from '../../common/issues/issues'
8
8
import { validateHedDatasetWithContext } from '../../validator/dataset'
9
+ import { groupBy } from '../../utils/map'
9
10
10
11
/**
11
12
* Validator for HED data in BIDS TSV files.
@@ -67,18 +68,15 @@ export class BidsHedTsvValidator {
67
68
/**
68
69
* Combine the BIDS sidecar HED data into a BIDS TSV file's HED data.
69
70
*
70
- * @returns {BidsTsvRow [] } The combined HED string collection for this BIDS TSV file.
71
+ * @returns {ParsedHedString [] } The combined HED string collection for this BIDS TSV file.
71
72
*/
72
73
parseHed ( ) {
73
74
const tsvHedRows = this . _generateHedRows ( )
74
- const hedStrings = [ ]
75
+ const hedStrings = this . _parseHedRows ( tsvHedRows )
75
76
76
- tsvHedRows . forEach ( ( row , index ) => {
77
- const hedString = this . _parseHedRow ( row , index + 2 )
78
- if ( hedString !== null ) {
79
- hedStrings . push ( hedString )
80
- }
81
- } )
77
+ if ( this . tsvFile . isTimelineFile ) {
78
+ return this . _mergeEventRows ( hedStrings )
79
+ }
82
80
83
81
return hedStrings
84
82
}
@@ -91,7 +89,7 @@ export class BidsHedTsvValidator {
91
89
*/
92
90
_generateHedRows ( ) {
93
91
const tsvHedColumns = Array . from ( this . tsvFile . parsedTsv . entries ( ) ) . filter (
94
- ( [ header ] ) => this . tsvFile . sidecarHedData . has ( header ) || header === 'HED' ,
92
+ ( [ header ] ) => this . tsvFile . sidecarHedData . has ( header ) || header === 'HED' || header === 'onset' ,
95
93
)
96
94
97
95
const tsvHedRows = [ ]
@@ -104,6 +102,44 @@ export class BidsHedTsvValidator {
104
102
return tsvHedRows
105
103
}
106
104
105
+ /**
106
+ * Parse the HED rows in the TSV file.
107
+ *
108
+ * @param {Map<string, string>[] } tsvHedRows A list of single-row column-to-value mappings.
109
+ * @return {BidsTsvRow[] } A list of row-based parsed HED strings.
110
+ * @private
111
+ */
112
+ _parseHedRows ( tsvHedRows ) {
113
+ const hedStrings = [ ]
114
+
115
+ tsvHedRows . forEach ( ( row , index ) => {
116
+ const hedString = this . _parseHedRow ( row , index + 2 )
117
+ if ( hedString !== null ) {
118
+ hedStrings . push ( hedString )
119
+ }
120
+ } )
121
+ return hedStrings
122
+ }
123
+
124
+ /**
125
+ * Merge rows with the same onset time into a single event string.
126
+ *
127
+ * @param {BidsTsvRow[] } rowStrings A list of row-based parsed HED strings.
128
+ * @return {BidsTsvEvent[] } A list of event-based parsed HED strings.
129
+ * @private
130
+ */
131
+ _mergeEventRows ( rowStrings ) {
132
+ const groupedTsvRows = groupBy ( rowStrings , ( rowString ) => rowString . onset )
133
+ const sortedOnsetTimes = Array . from ( groupedTsvRows . keys ( ) ) . sort ( ( a , b ) => a - b )
134
+ const eventStrings = [ ]
135
+ for ( const onset of sortedOnsetTimes ) {
136
+ const onsetRows = groupedTsvRows . get ( onset )
137
+ const onsetEventString = new BidsTsvEvent ( this . tsvFile , onsetRows )
138
+ eventStrings . push ( onsetEventString )
139
+ }
140
+ return eventStrings
141
+ }
142
+
107
143
/**
108
144
* Parse a row in a TSV file.
109
145
*
@@ -141,7 +177,7 @@ export class BidsHedTsvValidator {
141
177
const [ parsedString , parsingIssues ] = parseHedString ( hedString , this . hedSchemas )
142
178
const flatParsingIssues = Object . values ( parsingIssues ) . flat ( )
143
179
if ( flatParsingIssues . length > 0 ) {
144
- this . issues . push ( ...BidsHedIssue . fromHedIssues ( ... flatParsingIssues , this . tsvFile . file , { tsvLine } ) )
180
+ this . issues . push ( ...BidsHedIssue . fromHedIssues ( flatParsingIssues , this . tsvFile . file , { tsvLine } ) )
145
181
return null
146
182
}
147
183
0 commit comments