Skip to content

Commit c145f3e

Browse files
authored
Merge pull request #265 from bids-standard/enh/case_collision
Add per context check to see if any files in its directory have the same name with different case
2 parents 68fb2e9 + 7d32430 commit c145f3e

File tree

5 files changed

+102
-0
lines changed

5 files changed

+102
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!--
2+
A new scriv changelog fragment.
3+
4+
Uncomment the section that is right (remove the HTML comment wrapper).
5+
For top level release notes, leave all the headers commented out.
6+
-->
7+
8+
### Added
9+
10+
- Throw error on file name case collision.
11+
12+
<!--
13+
### Changed
14+
15+
- A bullet item for the Changed category.
16+
17+
-->
18+
<!--
19+
### Fixed
20+
21+
- A bullet item for the Fixed category.
22+
23+
-->
24+
<!--
25+
### Deprecated
26+
27+
- A bullet item for the Deprecated category.
28+
29+
-->
30+
<!--
31+
### Removed
32+
33+
- A bullet item for the Removed category.
34+
35+
-->
36+
<!--
37+
### Security
38+
39+
- A bullet item for the Security category.
40+
41+
-->
42+
<!--
43+
### Infrastructure
44+
45+
- A bullet item for the Infrastructure category.
46+
47+
-->

src/issues/list.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,11 @@ export const bidsIssues: IssueDefinitionRecord = {
199199
severity: 'warning',
200200
reason: 'The validation on this HED string returned a warning.',
201201
},
202+
CASE_COLLISION: {
203+
severity: 'error',
204+
reason: 'Files with the same name but different casing have been found.',
205+
},
206+
202207
}
203208

204209
export const nonSchemaIssues = { ...bidsIssues }

src/validators/bids.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { walkFileTree } from '../schema/walk.ts'
99
import { loadSchema } from '../setup/loadSchema.ts'
1010
import type { Config, ValidatorOptions } from '../setup/options.ts'
1111
import { Summary } from '../summary/summary.ts'
12+
import { filenameCase } from './filenameCase.ts'
1213
import { filenameIdentify } from './filenameIdentify.ts'
1314
import { filenameValidate } from './filenameValidate.ts'
1415
import type { DatasetIssues } from '../issues/datasetIssues.ts'
@@ -27,6 +28,7 @@ const perContextChecks: ContextCheckFunction[] = [
2728
emptyFile,
2829
filenameIdentify,
2930
filenameValidate,
31+
filenameCase,
3032
applyRules,
3133
hedValidate,
3234
]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { assertEquals } from '@std/assert'
2+
import { filenameCase } from './filenameCase.ts'
3+
import { FileIgnoreRules } from '../files/ignore.ts'
4+
import { loadSchema } from '../setup/loadSchema.ts'
5+
import { pathsToTree } from '../files/filetree.ts'
6+
import { BIDSFileDeno } from '../files/deno.ts'
7+
import { BIDSContext, BIDSContextDataset } from '../schema/context.ts'
8+
import { walkFileTree } from '../schema/walk.ts'
9+
import { GenericSchema } from '../types/schema.ts'
10+
11+
const schema = await loadSchema()
12+
const ignore = new FileIgnoreRules([])
13+
14+
const filesToTest = [
15+
'/file.txt',
16+
'/File.txt',
17+
'/FILE.txt',
18+
'/file.TXT',
19+
'/dir/file.txt',
20+
'/different_file.txt'
21+
]
22+
23+
const fileTree = pathsToTree(filesToTest)
24+
25+
Deno.test('test filenameCase', async (t) => {
26+
const dsContext = new BIDSContextDataset({ tree: fileTree, schema: schema })
27+
for await (const context of walkFileTree(dsContext)) {
28+
await filenameCase(schema as unknown as GenericSchema, context)
29+
}
30+
const issues = dsContext.issues.get({code: 'CASE_COLLISION'})
31+
assertEquals(issues.length, 4)
32+
})

src/validators/filenameCase.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { ContextCheckFunction } from '../types/check.ts'
2+
3+
export const filenameCase: ContextCheckFunction = (schema, context) => {
4+
const lowercase = context.file.name.toLowerCase()
5+
const caseCollision = context.file.parent?.files.filter(otherFile => {
6+
return (otherFile != context.file && otherFile.name.toLowerCase() === lowercase)
7+
})
8+
if (caseCollision?.length) {
9+
context.dataset.issues.add({
10+
code: 'CASE_COLLISION',
11+
location: context.path,
12+
affects: caseCollision.map(file => file.path)
13+
})
14+
}
15+
return Promise.resolve()
16+
}

0 commit comments

Comments
 (0)