Skip to content

Commit

Permalink
Merge pull request #201 from hed-standard/issue-error-static-throw
Browse files Browse the repository at this point in the history
Move all throws of IssueError to new static method
  • Loading branch information
happy5214 authored Oct 7, 2024
2 parents 670d7bf + 67155bd commit ec66cfe
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 70 deletions.
12 changes: 6 additions & 6 deletions bids/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function validateSchemasSpec(schemasSpec) {
if (schemasSpec instanceof SchemasSpec) {
return schemasSpec
} else {
throw new IssueError(generateIssue('invalidSchemaSpecification', { spec: JSON.stringify(schemasSpec) }))
IssueError.generateAndThrow('invalidSchemaSpecification', { spec: JSON.stringify(schemasSpec) })
}
}

Expand All @@ -70,12 +70,12 @@ function splitNicknameAndSchema(schemaVersion) {
let nickname = ''
let schema
if (nicknameSplit.length > 2) {
throw new IssueError(generateIssue('invalidSchemaSpecification', { spec: schemaVersion }))
IssueError.generateAndThrow('invalidSchemaSpecification', { spec: schemaVersion })
}
if (nicknameSplit.length > 1) {
;[nickname, schema] = nicknameSplit
if (!alphabeticRegExp.test(nickname)) {
throw new IssueError(generateIssue('invalidSchemaNickname', { nickname: nickname, spec: schemaVersion }))
IssueError.generateAndThrow('invalidSchemaNickname', { nickname: nickname, spec: schemaVersion })
}
} else {
schema = nicknameSplit[0]
Expand All @@ -88,18 +88,18 @@ function splitLibraryAndVersion(schemaVersion, originalVersion) {
let library = ''
let version
if (versionSplit.length > 2) {
throw new IssueError(generateIssue('invalidSchemaSpecification', { spec: originalVersion }))
IssueError.generateAndThrow('invalidSchemaSpecification', { spec: originalVersion })
}
if (versionSplit.length > 1) {
;[library, version] = versionSplit
if (!alphabeticRegExp.test(library)) {
throw new IssueError(generateIssue('invalidSchemaSpecification', { spec: originalVersion }))
IssueError.generateAndThrow('invalidSchemaSpecification', { spec: originalVersion })
}
} else {
version = versionSplit[0]
}
if (!semver.valid(version)) {
throw new IssueError(generateIssue('invalidSchemaSpecification', { spec: originalVersion }))
IssueError.generateAndThrow('invalidSchemaSpecification', { spec: originalVersion })
}
return [library, version]
}
Expand Down
23 changes: 12 additions & 11 deletions bids/types/json.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { parseHedString } from '../../parser/main'
import ParsedHedString from '../../parser/parsedHedString'
import { BidsFile } from './basic'
import BidsHedSidecarValidator from '../validator/bidsHedSidecarValidator'
import { generateIssue, IssueError } from '../../common/issues/issues'
import { IssueError } from '../../common/issues/issues'

const ILLEGAL_SIDECAR_KEYS = new Set(['hed', 'n/a'])

Expand Down Expand Up @@ -81,7 +81,7 @@ export class BidsSidecar extends BidsJsonFile {
.map(([sidecarKey, sidecarValue]) => {
const trimmedSidecarKey = sidecarKey.trim()
if (ILLEGAL_SIDECAR_KEYS.has(trimmedSidecarKey.toLowerCase())) {
throw new IssueError(generateIssue('illegalSidecarHedKey', {}))
IssueError.generateAndThrow('illegalSidecarHedKey')
}
if (sidecarValueHasHed(sidecarValue)) {
return [trimmedSidecarKey, new BidsSidecarKey(trimmedSidecarKey, sidecarValue.HED, this)]
Expand All @@ -104,7 +104,7 @@ export class BidsSidecar extends BidsJsonFile {
*/
_verifyKeyHasNoDeepHed(key, value) {
if (key.toUpperCase() === 'HED') {
throw new IssueError(generateIssue('illegalSidecarHedDeepKey', {}))
IssueError.generateAndThrow('illegalSidecarHedDeepKey')
}
if (!isPlainObject(value)) {
return
Expand Down Expand Up @@ -206,9 +206,9 @@ export class BidsSidecar extends BidsJsonFile {
this.columnSpliceMapping.set(sidecarKey, keyReferences)
}
} else {
throw new IssueError(
generateIssue('internalConsistencyError', { message: 'Unexpected type found in sidecar parsedHedData map.' }),
)
IssueError.generateAndThrow('internalConsistencyError', {
message: 'Unexpected type found in sidecar parsedHedData map.',
})
}
}
}
Expand Down Expand Up @@ -275,7 +275,7 @@ export class BidsSidecarKey {
if (typeof data === 'string') {
this.valueString = data
} else if (!isPlainObject(data)) {
throw new IssueError(generateIssue('illegalSidecarHedType', { key: key, file: sidecar.file.relativePath }))
IssueError.generateAndThrow('illegalSidecarHedType', { key: key, file: sidecar.file.relativePath })
} else {
this.categoryMap = data
}
Expand Down Expand Up @@ -307,11 +307,12 @@ export class BidsSidecarKey {
for (const [value, string] of Object.entries(this.categoryMap)) {
const trimmedValue = value.trim()
if (ILLEGAL_SIDECAR_KEYS.has(trimmedValue.toLowerCase())) {
throw new IssueError(generateIssue('illegalSidecarHedCategoricalValue', {}))
IssueError.generateAndThrow('illegalSidecarHedCategoricalValue')
} else if (typeof string !== 'string') {
throw new IssueError(
generateIssue('illegalSidecarHedType', { key: value, file: this.sidecar.deref()?.file?.relativePath }),
)
IssueError.generateAndThrow('illegalSidecarHedType', {
key: value,
file: this.sidecar.deref()?.file?.relativePath,
})
}
const [parsedString, parsingIssues] = parseHedString(string, hedSchemas)
this.parsedCategoryMap.set(value, parsedString)
Expand Down
10 changes: 5 additions & 5 deletions bids/types/tsv.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { convertParsedTSVData, parseTSV } from '../tsvParser'
import { BidsSidecar } from './json'
import ParsedHedString from '../../parser/parsedHedString'
import BidsHedTsvValidator from '../validator/bidsHedTsvValidator'
import { generateIssue, IssueError } from '../../common/issues/issues'
import { IssueError } from '../../common/issues/issues'

/**
* A BIDS TSV file.
Expand Down Expand Up @@ -58,7 +58,7 @@ export class BidsTsvFile extends BidsFile {
} else if (isPlainObject(tsvData)) {
this.parsedTsv = convertParsedTSVData(tsvData)
} else {
throw new IssueError(generateIssue('internalError', { message: 'parsedTsv has an invalid type' }))
IssueError.generateAndThrow('internalError', { message: 'parsedTsv has an invalid type' })
}

this.potentialSidecars = potentialSidecars
Expand Down Expand Up @@ -196,9 +196,9 @@ export class BidsTsvRow extends ParsedHedString {
get onset() {
const value = Number(this.rowCells.get('onset'))
if (Number.isNaN(value)) {
throw new IssueError(
generateIssue('internalError', { message: 'Attempting to access the onset of a TSV row without one.' }),
)
IssueError.generateAndThrow('internalError', {
message: 'Attempting to access the onset of a TSV row without one.',
})
}
return value
}
Expand Down
6 changes: 4 additions & 2 deletions bids/validator/bidsHedSidecarValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BidsHedIssue } from '../types/issues'
import ParsedHedString from '../../parser/parsedHedString'
// IMPORTANT: This import cannot be shortened to '../../validator', as this creates a circular dependency until v4.0.0.
import { validateHedString } from '../../validator/event/init'
import { generateIssue } from '../../common/issues/issues'
import { generateIssue, IssueError } from '../../common/issues/issues'

/**
* Validator for HED data in BIDS JSON sidecars.
Expand Down Expand Up @@ -81,7 +81,9 @@ export class BidsHedSidecarValidator {
issues.push(...this._validateString(sidecarKey, valueString, categoricalOptions))
}
} else {
throw new Error('Unexpected type found in sidecar parsedHedData map.')
IssueError.generateAndThrow('internalConsistencyError', {
message: 'Unexpected type found in sidecar parsedHedData map.',
})
}
}

Expand Down
11 changes: 11 additions & 0 deletions common/issues/issues.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ export class IssueError extends Error {

Object.setPrototypeOf(this, IssueError.prototype)
}

/**
* Generate a new {@link Issue} object and immediately throw it as an {@link IssueError}.
*
* @param {string} internalCode The internal error code.
* @param {Object<string, (string|number[])>?} parameters The error string parameters.
* @throws {IssueError} Corresponding to the generated {@link Issue}.
*/
static generateAndThrow(internalCode, parameters = {}) {
throw new IssueError(generateIssue(internalCode, parameters))
}
}

/**
Expand Down
8 changes: 4 additions & 4 deletions common/schema/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import xml2js from 'xml2js'

import * as files from '../../utils/files'
import { generateIssue, IssueError } from '../issues/issues'
import { IssueError } from '../issues/issues'

import { localSchemaList } from './config'

Expand All @@ -18,7 +18,7 @@ import { localSchemaList } from './config'
export default async function loadSchema(schemaDef = null) {
const xmlData = await loadPromise(schemaDef)
if (xmlData === null) {
throw new IssueError(generateIssue('invalidSchemaSpecification', { spec: JSON.stringify(schemaDef) }))
IssueError.generateAndThrow('invalidSchemaSpecification', { spec: JSON.stringify(schemaDef) })
}
return xmlData
}
Expand Down Expand Up @@ -82,7 +82,7 @@ async function loadBundledSchema(schemaDef) {
return parseSchemaXML(localSchemaList.get(schemaDef.localName))
} catch (error) {
const issueArgs = { spec: JSON.stringify(schemaDef), error: error.message }
throw new IssueError(generateIssue('bundledSchemaLoadFailed', issueArgs))
IssueError.generateAndThrow('bundledSchemaLoadFailed', issueArgs)
}
}

Expand All @@ -101,7 +101,7 @@ async function loadSchemaFile(xmlDataPromise, issueCode, issueArgs) {
return parseSchemaXML(data)
} catch (error) {
issueArgs.error = error.message
throw new IssueError(generateIssue(issueCode, issueArgs))
IssueError.generateAndThrow(issueCode, issueArgs)
}
}

Expand Down
32 changes: 13 additions & 19 deletions parser/converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default class TagConverter {
const firstLevel = this.tagLevels[0].toLowerCase().trimStart()
const schemaTag = this.tagMapping.getEntry(firstLevel)
if (!schemaTag || firstLevel === '' || firstLevel !== firstLevel.trim()) {
throw new IssueError(generateIssue('invalidTag', { tag: this.tagString }))
IssueError.generateAndThrow('invalidTag', { tag: this.tagString })
}
if (this.tagLevels.length === 1) {
return schemaTag
Expand Down Expand Up @@ -109,35 +109,29 @@ export default class TagConverter {
_validateChildTag(parentTag, i) {
const childTag = this._getSchemaTag(i)
if (this.schemaTag instanceof SchemaValueTag) {
throw new IssueError(
generateIssue('internalConsistencyError', {
message: 'Child tag is a value tag which should have been handled earlier.',
}),
)
IssueError.generateAndThrow('internalConsistencyError', {
message: 'Child tag is a value tag which should have been handled earlier.',
})
}
if (childTag === undefined && parentTag && !parentTag.hasAttributeName('extensionAllowed')) {
throw new IssueError(
generateIssue('invalidExtension', {
tag: this.tagLevels[i],
parentTag: parentTag.longName,
}),
)
IssueError.generateAndThrow('invalidExtension', {
tag: this.tagLevels[i],
parentTag: parentTag.longName,
})
}
if (childTag !== undefined && (childTag.parent === undefined || childTag.parent !== parentTag)) {
throw new IssueError(
generateIssue('invalidParentNode', {
tag: this.tagLevels[i],
parentTag: childTag.longName,
}),
)
IssueError.generateAndThrow('invalidParentNode', {
tag: this.tagLevels[i],
parentTag: childTag.longName,
})
}
return childTag
}

_getSchemaTag(i) {
const tagLevel = this.tagLevels[i].toLowerCase()
if (tagLevel === '' || tagLevel !== tagLevel.trim()) {
throw new IssueError(generateIssue('invalidTag', { tag: this.tagString }))
IssueError.generateAndThrow('invalidTag', { tag: this.tagString })
}
return this.tagMapping.getEntry(tagLevel)
}
Expand Down
20 changes: 8 additions & 12 deletions parser/parsedHedGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,12 +344,10 @@ export class ParsedHedGroup extends ParsedHedSubstring {
this.defTags.map((defTag) => ParsedHedGroup.findDefinitionName(defTag.canonicalTag, 'Def')),
)
} else if (this.defCount > 1) {
throw new IssueError(
generateIssue('temporalWithMultipleDefinitions', {
tagGroup: this.originalTag,
tag: this.temporalGroupName,
}),
)
IssueError.generateAndThrow('temporalWithMultipleDefinitions', {
tagGroup: this.originalTag,
tag: this.temporalGroupName,
})
} else if (this.hasDefExpandChildren) {
return this.defExpandChildren[0].defExpandName
}
Expand All @@ -371,12 +369,10 @@ export class ParsedHedGroup extends ParsedHedSubstring {
this.defTags.map((defTag) => ParsedHedGroup.getDefinitionTagValue(defTag, 'Def')),
)
} else if (this.defCount > 1) {
throw new IssueError(
generateIssue('temporalWithMultipleDefinitions', {
tagGroup: this.originalTag,
tag: this.temporalGroupName,
}),
)
IssueError.generateAndThrow('temporalWithMultipleDefinitions', {
tagGroup: this.originalTag,
tag: this.temporalGroupName,
})
} else if (this.hasDefExpandChildren) {
return this.defExpandChildren[0].defExpandValue
}
Expand Down
8 changes: 4 additions & 4 deletions utils/types.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** Utility classes. **/

import { generateIssue, IssueError } from '../common/issues/issues'
import { IssueError } from '../common/issues/issues'

/**
* Superclass for property memoization until we can get away with private fields.
Expand Down Expand Up @@ -32,9 +32,9 @@ export class Memoizer {
*/
_memoize(propertyName, valueComputer) {
if (!propertyName) {
throw new IssueError(
generateIssue('internalConsistencyError', { message: 'Invalid property name in Memoizer subclass.' }),
)
IssueError.generateAndThrow('internalConsistencyError', {
message: 'Invalid property name in Memoizer subclass.',
})
}
if (this._memoizedProperties.has(propertyName)) {
return this._memoizedProperties.get(propertyName)
Expand Down
15 changes: 8 additions & 7 deletions validator/schema/hed3.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ export class Hed3SchemaParser extends SchemaParser {
const tagEntries = new Map()
for (const [name, valueAttributes] of valueAttributeDefinitions) {
if (tagEntries.has(name)) {
throw new IssueError(generateIssue('duplicateTagsInSchema', {}))
IssueError.generateAndThrow('duplicateTagsInSchema')
}
const booleanAttributes = booleanAttributeDefinitions.get(name)
const unitClasses = tagUnitClassDefinitions.get(name)
Expand Down Expand Up @@ -422,13 +422,14 @@ export class Hed3PartneredSchemaMerger {
*/
_validate(source, destination) {
if (source.generation < 3 || destination.generation < 3) {
throw new Error('Partnered schemas must be HED-3G schemas')
IssueError.generateAndThrow('internalConsistencyError', { message: 'Partnered schemas must be HED-3G schemas' })
}

if (source.withStandard !== destination.withStandard) {
throw new IssueError(
generateIssue('differentWithStandard', { first: source.withStandard, second: destination.withStandard }),
)
IssueError.generateAndThrow('differentWithStandard', {
first: source.withStandard,
second: destination.withStandard,
})
}
}

Expand Down Expand Up @@ -482,14 +483,14 @@ export class Hed3PartneredSchemaMerger {

const shortName = tag.name
if (this.destinationTags.hasEntry(shortName.toLowerCase())) {
throw new IssueError(generateIssue('lazyPartneredSchemasShareTag', { tag: shortName }))
IssueError.generateAndThrow('lazyPartneredSchemasShareTag', { tag: shortName })
}

const rootedTagShortName = tag.getNamedAttributeValue('rooted')
if (rootedTagShortName) {
const parentTag = tag.parent
if (parentTag?.name?.toLowerCase() !== rootedTagShortName?.toLowerCase()) {
throw new Error(`Node ${shortName} is improperly rooted.`)
IssueError.generateAndThrow('internalError', { message: `Node ${shortName} is improperly rooted.` })
}
}

Expand Down

0 comments on commit ec66cfe

Please sign in to comment.