Skip to content

Commit 563f96e

Browse files
committed
Add per context check to see if any files in its directory have the same name with different case
1 parent a115575 commit 563f96e

File tree

5 files changed

+101
-0
lines changed

5 files changed

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

0 commit comments

Comments
 (0)