Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/lf 1338 fix choice type support for resursive #34

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
This log documents significant changes for each release. This project follows
[Semantic Versioning](http://semver.org/).

## [1.0.1] - 2020-01-17
### Fixed
- Issues with the new choice type support raised in
https://github.com/HL7/fhirpath.js/pull/34.

## [1.0.0] - 2019-12-19
### Added
- Support for FHIR "choice types" (e.g. Observation.value). The support is
Expand Down
65 changes: 0 additions & 65 deletions fhir-context/extract-choice-types.js

This file was deleted.

86 changes: 86 additions & 0 deletions fhir-context/extract-model-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Takes a directory of JSON FHIR definitions (STU3 or R4) and extracts the information
// about "choice types" (polymorphic fields).

const process = require('process');
const childProcess = require('child_process');
const path = require('path');
const fs = require('fs');

const args = require('yargs')
.nargs('fhirDefDir', 1)
.describe('fhirDefDir', 'the directory pathname for the JSON FHIR '+
'definitions to be processed')
.nargs('outputDir', 1)
.describe('outputDir', 'the directory into which the output files should be written')
.demandOption(['fhirDefDir', 'outputDir'])
.help('h')
.alias('h', 'help')
.argv;

const fhirDefDir = args.fhirDefDir;
const outputDir = args.outputDir;

// Files defining choice type fields
const choiceTypeFiles = ['profiles-types.json', 'profiles-resources.json',
'profiles-others.json'];

let choiceTypePaths = {};
let pathsDefinedElsewhere = {};
for (let f of choiceTypeFiles) {
// File all of the "path" information from the file. There will be
// duplicates, but we will use a hash to get a unique list.
let fData = JSON.parse(fs.readFileSync(path.join(fhirDefDir, f)));
// Walk the tree, looking for "path", and then finding the associated "type"
// field, if any.
let currentResource;
function visitNode(n) {
if (n.kind === "resource") {
currentResource = n;
// Only process definitions that are not constraints on resources defined
// elsewhere.
if (currentResource.derivation !== "constraint") {
// Only process snapshot definitions (not differentials)
visitNode(currentResource.snapshot);
}
}
else {
if (n.id && n.path && n.contentReference) {
if (n.contentReference[0] !== '#')
throw new Error('Unhandled new type of contentReference');
let refID = n.contentReference.slice(1);
// The content references point to IDs, and we want the path, which is
// the same except for slice labels. Remove those.
refID = refID.replace(/:[^\.]+/g, '');
pathsDefinedElsewhere[n.path] = refID;
}
if (n.id && n.path && n.type && n.path.match(/\[x\]$/)) {
// Uppercase the first letter of the type codes so they can be appended to
// the choice field name.
let types = n.type.map(t=>t.code[0].toUpperCase() + t.code.slice(1));
// Remove the [x] from end of the path
choiceTypePaths[n.path.slice(0, -3)] = types;
}
else {
// Check sub-nodes that are objects or arrays
if (Array.isArray(n)) {
for (let e of n)
visitNode(e);
}
else if (typeof n === "object") {
for (let k of Object.keys(n))
visitNode(n[k]);
}
}
}
}
visitNode(fData);
}

// Output the results as JSON hash for ease of import and ease of checking
// whether a path is a choice type path.
// Since there are no nested objects, we can easily sort the output keys.
fs.writeFileSync(path.join(outputDir, 'choiceTypePaths.json'),
JSON.stringify(choiceTypePaths, Object.keys(choiceTypePaths).sort(), 2));
fs.writeFileSync(path.join(outputDir, 'pathsDefinedElsewhere.json'),
JSON.stringify(pathsDefinedElsewhere, Object.keys(pathsDefinedElsewhere).sort(), 2));

2 changes: 1 addition & 1 deletion fhir-context/r4/choiceTypePaths.json
Original file line number Diff line number Diff line change
Expand Up @@ -1362,4 +1362,4 @@
"Code",
"DateTime"
]
}
}
8 changes: 7 additions & 1 deletion fhir-context/r4/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,11 @@ module.exports = {
* A hash of resource element paths (e.g. Observation.value) that are known
* to point to fiels that are choice types.
*/
choiceTypePaths: require('./choiceTypePaths')
choiceTypePaths: require('./choiceTypePaths'),

/**
* A hash from paths to the path for which their content is defined, e.g.
* Questionnaire.item.item -> Questionnaire.item.
*/
pathsDefinedElsewhere: require('./pathsDefinedElsewhere')
}
57 changes: 57 additions & 0 deletions fhir-context/r4/pathsDefinedElsewhere.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"Bundle.entry.link": "Bundle.link",
"CapabilityStatement.rest.operation": "CapabilityStatement.rest.resource.operation",
"CapabilityStatement.rest.searchParam": "CapabilityStatement.rest.resource.searchParam",
"ChargeItemDefinition.propertyGroup.applicability": "ChargeItemDefinition.applicability",
"ClaimResponse.addItem.adjudication": "ClaimResponse.item.adjudication",
"ClaimResponse.addItem.detail.adjudication": "ClaimResponse.item.adjudication",
"ClaimResponse.addItem.detail.subDetail.adjudication": "ClaimResponse.item.adjudication",
"ClaimResponse.adjudication": "ClaimResponse.item.adjudication",
"ClaimResponse.item.detail.adjudication": "ClaimResponse.item.adjudication",
"ClaimResponse.item.detail.subDetail.adjudication": "ClaimResponse.item.adjudication",
"CodeSystem.concept.concept": "CodeSystem.concept",
"Composition.section.section": "Composition.section",
"ConceptMap.group.element.target.product": "ConceptMap.group.element.target.dependsOn",
"Consent.provision.provision": "Consent.provision",
"Contract.term.asset.answer": "Contract.term.offer.answer",
"Contract.term.group": "Contract.term",
"ExampleScenario.process.step.alternative.step": "ExampleScenario.process.step",
"ExampleScenario.process.step.operation.request": "ExampleScenario.instance.containedInstance",
"ExampleScenario.process.step.operation.response": "ExampleScenario.instance.containedInstance",
"ExampleScenario.process.step.process": "ExampleScenario.process",
"ExplanationOfBenefit.addItem.adjudication": "ExplanationOfBenefit.item.adjudication",
"ExplanationOfBenefit.addItem.detail.adjudication": "ExplanationOfBenefit.item.adjudication",
"ExplanationOfBenefit.addItem.detail.subDetail.adjudication": "ExplanationOfBenefit.item.adjudication",
"ExplanationOfBenefit.adjudication": "ExplanationOfBenefit.item.adjudication",
"ExplanationOfBenefit.item.detail.adjudication": "ExplanationOfBenefit.item.adjudication",
"ExplanationOfBenefit.item.detail.subDetail.adjudication": "ExplanationOfBenefit.item.adjudication",
"GraphDefinition.link.target.link": "GraphDefinition.link",
"ImplementationGuide.definition.page.page": "ImplementationGuide.definition.page",
"Invoice.totalPriceComponent": "Invoice.lineItem.priceComponent",
"MedicinalProductAuthorization.procedure.application": "MedicinalProductAuthorization.procedure",
"MedicinalProductIngredient.substance.strength": "MedicinalProductIngredient.specifiedSubstance.strength",
"MedicinalProductPackaged.packageItem.packageItem": "MedicinalProductPackaged.packageItem",
"Observation.component.referenceRange": "Observation.referenceRange",
"OperationDefinition.parameter.part": "OperationDefinition.parameter",
"Parameters.parameter.part": "Parameters.parameter",
"PlanDefinition.action.action": "PlanDefinition.action",
"Provenance.entity.agent": "Provenance.agent",
"Questionnaire.item.item": "Questionnaire.item",
"QuestionnaireResponse.item.answer.item": "QuestionnaireResponse.item",
"QuestionnaireResponse.item.item": "QuestionnaireResponse.item",
"RequestGroup.action.action": "RequestGroup.action",
"StructureMap.group.rule.rule": "StructureMap.group.rule",
"SubstanceSpecification.molecularWeight": "SubstanceSpecification.structure.isotope.molecularWeight",
"SubstanceSpecification.name.synonym": "SubstanceSpecification.name",
"SubstanceSpecification.name.translation": "SubstanceSpecification.name",
"SubstanceSpecification.structure.molecularWeight": "SubstanceSpecification.structure.isotope.molecularWeight",
"TestReport.teardown.action.operation": "TestReport.setup.action.operation",
"TestReport.test.action.assert": "TestReport.setup.action.assert",
"TestReport.test.action.operation": "TestReport.setup.action.operation",
"TestScript.teardown.action.operation": "TestScript.setup.action.operation",
"TestScript.test.action.assert": "TestScript.setup.action.assert",
"TestScript.test.action.operation": "TestScript.setup.action.operation",
"ValueSet.compose.exclude": "ValueSet.compose.include",
"ValueSet.expansion.contains.contains": "ValueSet.expansion.contains",
"ValueSet.expansion.contains.designation": "ValueSet.compose.include.concept.designation"
}
2 changes: 1 addition & 1 deletion fhir-context/stu3/choiceTypePaths.json
Original file line number Diff line number Diff line change
Expand Up @@ -1023,4 +1023,4 @@
"CodeableConcept",
"Reference"
]
}
}
8 changes: 7 additions & 1 deletion fhir-context/stu3/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,11 @@ module.exports = {
* A hash of resource element paths (e.g. Observation.value) that are known
* to point to fiels that are choice types.
*/
choiceTypePaths: require('./choiceTypePaths')
choiceTypePaths: require('./choiceTypePaths'),

/**
* A hash from paths to the path for which their content is defined, e.g.
* Questionnaire.item.item -> Questionnaire.item.
*/
pathsDefinedElsewhere: require('./pathsDefinedElsewhere')
}
37 changes: 37 additions & 0 deletions fhir-context/stu3/pathsDefinedElsewhere.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"Bundle.entry.link": "Bundle.link",
"CapabilityStatement.rest.searchParam": "CapabilityStatement.rest.resource.searchParam",
"ClaimResponse.addItem.adjudication": "ClaimResponse.item.adjudication",
"ClaimResponse.addItem.detail.adjudication": "ClaimResponse.item.adjudication",
"ClaimResponse.item.detail.adjudication": "ClaimResponse.item.adjudication",
"ClaimResponse.item.detail.subDetail.adjudication": "ClaimResponse.item.adjudication",
"CodeSystem.concept.concept": "CodeSystem.concept",
"Composition.section.section": "Composition.section",
"ConceptMap.group.element.target.product": "ConceptMap.group.element.target.dependsOn",
"Contract.term.group": "Contract.term",
"ExplanationOfBenefit.addItem.adjudication": "ExplanationOfBenefit.item.adjudication",
"ExplanationOfBenefit.addItem.detail.adjudication": "ExplanationOfBenefit.item.adjudication",
"ExplanationOfBenefit.item.detail.adjudication": "ExplanationOfBenefit.item.adjudication",
"ExplanationOfBenefit.item.detail.subDetail.adjudication": "ExplanationOfBenefit.item.adjudication",
"GraphDefinition.link.target.link": "GraphDefinition.link",
"ImplementationGuide.page.page": "ImplementationGuide.page",
"Observation.component.referenceRange": "Observation.referenceRange",
"OperationDefinition.parameter.part": "OperationDefinition.parameter",
"Parameters.parameter.part": "Parameters.parameter",
"PlanDefinition.action.action": "PlanDefinition.action",
"Provenance.entity.agent": "Provenance.agent",
"Questionnaire.item.item": "Questionnaire.item",
"QuestionnaireResponse.item.answer.item": "QuestionnaireResponse.item",
"QuestionnaireResponse.item.item": "QuestionnaireResponse.item",
"RequestGroup.action.action": "RequestGroup.action",
"StructureMap.group.rule.rule": "StructureMap.group.rule",
"TestReport.teardown.action.operation": "TestReport.setup.action.operation",
"TestReport.test.action.assert": "TestReport.setup.action.assert",
"TestReport.test.action.operation": "TestReport.setup.action.operation",
"TestScript.teardown.action.operation": "TestScript.setup.action.operation",
"TestScript.test.action.assert": "TestScript.setup.action.assert",
"TestScript.test.action.operation": "TestScript.setup.action.operation",
"ValueSet.compose.exclude": "ValueSet.compose.include",
"ValueSet.expansion.contains.contains": "ValueSet.expansion.contains",
"ValueSet.expansion.contains.designation": "ValueSet.compose.include.concept.designation"
}
Loading