Skip to content

Commit 920d195

Browse files
authored
Merge pull request #828 from bids-standard/bep018
Bep018 bids-standard/bids-examples#178
2 parents 502cce1 + b88d1ac commit 920d195

File tree

9 files changed

+154
-0
lines changed

9 files changed

+154
-0
lines changed

bids-validator/bids_validator/rules/fixed_top_level_names.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"/README",
44
"/CHANGES",
55
"/dataset_description.json",
6+
"/genetic_info.json",
67
"/participants.tsv",
78
"/participants.json",
89
"/phasediff.json",

bids-validator/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"ignore": "^4.0.2",
3232
"is-utf8": "^0.2.1",
3333
"jshint": "^2.9.6",
34+
"lerna": "^3.15.0",
3435
"minimatch": "3.0.4",
3536
"nifti-js": "^1.0.1",
3637
"p-limit": "^2.1.0",

bids-validator/tests/json.spec.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,4 +271,39 @@ describe('JSON', function() {
271271
assert.deepEqual(issues, [])
272272
})
273273
})
274+
275+
var genetic_info_file = {
276+
name: 'genetic_info.json',
277+
relativePath: '/genetic_info.json',
278+
}
279+
280+
it('sample genetic_info.json should parse', function() {
281+
var jsonObj = {
282+
GeneticLevel: 'Genetic',
283+
AnalyticalApproach: ['SNP Genotypes'],
284+
SampleOrigin: 'brain',
285+
TissueOrigin: 'gray matter',
286+
CellType: 'neuron',
287+
BrainLocation: '[-30 -15 10]',
288+
}
289+
jsonDict[genetic_info_file.relativePath] = jsonObj
290+
validate.JSON(genetic_info_file, jsonDict, function(issues) {
291+
assert.deepEqual(issues, [])
292+
})
293+
})
294+
295+
it('genetic_info.json should use limited vocabulary for sample origin', function() {
296+
var jsonObj = {
297+
GeneticLevel: 'Genetic',
298+
AnalyticalApproach: ['SNP Genotypes'],
299+
SampleOrigin: 'not_from_around_here',
300+
TissueOrigin: 'gray matter',
301+
CellType: 'neuron',
302+
BrainLocation: '[-30 -15 10]',
303+
}
304+
jsonDict[genetic_info_file.relativePath] = jsonObj
305+
validate.JSON(genetic_info_file, jsonDict, function(issues) {
306+
assert(issues.length === 1 && issues[0].code == 55)
307+
})
308+
})
274309
})

bids-validator/utils/issues/list.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,4 +703,10 @@ export default {
703703
reason:
704704
'Status column in channels.tsv files must contain only one of two values: good or bad. Per the BIDS spec: (https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/04-intracranial-electroencephalography.html#channels-description-_channelstsv).'
705705
},
706+
128: {
707+
key: 'NO_GENETIC_DATABASE',
708+
severity: 'error',
709+
reason:
710+
'A genetic_info.json file is present but no Database field present in Genetics object in dataset_description.json.',
711+
},
706712
}

bids-validator/validators/bids/__tests__/checkDatasetDescription.spec.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,32 @@ describe('checkDatasetDescription', () => {
5858
)
5959
})
6060
})
61+
describe('checkGeneticDatabaseField', () => {
62+
it('returns code 128 when there is no Genetics.Dataset with a genetic_info.json present', () => {
63+
const invalidJsonContentsDict = {
64+
'/dataset_description.json': { },
65+
'/genetic_info.json': { }
66+
}
67+
let issues = checkDatasetDescription(invalidJsonContentsDict)
68+
assert(
69+
issues.findIndex(issue => issue.code === 128) > -1,
70+
'issues include a code 128',
71+
)
72+
})
73+
it('does not return code 128 when GeneticDataset field and genetic_info.json present', () => {
74+
const validJsonContentsDict = {
75+
'/dataset_description.json': {
76+
Authors: ['Benny', 'the Jets'],
77+
Genetics: {Dataset: 'GeneticGeneticDataset'},
78+
},
79+
'/genetic_info.json': { }
80+
}
81+
let issues = checkDatasetDescription(validJsonContentsDict)
82+
assert(
83+
issues.findIndex(issue => issue.code === 128) === -1,
84+
'issues does not include a code 128'
85+
)
86+
})
87+
88+
})
6189
})

bids-validator/validators/bids/checkDatasetDescription.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ const checkDatasetDescription = jsonContentsDict => {
66
const hasDatasetDescription = jsonFilePaths.some(path => {
77
return path == '/dataset_description.json'
88
})
9+
const hasGeneticInfo = jsonFilePaths.some(path => {
10+
return path === '/genetic_info.json'
11+
})
12+
913
if (!hasDatasetDescription) {
1014
issues.push(new Issue({ code: 57 }))
1115
} else {
@@ -14,6 +18,11 @@ const checkDatasetDescription = jsonContentsDict => {
1418
// check to ensure that the dataset description Authors are
1519
// properly formatted
1620
issues = issues.concat(checkAuthorField(datasetDescription.Authors))
21+
22+
// if genetic info json present ensure mandatory GeneticDataset present
23+
if (hasGeneticInfo && !(('Genetics' in datasetDescription) && ('Dataset' in datasetDescription.Genetics))) {
24+
issues.push(new Issue({ code: 128 }));
25+
}
1726
}
1827
return issues
1928
}

bids-validator/validators/json/json.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ const selectSchema = file => {
107107
file.name.endsWith('coordsystem.json')
108108
) {
109109
schema = require('./schemas/coordsystem_eeg.json')
110+
} else if (
111+
file.name.endsWith('genetic_info.json')
112+
) {
113+
schema = require('./schemas/genetic_info.json')
110114
}
111115
}
112116
return schema

bids-validator/validators/json/schemas/dataset_description.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,26 @@
4343
},
4444
"DatasetDOI": {
4545
"type": "string"
46+
},
47+
"Genetics": {
48+
"type": "object",
49+
"properties": {
50+
"Database": {
51+
"items": {
52+
"type": "string"
53+
},
54+
"type": ["array", "string"]
55+
},
56+
"Dataset": {
57+
"type": "string"
58+
},
59+
"Descriptors": {
60+
"items": {
61+
"type": "string"
62+
},
63+
"type": ["array", "string"]
64+
}
65+
}
4666
}
4767
},
4868
"required": ["Name", "BIDSVersion"],
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"GeneticLevel": {
5+
"type": "string",
6+
"enum": [
7+
"Genetic",
8+
"Genomic",
9+
"Epigenomic",
10+
"Transcriptomic",
11+
"Metabolomic",
12+
"Proteomic"
13+
]
14+
},
15+
"AnalyticalApproach": {
16+
"items": {
17+
"type": "string"
18+
},
19+
"type": "array"
20+
},
21+
"SampleOrigin": {
22+
"type": "string",
23+
"enum": [
24+
"blood",
25+
"saliva",
26+
"brain",
27+
"csf",
28+
"breast milk",
29+
"bile",
30+
"amniotic fluid",
31+
"other biospecimen"
32+
]
33+
},
34+
"TissueOrigin": {
35+
"type": "string",
36+
"enum": [
37+
"gray matter",
38+
"white matter",
39+
"csf",
40+
"meninges",
41+
"macrovascular",
42+
"microvascular"
43+
]
44+
},
45+
"BrainLocation": { "type": "string" },
46+
"CellType": { "type": "string" }
47+
},
48+
"required": ["GeneticLevel", "SampleOrigin"],
49+
"additionalProperties": false
50+
}

0 commit comments

Comments
 (0)