Skip to content

Commit

Permalink
Include name of FHIR entity in temporal format warning
Browse files Browse the repository at this point in the history
  • Loading branch information
mint-thompson committed Mar 18, 2024
1 parent 5b0cabc commit a60e4a1
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 75 deletions.
13 changes: 8 additions & 5 deletions src/extractor/AssignmentRuleExtractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { dateRegex, dateTimeRegex, getPath, instantRegex, timeRegex, logger } fr
import { fshifyString } from '../exportable/common';

export class AssignmentRuleExtractor {
static process(input: ProcessableElementDefinition): ExportableAssignmentRule[] {
static process(
input: ProcessableElementDefinition,
entityName: string
): ExportableAssignmentRule[] {
// check for fixedSomething or patternSomething
// pattern and fixed are mutually exclusive
// these are on one-type elements, so if our SD has value[x],
Expand All @@ -31,25 +34,25 @@ export class AssignmentRuleExtractor {
if (matchingKey.endsWith('DateTime')) {
if (!dateTimeRegex.test(matchingValue)) {
logger.warn(
`Value ${matchingValue} on element ${assignmentRule.path} is not a valid FHIR dateTime`
`Value ${matchingValue} on ${entityName} element ${assignmentRule.path} is not a valid FHIR dateTime`
);
}
} else if (matchingKey.endsWith('Date')) {
if (!dateRegex.test(matchingValue)) {
logger.warn(
`Value ${matchingValue} on element ${assignmentRule.path} is not a valid FHIR date`
`Value ${matchingValue} on ${entityName} element ${assignmentRule.path} is not a valid FHIR date`
);
}
} else if (matchingKey.endsWith('Time')) {
if (!timeRegex.test(matchingValue)) {
logger.warn(
`Value ${matchingValue} on element ${assignmentRule.path} is not a valid FHIR time`
`Value ${matchingValue} on ${entityName} element ${assignmentRule.path} is not a valid FHIR time`
);
}
} else if (matchingKey.endsWith('Instant')) {
if (!instantRegex.test(matchingValue)) {
logger.warn(
`Value ${matchingValue} on element ${assignmentRule.path} is not a valid FHIR instant`
`Value ${matchingValue} on ${entityName} element ${assignmentRule.path} is not a valid FHIR instant`
);
}
}
Expand Down
21 changes: 17 additions & 4 deletions src/extractor/CaretValueRuleExtractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,17 @@ export class CaretValueRuleExtractor {
const remainingFlatElementArray = flatElementArray.filter(
([key]) => !input.processedPaths.includes(key)
);
const entityPath = path === '' ? structDef.name : `${structDef.name}.${path}`;
remainingFlatElementArray.forEach(([key], i) => {
const caretValueRule = new ExportableCaretValueRule(path);
caretValueRule.caretPath = key;
caretValueRule.value = getFSHValue(i, remainingFlatElementArray, 'ElementDefinition', fisher);
caretValueRule.value = getFSHValue(
i,
remainingFlatElementArray,
'ElementDefinition',
entityPath,
fisher
);
// If the value is empty, we can't use it. Log an error and give up on trying to use this key.
if (isFSHValueEmpty(caretValueRule.value)) {
logger.error(
Expand Down Expand Up @@ -207,7 +214,7 @@ export class CaretValueRuleExtractor {
}
const caretValueRule = new ExportableCaretValueRule('');
caretValueRule.caretPath = key;
caretValueRule.value = getFSHValue(i, flatArray, 'StructureDefinition', fisher);
caretValueRule.value = getFSHValue(i, flatArray, 'StructureDefinition', input.name, fisher);
if (isFSHValueEmpty(caretValueRule.value)) {
logger.error(
`Value in StructureDefinition ${input.name} for element ${key} is empty. No caret value rule will be created.`
Expand Down Expand Up @@ -241,7 +248,13 @@ export class CaretValueRuleExtractor {
}
const caretValueRule = new ExportableCaretValueRule('');
caretValueRule.caretPath = key;
caretValueRule.value = getFSHValue(i, flatArray, resourceType, fisher);
caretValueRule.value = getFSHValue(
i,
flatArray,
resourceType,
input.name ?? input.id,
fisher
);
if (isFSHValueEmpty(caretValueRule.value)) {
logger.error(
`Value in ${resourceType} ${
Expand Down Expand Up @@ -272,7 +285,7 @@ export class CaretValueRuleExtractor {
flatArray.forEach(([key], i) => {
const caretValueRule = new ExportableCaretValueRule('');
caretValueRule.caretPath = key;
caretValueRule.value = getFSHValue(i, flatArray, 'Concept', fisher);
caretValueRule.value = getFSHValue(i, flatArray, 'Concept', entityName, fisher);
caretValueRule.isCodeCaretRule = true;
caretValueRule.pathArray = [...pathArray];
if (isFSHValueEmpty(caretValueRule.value)) {
Expand Down
12 changes: 8 additions & 4 deletions src/extractor/InvariantExtractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
ProcessableStructureDefinition,
switchQuantityRules
} from '../processor';
import { getFSHValue, getPathValuePairs, isFSHValueEmpty } from '../utils';
import { getFSHValue, getPath, getPathValuePairs, isFSHValueEmpty } from '../utils';
import { ExportableAssignmentRule } from '../exportable';

export class InvariantExtractor {
Expand Down Expand Up @@ -55,21 +55,25 @@ export class InvariantExtractor {
// so that we can get the FSH value correctly.
// but, we want the original path for the rule itself.
const flatPropertyArray = toPairs(
getPathValuePairs(workingConstraint, x => `constraint.${x}`)
getPathValuePairs(workingConstraint, x => `constraint[${i}].${x}`)
);
const elementPath = getPath(input);
const entityPath =
elementPath === '.' ? structDef.name : `${structDef.name}.${elementPath}`;
flatPropertyArray.forEach(([path], propertyIdx) => {
const originalPath = path.replace('constraint.', '');
const originalPath = path.replace(`constraint[${i}].`, '');
const assignmentRule = new ExportableAssignmentRule(originalPath);
assignmentRule.value = getFSHValue(
propertyIdx,
flatPropertyArray,
'ElementDefinition',
entityPath,
fisher
);
if (!isFSHValueEmpty(assignmentRule.value)) {
invariant.rules.push(assignmentRule);
}
constraintPaths.push(`constraint[${i}].${originalPath}`);
constraintPaths.push(path);
});
switchQuantityRules(invariant.rules);

Expand Down
8 changes: 7 additions & 1 deletion src/processor/InstanceProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,13 @@ export class InstanceProcessor {
const flatInstanceArray = toPairs(getPathValuePairs(inputJSON));
flatInstanceArray.forEach(([path], i) => {
const assignmentRule = new ExportableAssignmentRule(path);
assignmentRule.value = getFSHValue(i, flatInstanceArray, instanceOfJSON.type, fisher);
assignmentRule.value = getFSHValue(
i,
flatInstanceArray,
instanceOfJSON.type,
target.name,
fisher
);
// if the value is empty, we can't use that
if (isFSHValueEmpty(assignmentRule.value)) {
logger.error(
Expand Down
6 changes: 3 additions & 3 deletions src/processor/StructureDefinitionProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,21 +225,21 @@ export class StructureDefinitionProcessor {
newRules.push(
BindingRuleExtractor.process(element),
ObeysRuleExtractor.process(element),
...AssignmentRuleExtractor.process(element)
...AssignmentRuleExtractor.process(element, target.name)
);
} else if (isNewSlice) {
newRules.push(
ContainsRuleExtractor.process(element, input, fisher),
OnlyRuleExtractor.process(element),
...AssignmentRuleExtractor.process(element),
...AssignmentRuleExtractor.process(element, target.name),
BindingRuleExtractor.process(element),
ObeysRuleExtractor.process(element)
);
} else {
newRules.push(
CardRuleExtractor.process(element, input, fisher),
OnlyRuleExtractor.process(element),
...AssignmentRuleExtractor.process(element),
...AssignmentRuleExtractor.process(element, target.name),
FlagRuleExtractor.process(element),
BindingRuleExtractor.process(element),
ObeysRuleExtractor.process(element)
Expand Down
36 changes: 27 additions & 9 deletions src/utils/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export function getFSHValue(
index: number,
flatArray: [string, string | number | boolean][],
resourceType: string,
resourceName: string,
fisher: utils.Fishable
): number | boolean | string | fshtypes.FshCode | bigint {
const [key, value] = flatArray[index];
Expand All @@ -103,23 +104,31 @@ export function getFSHValue(
return BigInt(value);
} else if (type === 'dateTime') {
if (!dateTimeRegex.test(value.toString())) {
logger.warn(`Value ${value.toString()} on element ${key} is not a valid FHIR dateTime`);
logger.warn(
`Value ${value.toString()} on ${resourceName} element ${key} is not a valid FHIR dateTime`
);
}
return value;
} else if (type === 'date') {
if (!dateRegex.test(value.toString())) {
logger.warn(`Value ${value.toString()} on element ${key} is not a valid FHIR date`);
logger.warn(
`Value ${value.toString()} on ${resourceName} element ${key} is not a valid FHIR date`
);
}
return value;
} else if (type === 'time') {
if (!timeRegex.test(value.toString())) {
logger.warn(`Value ${value.toString()} on element ${key} is not a valid FHIR time`);
logger.warn(
`Value ${value.toString()} on ${resourceName} element ${key} is not a valid FHIR time`
);
}
return value;
} else if (type === 'instant') {
typeCache.get(resourceType).set(pathWithoutIndex, 'instant');
if (!instantRegex.test(value.toString())) {
logger.warn(`Value ${value.toString()} on element ${key} is not a valid FHIR instant`);
logger.warn(
`Value ${value.toString()} on ${resourceName} element ${key} is not a valid FHIR instant`
);
}
return value;
} else if (type) {
Expand Down Expand Up @@ -150,9 +159,10 @@ export function getFSHValue(
]) as [string, string | number | boolean][];
const containedResourceType = subArray.find(([key]) => key === 'resourceType')?.[1] as string;
const newIndex = subArray.findIndex(([key]) => key === newKey);
const containedResourceName = `${resourceName}.${baseKey}`;

// Get the FSH value based on the contained resource type. Use paths relative to the contained resource.
return getFSHValue(newIndex, subArray, containedResourceType, fisher);
return getFSHValue(newIndex, subArray, containedResourceType, containedResourceName, fisher);
}
if (!typeCache.has(resourceType)) {
typeCache.set(resourceType, new Map());
Expand All @@ -170,25 +180,33 @@ export function getFSHValue(
} else if (element?.type?.[0]?.code === 'dateTime') {
typeCache.get(resourceType).set(pathWithoutIndex, 'dateTime');
if (!dateTimeRegex.test(value.toString())) {
logger.warn(`Value ${value.toString()} on element ${key} is not a valid FHIR dateTime`);
logger.warn(
`Value ${value.toString()} on ${resourceName} element ${key} is not a valid FHIR dateTime`
);
}
return value;
} else if (element?.type?.[0]?.code === 'date') {
typeCache.get(resourceType).set(pathWithoutIndex, 'date');
if (!dateRegex.test(value.toString())) {
logger.warn(`Value ${value.toString()} on element ${key} is not a valid FHIR date`);
logger.warn(
`Value ${value.toString()} on ${resourceName} element ${key} is not a valid FHIR date`
);
}
return value;
} else if (element?.type?.[0]?.code === 'time') {
typeCache.get(resourceType).set(pathWithoutIndex, 'time');
if (!timeRegex.test(value.toString())) {
logger.warn(`Value ${value.toString()} on element ${key} is not a valid FHIR time`);
logger.warn(
`Value ${value.toString()} on ${resourceName} element ${key} is not a valid FHIR time`
);
}
return value;
} else if (element?.type?.[0]?.code === 'instant') {
typeCache.get(resourceType).set(pathWithoutIndex, 'instant');
if (!instantRegex.test(value.toString())) {
logger.warn(`Value ${value.toString()} on element ${key} is not a valid FHIR instant`);
logger.warn(
`Value ${value.toString()} on ${resourceName} element ${key} is not a valid FHIR instant`
);
}
return value;
} else {
Expand Down
Loading

0 comments on commit a60e4a1

Please sign in to comment.