Merge branch 'master' into do-20240909-package-lock-cleanup

This commit is contained in:
dotasek 2024-09-18 09:29:46 -04:00
commit 3d6650399c
26 changed files with 128 additions and 87 deletions

View File

@ -1,18 +1,7 @@
## Validator Changes ## Validator Changes
* Fix expression for con-3 properly (fix validation problem on some condition resources) * no changes
* Fix FHIRPath bug using wrong type on simple elements when checking FHIRPath types
* FHIRPath: Allow _ in constant names (per FHIRPath spec)
* Fix value set rendering creating wrong references
* Fix bug processing value set includes / excludes that are just value sets (no system value)
* Alter processing of unknown code systems per discussion at ,https://chat.fhir.org/#narrow/stream/179252-IG-creation/topic/Don't.20error.20when.20you.20can't.20find.20code.20system and implement unknown-codesystems-cause-errors
* Improve message for when elements are out of order in profile differentials
## Other code changes ## Other code changes
* fix problem where profile rendering had spurious 'slices for' nodes everywhere * no changes
* Update SQL-On-FHIR implementation for latest cases, and clone test cases to general test care repository
* Fix problem generating value set spreadsheets
* fix concurrent modification error processing language translations
* Check for null fetcher processing ConceptMaps (#1728)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -1,5 +1,5 @@
Locale,Coverage #,Coverage % Locale,Coverage #,Coverage %
de,831,41% de,831,40%
es,714,35% es,714,35%
ja,902,44% ja,902,44%
nl,1989,98% nl,1989,98%

1 Locale Coverage # Coverage %
2 de 831 41% 40%
3 es 714 35%
4 ja 902 44%
5 nl 1989 98%

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -413,11 +413,10 @@ public class ProfileUtilities {
// note that ProfileUtilities are used re-entrantly internally, so nothing with process state can be here // note that ProfileUtilities are used re-entrantly internally, so nothing with process state can be here
private final IWorkerContext context; private final IWorkerContext context;
private FHIRPathEngine fpe; private FHIRPathEngine fpe;
private List<ValidationMessage> messages; private List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
private List<String> snapshotStack = new ArrayList<String>(); private List<String> snapshotStack = new ArrayList<String>();
private ProfileKnowledgeProvider pkp; private ProfileKnowledgeProvider pkp;
// private boolean igmode; // private boolean igmode;
private boolean exception;
private ValidationOptions terminologyServiceOptions = new ValidationOptions(FhirPublication.R5); private ValidationOptions terminologyServiceOptions = new ValidationOptions(FhirPublication.R5);
private boolean newSlicingProcessing; private boolean newSlicingProcessing;
private String defWebRoot; private String defWebRoot;
@ -431,11 +430,16 @@ public class ProfileUtilities {
private MappingMergeModeOption mappingMergeMode = MappingMergeModeOption.APPEND; private MappingMergeModeOption mappingMergeMode = MappingMergeModeOption.APPEND;
private boolean forPublication; private boolean forPublication;
private List<StructureDefinition> obligationProfiles = new ArrayList<>(); private List<StructureDefinition> obligationProfiles = new ArrayList<>();
private boolean wantThrowExceptions;
public ProfileUtilities(IWorkerContext context, List<ValidationMessage> messages, ProfileKnowledgeProvider pkp, FHIRPathEngine fpe) { public ProfileUtilities(IWorkerContext context, List<ValidationMessage> messages, ProfileKnowledgeProvider pkp, FHIRPathEngine fpe) {
super(); super();
this.context = context; this.context = context;
if (messages != null) {
this.messages = messages; this.messages = messages;
} else {
wantThrowExceptions = true;
}
this.pkp = pkp; this.pkp = pkp;
this.fpe = fpe; this.fpe = fpe;
@ -447,7 +451,11 @@ public class ProfileUtilities {
public ProfileUtilities(IWorkerContext context, List<ValidationMessage> messages, ProfileKnowledgeProvider pkp) { public ProfileUtilities(IWorkerContext context, List<ValidationMessage> messages, ProfileKnowledgeProvider pkp) {
super(); super();
this.context = context; this.context = context;
if (messages != null) {
this.messages = messages; this.messages = messages;
} else {
wantThrowExceptions = true;
}
this.pkp = pkp; this.pkp = pkp;
if (context != null) { if (context != null) {
this.fpe = new FHIRPathEngine(context, this); this.fpe = new FHIRPathEngine(context, this);
@ -789,7 +797,7 @@ public class ProfileUtilities {
ce++; ce++;
if (e.hasId()) { if (e.hasId()) {
String msg = "No match found for "+e.getId()+" in the generated snapshot: check that the path and definitions are legal in the differential (including order)"; String msg = "No match found for "+e.getId()+" in the generated snapshot: check that the path and definitions are legal in the differential (including order)";
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.differential.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, "StructureDefinition.differential.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR));
} }
} }
i++; i++;
@ -862,19 +870,19 @@ public class ProfileUtilities {
slice.getFocus().setMin(count); slice.getFocus().setMin(count);
} else { } else {
String msg = "The slice definition for "+slice.getFocus().getId()+" has a minimum of "+slice.getFocus().getMin()+" but the slices add up to a minimum of "+count; String msg = "The slice definition for "+slice.getFocus().getId()+" has a minimum of "+slice.getFocus().getMin()+" but the slices add up to a minimum of "+count;
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, forPublication ? ValidationMessage.IssueSeverity.ERROR : ValidationMessage.IssueSeverity.INFORMATION).setIgnorableError(true)); "StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, forPublication ? ValidationMessage.IssueSeverity.ERROR : ValidationMessage.IssueSeverity.INFORMATION).setIgnorableError(true));
} }
} }
count = slice.checkMax(); count = slice.checkMax();
if (count > -1 && repeats) { if (count > -1 && repeats) {
String msg = "The slice definition for "+slice.getFocus().getId()+" has a maximum of "+slice.getFocus().getMax()+" but the slices add up to a maximum of "+count+". Check that this is what is intended"; String msg = "The slice definition for "+slice.getFocus().getId()+" has a maximum of "+slice.getFocus().getMax()+" but the slices add up to a maximum of "+count+". Check that this is what is intended";
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, ValidationMessage.IssueSeverity.INFORMATION)); "StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, ValidationMessage.IssueSeverity.INFORMATION));
} }
if (!slice.checkMinMax()) { if (!slice.checkMinMax()) {
String msg = "The slice definition for "+slice.getFocus().getId()+" has a maximum of "+slice.getFocus().getMax()+" which is less than the minimum of "+slice.getFocus().getMin(); String msg = "The slice definition for "+slice.getFocus().getId()+" has a maximum of "+slice.getFocus().getMax()+" which is less than the minimum of "+slice.getFocus().getMin();
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, ValidationMessage.IssueSeverity.WARNING)); "StructureDefinition.snapshot.element["+slice.getIndex()+"]", msg, ValidationMessage.IssueSeverity.WARNING));
} }
slices.remove(s); slices.remove(s);
@ -885,13 +893,13 @@ public class ProfileUtilities {
} }
if (ed.hasSliceName() && !slices.containsKey(ed.getPath())) { if (ed.hasSliceName() && !slices.containsKey(ed.getPath())) {
String msg = "The element "+ed.getId()+" launches straight into slicing without the slicing being set up properly first"; String msg = "The element "+ed.getId()+" launches straight into slicing without the slicing being set up properly first";
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true)); "StructureDefinition.snapshot.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true));
} }
if (ed.hasSliceName() && slices.containsKey(ed.getPath())) { if (ed.hasSliceName() && slices.containsKey(ed.getPath())) {
if (!slices.get(ed.getPath()).count(ed, ed.getSliceName())) { if (!slices.get(ed.getPath()).count(ed, ed.getSliceName())) {
String msg = "Duplicate slice name "+ed.getSliceName()+" on "+ed.getId()+" (["+i+"])"; String msg = "Duplicate slice name "+ed.getSliceName()+" on "+ed.getId()+" (["+i+"])";
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true)); "StructureDefinition.snapshot.element["+i+"]", msg, ValidationMessage.IssueSeverity.ERROR).setIgnorableError(true));
} }
} }
@ -910,10 +918,8 @@ public class ProfileUtilities {
} }
} }
if (sd == null) { if (sd == null) {
if (messages != null) { addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE,
"StructureDefinition.snapshot.element["+i+"]", "The type of profile "+u.getValue()+" cannot be checked as the profile is not known", IssueSeverity.WARNING)); "StructureDefinition.snapshot.element["+i+"]", "The type of profile "+u.getValue()+" cannot be checked as the profile is not known", IssueSeverity.WARNING));
}
} else { } else {
String wt = t.getWorkingCode(); String wt = t.getWorkingCode();
if (ed.getPath().equals("Bundle.entry.response.outcome")) { if (ed.getPath().equals("Bundle.entry.response.outcome")) {
@ -1012,13 +1018,15 @@ public class ProfileUtilities {
} }
private void handleError(String url, String msg) { private void handleError(String url, String msg) {
if (exception) addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url, msg, ValidationMessage.IssueSeverity.ERROR));
throw new DefinitionException(msg);
else
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url, msg, ValidationMessage.IssueSeverity.ERROR));
} }
private void addMessage(ValidationMessage msg) {
messages.add(msg);
if (msg.getLevel() == IssueSeverity.ERROR && wantThrowExceptions) {
throw new DefinitionException(msg.getMessage());
}
}
private void copyInheritedExtensions(StructureDefinition base, StructureDefinition derived, String webUrl) { private void copyInheritedExtensions(StructureDefinition base, StructureDefinition derived, String webUrl) {
@ -2249,7 +2257,7 @@ public class ProfileUtilities {
* Not sure we have enough information here to do the check properly. Might be better done when we're sorting the profile? * Not sure we have enough information here to do the check properly. Might be better done when we're sorting the profile?
if (i != start && result.isEmpty() && !path.startsWith(context.getElement().get(start).getPath())) if (i != start && result.isEmpty() && !path.startsWith(context.getElement().get(start).getPath()))
messages.add(new ValidationMessage(Source.ProfileValidator, IssueType.VALUE, "StructureDefinition.differential.element["+Integer.toString(start)+"]", "Error: unknown element '"+context.getElement().get(start).getPath()+"' (or it is out of order) in profile '"+url+"' (looking for '"+path+"')", IssueSeverity.WARNING)); addMessage(new ValidationMessage(Source.ProfileValidator, IssueType.VALUE, "StructureDefinition.differential.element["+Integer.toString(start)+"]", "Error: unknown element '"+context.getElement().get(start).getPath()+"' (or it is out of order) in profile '"+url+"' (looking for '"+path+"')", IssueSeverity.WARNING));
*/ */
result.add(context.getElement().get(i)); result.add(context.getElement().get(i));
@ -2529,7 +2537,7 @@ public class ProfileUtilities {
if (derived.hasMinElement()) { if (derived.hasMinElement()) {
if (!Base.compareDeep(derived.getMinElement(), base.getMinElement(), false)) { if (!Base.compareDeep(derived.getMinElement(), base.getMinElement(), false)) {
if (derived.getMin() < base.getMin() && !derived.hasSliceName()) // in a slice, minimum cardinality rules do not apply if (derived.getMin() < base.getMin() && !derived.hasSliceName()) // in a slice, minimum cardinality rules do not apply
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived min ("+Integer.toString(derived.getMin())+") cannot be less than the base min ("+Integer.toString(base.getMin())+") in "+srcSD.getVersionedUrl(), ValidationMessage.IssueSeverity.ERROR)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived min ("+Integer.toString(derived.getMin())+") cannot be less than the base min ("+Integer.toString(base.getMin())+") in "+srcSD.getVersionedUrl(), ValidationMessage.IssueSeverity.ERROR));
base.setMinElement(derived.getMinElement().copy()); base.setMinElement(derived.getMinElement().copy());
} else if (trimDifferential) } else if (trimDifferential)
derived.setMinElement(null); derived.setMinElement(null);
@ -2540,7 +2548,7 @@ public class ProfileUtilities {
if (derived.hasMaxElement()) { if (derived.hasMaxElement()) {
if (!Base.compareDeep(derived.getMaxElement(), base.getMaxElement(), false)) { if (!Base.compareDeep(derived.getMaxElement(), base.getMaxElement(), false)) {
if (isLargerMax(derived.getMax(), base.getMax())) if (isLargerMax(derived.getMax(), base.getMax()))
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived max ("+derived.getMax()+") cannot be greater than the base max ("+base.getMax()+")", ValidationMessage.IssueSeverity.ERROR)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+source.getPath(), "Element "+base.getPath()+": derived max ("+derived.getMax()+") cannot be greater than the base max ("+base.getMax()+")", ValidationMessage.IssueSeverity.ERROR));
base.setMaxElement(derived.getMaxElement().copy()); base.setMaxElement(derived.getMaxElement().copy());
} else if (trimDifferential) } else if (trimDifferential)
derived.setMaxElement(null); derived.setMaxElement(null);
@ -2642,7 +2650,7 @@ public class ProfileUtilities {
} }
if (!(base.hasMustSupportElement() && Base.compareDeep(base.getMustSupportElement(), mse, false))) { if (!(base.hasMustSupportElement() && Base.compareDeep(base.getMustSupportElement(), mse, false))) {
if (base.hasMustSupport() && base.getMustSupport() && !derived.getMustSupport()) { if (base.hasMustSupport() && base.getMustSupport() && !derived.getMustSupport()) {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Illegal constraint [must-support = false] when [must-support = true] in the base profile", ValidationMessage.IssueSeverity.ERROR)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Illegal constraint [must-support = false] when [must-support = true] in the base profile", ValidationMessage.IssueSeverity.ERROR));
} }
base.setMustSupportElement(mse); base.setMustSupportElement(mse);
} else if (trimDifferential) } else if (trimDifferential)
@ -2654,7 +2662,7 @@ public class ProfileUtilities {
if (derived.hasMustHaveValueElement()) { if (derived.hasMustHaveValueElement()) {
if (!(base.hasMustHaveValueElement() && Base.compareDeep(derived.getMustHaveValueElement(), base.getMustHaveValueElement(), false))) { if (!(base.hasMustHaveValueElement() && Base.compareDeep(derived.getMustHaveValueElement(), base.getMustHaveValueElement(), false))) {
if (base.hasMustHaveValue() && base.getMustHaveValue() && !derived.getMustHaveValue()) { if (base.hasMustHaveValue() && base.getMustHaveValue() && !derived.getMustHaveValue()) {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Illegal constraint [must-have-value = false] when [must-have-value = true] in the base profile", ValidationMessage.IssueSeverity.ERROR)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Illegal constraint [must-have-value = false] when [must-have-value = true] in the base profile", ValidationMessage.IssueSeverity.ERROR));
} }
base.setMustHaveValueElement(derived.getMustHaveValueElement().copy()); base.setMustHaveValueElement(derived.getMustHaveValueElement().copy());
} else if (trimDifferential) } else if (trimDifferential)
@ -2721,25 +2729,25 @@ public class ProfileUtilities {
if (!base.hasBinding() || !Base.compareDeep(derived.getBinding(), base.getBinding(), false)) { if (!base.hasBinding() || !Base.compareDeep(derived.getBinding(), base.getBinding(), false)) {
if (base.hasBinding() && base.getBinding().getStrength() == BindingStrength.REQUIRED && derived.getBinding().getStrength() != BindingStrength.REQUIRED) if (base.hasBinding() && base.getBinding().getStrength() == BindingStrength.REQUIRED && derived.getBinding().getStrength() != BindingStrength.REQUIRED)
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "illegal attempt to change the binding on "+derived.getPath()+" from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode(), ValidationMessage.IssueSeverity.ERROR)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "illegal attempt to change the binding on "+derived.getPath()+" from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode(), ValidationMessage.IssueSeverity.ERROR));
// throw new DefinitionException("StructureDefinition "+pn+" at "+derived.getPath()+": illegal attempt to change a binding from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode()); // throw new DefinitionException("StructureDefinition "+pn+" at "+derived.getPath()+": illegal attempt to change a binding from "+base.getBinding().getStrength().toCode()+" to "+derived.getBinding().getStrength().toCode());
else if (base.hasBinding() && derived.hasBinding() && base.getBinding().getStrength() == BindingStrength.REQUIRED && base.getBinding().hasValueSet() && derived.getBinding().hasValueSet()) { else if (base.hasBinding() && derived.hasBinding() && base.getBinding().getStrength() == BindingStrength.REQUIRED && base.getBinding().hasValueSet() && derived.getBinding().hasValueSet()) {
ValueSet baseVs = context.findTxResource(ValueSet.class, base.getBinding().getValueSet(), srcSD); ValueSet baseVs = context.findTxResource(ValueSet.class, base.getBinding().getValueSet(), srcSD);
ValueSet contextVs = context.findTxResource(ValueSet.class, derived.getBinding().getValueSet(), derivedSrc); ValueSet contextVs = context.findTxResource(ValueSet.class, derived.getBinding().getValueSet(), derivedSrc);
if (baseVs == null) { if (baseVs == null) {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+base.getPath(), "Binding "+base.getBinding().getValueSet()+" could not be located", ValidationMessage.IssueSeverity.WARNING)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+base.getPath(), "Binding "+base.getBinding().getValueSet()+" could not be located", ValidationMessage.IssueSeverity.WARNING));
} else if (contextVs == null) { } else if (contextVs == null) {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" could not be located", ValidationMessage.IssueSeverity.WARNING)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" could not be located", ValidationMessage.IssueSeverity.WARNING));
} else { } else {
ValueSetExpansionOutcome expBase = context.expandVS(baseVs, true, false); ValueSetExpansionOutcome expBase = context.expandVS(baseVs, true, false);
ValueSetExpansionOutcome expDerived = context.expandVS(contextVs, true, false); ValueSetExpansionOutcome expDerived = context.expandVS(contextVs, true, false);
if (expBase.getValueset() == null) if (expBase.getValueset() == null)
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+base.getPath(), "Binding "+base.getBinding().getValueSet()+" could not be expanded", ValidationMessage.IssueSeverity.WARNING)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+base.getPath(), "Binding "+base.getBinding().getValueSet()+" could not be expanded", ValidationMessage.IssueSeverity.WARNING));
else if (expDerived.getValueset() == null) else if (expDerived.getValueset() == null)
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" could not be expanded", ValidationMessage.IssueSeverity.WARNING)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" could not be expanded", ValidationMessage.IssueSeverity.WARNING));
else if (ToolingExtensions.hasExtension(expBase.getValueset().getExpansion(), ToolingExtensions.EXT_EXP_TOOCOSTLY)) { else if (ToolingExtensions.hasExtension(expBase.getValueset().getExpansion(), ToolingExtensions.EXT_EXP_TOOCOSTLY)) {
if (ToolingExtensions.hasExtension(expDerived.getValueset().getExpansion(), ToolingExtensions.EXT_EXP_TOOCOSTLY) || expDerived.getValueset().getExpansion().getContains().size() > 100) { if (ToolingExtensions.hasExtension(expDerived.getValueset().getExpansion(), ToolingExtensions.EXT_EXP_TOOCOSTLY) || expDerived.getValueset().getExpansion().getContains().size() > 100) {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Unable to check if "+derived.getBinding().getValueSet()+" is a proper subset of " +base.getBinding().getValueSet()+" - base value set is too large to check", ValidationMessage.IssueSeverity.WARNING)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Unable to check if "+derived.getBinding().getValueSet()+" is a proper subset of " +base.getBinding().getValueSet()+" - base value set is too large to check", ValidationMessage.IssueSeverity.WARNING));
} else { } else {
boolean ok = true; boolean ok = true;
for (ValueSetExpansionContainsComponent cc : expDerived.getValueset().getExpansion().getContains()) { for (ValueSetExpansionContainsComponent cc : expDerived.getValueset().getExpansion().getContains()) {
@ -2750,11 +2758,11 @@ public class ProfileUtilities {
} }
} }
if (!ok) { if (!ok) {
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" is not a subset of binding "+base.getBinding().getValueSet(), ValidationMessage.IssueSeverity.ERROR)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" is not a subset of binding "+base.getBinding().getValueSet(), ValidationMessage.IssueSeverity.ERROR));
} }
} }
} else if (!isSubset(expBase.getValueset(), expDerived.getValueset())) } else if (!isSubset(expBase.getValueset(), expDerived.getValueset()))
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" is not a subset of binding "+base.getBinding().getValueSet(), ValidationMessage.IssueSeverity.ERROR)); addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, pn+"."+derived.getPath(), "Binding "+derived.getBinding().getValueSet()+" is not a subset of binding "+base.getBinding().getValueSet(), ValidationMessage.IssueSeverity.ERROR));
} }
} }
ElementDefinitionBindingComponent d = derived.getBinding(); ElementDefinitionBindingComponent d = derived.getBinding();
@ -2965,11 +2973,7 @@ public class ProfileUtilities {
if (tgtOk) { if (tgtOk) {
ok = true; ok = true;
} else { } else {
if (messages == null) { addMessage(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, derived.getPath(), context.formatMessage(I18nConstants.ERROR_AT__THE_TARGET_PROFILE__IS_NOT__VALID_CONSTRAINT_ON_THE_BASE_, purl, derived.getPath(), url, td.getTargetProfile()), IssueSeverity.ERROR));
throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT__THE_TARGET_PROFILE__IS_NOT__VALID_CONSTRAINT_ON_THE_BASE_, purl, derived.getPath(), url, td.getTargetProfile()));
} else {
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, derived.getPath(), "The target profile " + u.getValue() + " is not a valid constraint on the base (" + td.getTargetProfile() + ") at " + derived.getPath(), IssueSeverity.ERROR));
}
} }
} }
} else { } else {
@ -2989,9 +2993,7 @@ public class ProfileUtilities {
} }
StructureDefinition sd = context.fetchResource(StructureDefinition.class, url); StructureDefinition sd = context.fetchResource(StructureDefinition.class, url);
if (sd == null) { if (sd == null) {
if (messages != null) { addMessage(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, path, "Cannot check whether the target profile " + url + " on "+dPath+" is valid constraint on the base because it is not known", IssueSeverity.WARNING));
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, path, "Cannot check whether the target profile " + url + " on "+dPath+" is valid constraint on the base because it is not known", IssueSeverity.WARNING));
}
return true; return true;
} else { } else {
if (sd.hasBaseDefinition() && sdConformsToTargets(path, dPath, sd.getBaseDefinition(), td)) { if (sd.hasBaseDefinition() && sdConformsToTargets(path, dPath, sd.getBaseDefinition(), td)) {
@ -3022,7 +3024,7 @@ public class ProfileUtilities {
} }
if (!ok) { if (!ok) {
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.CONFLICT, dest.getId(), "The "+fieldName+" value has type '"+ft+"' which is not valid (valid "+Utilities.pluralize("type", dest.getType().size())+": "+types.toString()+")", IssueSeverity.ERROR)); addMessage(new ValidationMessage(Source.InstanceValidator, IssueType.CONFLICT, dest.getId(), "The "+fieldName+" value has type '"+ft+"' which is not valid (valid "+Utilities.pluralize("type", dest.getType().size())+": "+types.toString()+")", IssueSeverity.ERROR));
} }
} }
@ -3936,10 +3938,7 @@ public class ProfileUtilities {
} }
ed.setId(bs); ed.setId(bs);
if (idList.containsKey(bs)) { if (idList.containsKey(bs)) {
if (exception || messages == null) { addMessage(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, name+"."+bs, context.formatMessage(I18nConstants.SAME_ID_ON_MULTIPLE_ELEMENTS__IN_, bs, idList.get(bs), ed.getPath(), name), ValidationMessage.IssueSeverity.ERROR));
throw new DefinitionException(context.formatMessage(I18nConstants.SAME_ID_ON_MULTIPLE_ELEMENTS__IN_, bs, idList.get(bs), ed.getPath(), name));
} else
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.BUSINESSRULE, name+"."+bs, "Duplicate Element id "+bs, ValidationMessage.IssueSeverity.ERROR));
} }
idList.put(bs, ed.getPath()); idList.put(bs, ed.getPath());
if (ed.hasContentReference() && ed.getContentReference().startsWith("#")) { if (ed.hasContentReference() && ed.getContentReference().startsWith("#")) {
@ -4315,12 +4314,12 @@ public class ProfileUtilities {
public boolean isThrowException() { public boolean isThrowException() {
return exception; return wantThrowExceptions;
} }
public void setThrowException(boolean exception) { public void setThrowException(boolean exception) {
this.exception = exception; this.wantThrowExceptions = exception;
} }
@ -4578,8 +4577,10 @@ public class ProfileUtilities {
} }
public void setMessages(List<ValidationMessage> messages) { public void setMessages(List<ValidationMessage> messages) {
if (messages != null) {
this.messages = messages; this.messages = messages;
} }
}
private Map<String, List<Property>> propertyCache = new HashMap<>(); private Map<String, List<Property>> propertyCache = new HashMap<>();

View File

@ -750,9 +750,9 @@ public class ValueSetRenderer extends TerminologyRenderer {
if (cs == null) { if (cs == null) {
return "?cs-n?"; return "?cs-n?";
} }
String ref = (String) cs.getUserData("filename"); String ref = cs.getWebPath();
if (ref == null) { if (ref == null) {
ref = (String) cs.getWebPath(); ref = cs.getUserString("filename");
} }
return ref == null ? null : ref.replace("\\", "/"); return ref == null ? null : ref.replace("\\", "/");
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -1108,4 +1108,7 @@ public class I18nConstants {
public static final String SM_TARGET_TYPE_UNKNOWN = "SM_TARGET_TYPE_UNKNOWN"; public static final String SM_TARGET_TYPE_UNKNOWN = "SM_TARGET_TYPE_UNKNOWN";
public static final String XHTML_XHTML_ATTRIBUTE_XML_SPACE = "XHTML_XHTML_ATTRIBUTE_XML_SPACE"; public static final String XHTML_XHTML_ATTRIBUTE_XML_SPACE = "XHTML_XHTML_ATTRIBUTE_XML_SPACE";
public static final String VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS = "VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS"; public static final String VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS = "VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS";
public static final String SD_BASE_EXPERIMENTAL = "SD_BASE_EXPERIMENTAL";
public static final String SD_ED_EXPERIMENTAL_BINDING = "SD_ED_EXPERIMENTAL_BINDING";
public static final String VALIDATION_NO_EXPERIMENTAL_CONTENT = "VALIDATION_NO_EXPERIMENTAL_CONTENT";
} }

View File

@ -1140,4 +1140,6 @@ XHTML_XHTML_ATTRIBUTE_XML_SPACE = The attribute 'xml:space' is legal but has a f
VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS = This resource has more than workgroup extension (http://hl7.org/fhir/StructureDefinition/structuredefinition-wg) VALIDATION_HL7_PUBLISHER_MULTIPLE_WGS = This resource has more than workgroup extension (http://hl7.org/fhir/StructureDefinition/structuredefinition-wg)
NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG = Wrong Display Name ''{0}'' for {1}#{2}. There are no valid display names found for language(s) ''{3}''. Default display is ''{4}'' NO_VALID_DISPLAY_FOUND_NONE_FOR_LANG = Wrong Display Name ''{0}'' for {1}#{2}. There are no valid display names found for language(s) ''{3}''. Default display is ''{4}''
NO_VALID_DISPLAY_AT_ALL = Cannot validate display Name ''{0}'' for {1}#{2}: No displays are known NO_VALID_DISPLAY_AT_ALL = Cannot validate display Name ''{0}'' for {1}#{2}: No displays are known
SD_BASE_EXPERIMENTAL = The definition builds on ''{0}'' which is experimental, but this definition is not labeled as experimental
SD_ED_EXPERIMENTAL_BINDING = The definition for the element ''{0}'' binds to the value set ''{1}'' which is experimental, but this structure is not labeled as experimental
VALIDATION_NO_EXPERIMENTAL_CONTENT = Experimental content is not allowed in this context

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -227,6 +227,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
@Getter @Setter private boolean checkIPSCodes; @Getter @Setter private boolean checkIPSCodes;
@Getter @Setter private BestPracticeWarningLevel bestPracticeLevel; @Getter @Setter private BestPracticeWarningLevel bestPracticeLevel;
@Getter @Setter private boolean unknownCodeSystemsCauseErrors; @Getter @Setter private boolean unknownCodeSystemsCauseErrors;
@Getter @Setter private boolean noExperimentalContent;
@Getter @Setter private Locale locale; @Getter @Setter private Locale locale;
@Getter @Setter private List<ImplementationGuide> igs = new ArrayList<>(); @Getter @Setter private List<ImplementationGuide> igs = new ArrayList<>();
@Getter @Setter private List<String> extensionDomains = new ArrayList<>(); @Getter @Setter private List<String> extensionDomains = new ArrayList<>();
@ -909,6 +910,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
validator.setPolicyAdvisor(policyAdvisor); validator.setPolicyAdvisor(policyAdvisor);
} }
validator.setUnknownCodeSystemsCauseErrors(unknownCodeSystemsCauseErrors); validator.setUnknownCodeSystemsCauseErrors(unknownCodeSystemsCauseErrors);
validator.setNoExperimentalContent(noExperimentalContent);
return validator; return validator;
} }

View File

@ -166,6 +166,9 @@ public class CliContext {
@JsonProperty("unknownCodeSystemsCauseErrors") @JsonProperty("unknownCodeSystemsCauseErrors")
private boolean unknownCodeSystemsCauseErrors; private boolean unknownCodeSystemsCauseErrors;
@JsonProperty("noExperimentalContent")
private boolean noExperimentalContent;
@JsonProperty("baseEngine") @JsonProperty("baseEngine")
public String getBaseEngine() { public String getBaseEngine() {
return baseEngine; return baseEngine;
@ -836,6 +839,7 @@ public class CliContext {
Objects.equals(bestPracticeLevel, that.bestPracticeLevel) && Objects.equals(bestPracticeLevel, that.bestPracticeLevel) &&
Objects.equals(watchScanDelay, that.watchScanDelay) && Objects.equals(watchScanDelay, that.watchScanDelay) &&
Objects.equals(unknownCodeSystemsCauseErrors, that.unknownCodeSystemsCauseErrors) && Objects.equals(unknownCodeSystemsCauseErrors, that.unknownCodeSystemsCauseErrors) &&
Objects.equals(noExperimentalContent, that.noExperimentalContent) &&
Objects.equals(watchSettleTime, that.watchSettleTime) ; Objects.equals(watchSettleTime, that.watchSettleTime) ;
} }
@ -844,7 +848,7 @@ public class CliContext {
return Objects.hash(baseEngine, doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, return Objects.hash(baseEngine, doNative, extensions, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching,
noExtensibleBindingMessages, noInvariants, displayWarnings, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT, noExtensibleBindingMessages, noInvariants, displayWarnings, wantInvariantsInMessages, map, output, outputSuffix, htmlOutput, txServer, sv, txLog, txCache, mapLog, lang, srcLang, tgtLang, fhirpath, snomedCT,
targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars, targetVer, igs, questionnaireMode, level, profiles, sources, inputs, mode, locale, locations, crumbTrails, forPublication, showTimes, allowExampleUrls, outputStyle, jurisdiction, noUnicodeBiDiControlChars,
watchMode, watchScanDelay, watchSettleTime, bestPracticeLevel, unknownCodeSystemsCauseErrors, htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes); watchMode, watchScanDelay, watchSettleTime, bestPracticeLevel, unknownCodeSystemsCauseErrors, noExperimentalContent, htmlInMarkdownCheck, allowDoubleQuotesInFHIRPath, checkIPSCodes);
} }
@Override @Override
@ -904,6 +908,7 @@ public class CliContext {
", watchSettleTime=" + watchSettleTime + ", watchSettleTime=" + watchSettleTime +
", watchScanDelay=" + watchScanDelay + ", watchScanDelay=" + watchScanDelay +
", unknownCodeSystemsCauseErrors=" + unknownCodeSystemsCauseErrors + ", unknownCodeSystemsCauseErrors=" + unknownCodeSystemsCauseErrors +
", noExperimentalContent=" + noExperimentalContent +
'}'; '}';
} }
@ -973,5 +978,16 @@ public class CliContext {
this.unknownCodeSystemsCauseErrors = unknownCodeSystemsCauseErrors; this.unknownCodeSystemsCauseErrors = unknownCodeSystemsCauseErrors;
} }
@JsonProperty("noExperimentalContent")
public boolean isNoExperimentalContent() {
return noExperimentalContent;
}
@JsonProperty("noExperimentalContent")
public void setNoExperimentalContent(boolean noExperimentalContent) {
this.noExperimentalContent = noExperimentalContent;
}
} }

View File

@ -582,6 +582,7 @@ public class ValidationService {
validationEngine.getBundleValidationRules().addAll(cliContext.getBundleValidationRules()); validationEngine.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction())); validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction()));
validationEngine.setUnknownCodeSystemsCauseErrors(cliContext.isUnknownCodeSystemsCauseErrors()); validationEngine.setUnknownCodeSystemsCauseErrors(cliContext.isUnknownCodeSystemsCauseErrors());
validationEngine.setNoExperimentalContent(cliContext.isNoExperimentalContent());
TerminologyCache.setNoCaching(cliContext.isNoInternalCaching()); TerminologyCache.setNoCaching(cliContext.isNoInternalCaching());
validationEngine.prepare(); // generate any missing snapshots validationEngine.prepare(); // generate any missing snapshots
System.out.println(" go (" + timeTracker.milestone() + ")"); System.out.println(" go (" + timeTracker.milestone() + ")");

View File

@ -95,6 +95,7 @@ public class Params {
public static final String CHECK_IPS_CODES = "-check-ips-codes"; public static final String CHECK_IPS_CODES = "-check-ips-codes";
public static final String BEST_PRACTICE = "-best-practice"; public static final String BEST_PRACTICE = "-best-practice";
public static final String UNKNOWN_CODESYSTEMS_CAUSE_ERROR = "-unknown-codesystems-cause-errors"; public static final String UNKNOWN_CODESYSTEMS_CAUSE_ERROR = "-unknown-codesystems-cause-errors";
public static final String NO_EXPERIMENTAL_CONTENT = "-no-experimental-content";
public static final String RUN_TESTS = "-run-tests"; public static final String RUN_TESTS = "-run-tests";
@ -321,6 +322,8 @@ public class Params {
cliContext.setForPublication(true); cliContext.setForPublication(true);
} else if (args[i].equals(UNKNOWN_CODESYSTEMS_CAUSE_ERROR)) { } else if (args[i].equals(UNKNOWN_CODESYSTEMS_CAUSE_ERROR)) {
cliContext.setUnknownCodeSystemsCauseErrors(true); cliContext.setUnknownCodeSystemsCauseErrors(true);
} else if (args[i].equals(NO_EXPERIMENTAL_CONTENT)) {
cliContext.setNoExperimentalContent(true);
} else if (args[i].equals(VERBOSE)) { } else if (args[i].equals(VERBOSE)) {
cliContext.setCrumbTrails(true); cliContext.setCrumbTrails(true);
} else if (args[i].equals(ALLOW_EXAMPLE_URLS)) { } else if (args[i].equals(ALLOW_EXAMPLE_URLS)) {

View File

@ -599,6 +599,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private IDigitalSignatureServices signatureServices; private IDigitalSignatureServices signatureServices;
private ContextUtilities cu; private ContextUtilities cu;
private boolean unknownCodeSystemsCauseErrors; private boolean unknownCodeSystemsCauseErrors;
private boolean noExperimentalContent;
public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager) { public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager) {
super(theContext, xverManager, false); super(theContext, xverManager, false);
@ -5718,6 +5719,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus); hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus);
} }
} }
if (noExperimentalContent) {
String exp = element.getNamedChildValue("experimental");
ok = rule(errors, "2024-09-17", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), !"true".equals(exp), I18nConstants.VALIDATION_NO_EXPERIMENTAL_CONTENT) && ok;
}
if (isHL7Core(element) && !isExample()) { if (isHL7Core(element) && !isExample()) {
ok = checkPublisherConsistency(valContext, errors, element, stack, contained) && ok; ok = checkPublisherConsistency(valContext, errors, element, stack, contained) && ok;
@ -7840,5 +7845,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
this.unknownCodeSystemsCauseErrors = unknownCodeSystemsCauseErrors; this.unknownCodeSystemsCauseErrors = unknownCodeSystemsCauseErrors;
} }
public boolean isNoExperimentalContent() {
return noExperimentalContent;
}
public void setNoExperimentalContent(boolean noExperimentalContent) {
this.noExperimentalContent = noExperimentalContent;
}
} }

View File

@ -85,6 +85,7 @@ public class StructureDefinitionValidator extends BaseValidator {
List<ElementDefinition> snapshot = sd.getSnapshot().getElement(); List<ElementDefinition> snapshot = sd.getSnapshot().getElement();
sd.setSnapshot(null); sd.setSnapshot(null);
typeName = sd.getTypeName(); typeName = sd.getTypeName();
boolean experimental = "true".equals(src.getNamedChildValue("experimental", false));
StructureDefinition base = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); StructureDefinition base = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition());
if (warning(errors, NO_RULE_DATE, IssueType.NOTFOUND, stack.getLiteralPath(), base != null, I18nConstants.UNABLE_TO_FIND_BASE__FOR_, sd.getBaseDefinition(), "StructureDefinition, so can't check the differential")) { if (warning(errors, NO_RULE_DATE, IssueType.NOTFOUND, stack.getLiteralPath(), base != null, I18nConstants.UNABLE_TO_FIND_BASE__FOR_, sd.getBaseDefinition(), "StructureDefinition, so can't check the differential")) {
if (rule(errors, NO_RULE_DATE, IssueType.NOTFOUND, stack.getLiteralPath(), sd.hasDerivation(), I18nConstants.SD_MUST_HAVE_DERIVATION, sd.getUrl())) { if (rule(errors, NO_RULE_DATE, IssueType.NOTFOUND, stack.getLiteralPath(), sd.hasDerivation(), I18nConstants.SD_MUST_HAVE_DERIVATION, sd.getUrl())) {
@ -129,6 +130,7 @@ public class StructureDefinitionValidator extends BaseValidator {
ok = rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), base.getKindElement().primitiveValue().equals(src.getChildValue("kind")), ok = rule(errors, "2022-11-02", IssueType.NOTFOUND, stack.getLiteralPath(), base.getKindElement().primitiveValue().equals(src.getChildValue("kind")),
I18nConstants.SD_DERIVATION_KIND_MISMATCH, base.getKindElement().primitiveValue(), src.getChildValue("kind")) && ok; I18nConstants.SD_DERIVATION_KIND_MISMATCH, base.getKindElement().primitiveValue(), src.getChildValue("kind")) && ok;
} }
warning(errors, "2024-09-17", IssueType.BUSINESSRULE, stack.getLiteralPath(), !base.getExperimental() || experimental, I18nConstants.SD_BASE_EXPERIMENTAL, sd.getBaseDefinition());
} }
List<Element> differentials = src.getChildrenByName("differential"); List<Element> differentials = src.getChildrenByName("differential");
@ -136,10 +138,10 @@ public class StructureDefinitionValidator extends BaseValidator {
boolean logical = "logical".equals(src.getNamedChildValue("kind", false)); boolean logical = "logical".equals(src.getNamedChildValue("kind", false));
boolean constraint = "constraint".equals(src.getNamedChildValue("derivation", false)); boolean constraint = "constraint".equals(src.getNamedChildValue("derivation", false));
for (Element differential : differentials) { for (Element differential : differentials) {
ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base) && ok; ok = validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base, experimental) && ok;
} }
for (Element snapshotE : snapshots) { for (Element snapshotE : snapshots) {
ok = validateElementList(errors, snapshotE, stack.push(snapshotE, -1, null, null), true, true, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base) && ok; ok = validateElementList(errors, snapshotE, stack.push(snapshotE, -1, null, null), true, true, sd, typeName, logical, constraint, src.getNamedChildValue("type", false), src.getNamedChildValue("url", false), src.getNamedChildValue("type", false), base, experimental) && ok;
} }
// obligation profile support // obligation profile support
@ -189,6 +191,7 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage()); rule(errors, NO_RULE_DATE, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage());
ok = false; ok = false;
} }
@ -409,19 +412,19 @@ public class StructureDefinitionValidator extends BaseValidator {
} }
} }
private boolean validateElementList(List<ValidationMessage> errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, String rootPath, String profileUrl, String profileType, StructureDefinition base) { private boolean validateElementList(List<ValidationMessage> errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, String rootPath, String profileUrl, String profileType, StructureDefinition base, boolean experimental) {
Map<String, String> invariantMap = new HashMap<>(); Map<String, String> invariantMap = new HashMap<>();
boolean ok = true; boolean ok = true;
List<Element> elements = elementList.getChildrenByName("element"); List<Element> elements = elementList.getChildrenByName("element");
int cc = 0; int cc = 0;
for (Element element : elements) { for (Element element : elements) {
ok = validateElementDefinition(errors, elements, element, stack.push(element, cc, null, null), snapshot, hasSnapshot, sd, typeName, logical, constraint, invariantMap, rootPath, profileUrl, profileType, base) && ok; ok = validateElementDefinition(errors, elements, element, stack.push(element, cc, null, null), snapshot, hasSnapshot, sd, typeName, logical, constraint, invariantMap, rootPath, profileUrl, profileType, base, experimental) && ok;
cc++; cc++;
} }
return ok; return ok;
} }
private boolean validateElementDefinition(List<ValidationMessage> errors, List<Element> elements, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, Map<String, String> invariantMap, String rootPath, String profileUrl, String profileType, StructureDefinition base) { private boolean validateElementDefinition(List<ValidationMessage> errors, List<Element> elements, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot, StructureDefinition sd, String typeName, boolean logical, boolean constraint, Map<String, String> invariantMap, String rootPath, String profileUrl, String profileType, StructureDefinition base, boolean experimental) {
boolean ok = true; boolean ok = true;
boolean typeMustSupport = false; boolean typeMustSupport = false;
String path = element.getNamedChildValue("path", false); String path = element.getNamedChildValue("path", false);
@ -522,7 +525,7 @@ public class StructureDefinitionValidator extends BaseValidator {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("can-bind") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Binding", typeCodes) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("can-bind") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Binding", typeCodes) && ok;
} }
Element binding = element.getNamedChild("binding", false); Element binding = element.getNamedChild("binding", false);
ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, path) && ok; ok = validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, path, experimental) && ok;
} else { } else {
// this is a good idea but there's plenty of cases where the rule isn't met; maybe one day it's worth investing the time to exclude these cases and bring this rule back // this is a good idea but there's plenty of cases where the rule isn't met; maybe one day it's worth investing the time to exclude these cases and bring this rule back
// String bt = boundType(typeCodes); // String bt = boundType(typeCodes);
@ -986,7 +989,7 @@ public class StructureDefinitionValidator extends BaseValidator {
return null; return null;
} }
private boolean validateBinding(List<ValidationMessage> errors, Element binding, NodeStack stack, Set<String> typeCodes, boolean snapshot, String path) { private boolean validateBinding(List<ValidationMessage> errors, Element binding, NodeStack stack, Set<String> typeCodes, boolean snapshot, String path, boolean experimental) {
boolean ok = true; boolean ok = true;
if (bindableType(typeCodes) == null) { if (bindableType(typeCodes) == null) {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot, I18nConstants.SD_ED_BIND_NO_BINDABLE, path, typeCodes.toString()) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot, I18nConstants.SD_ED_BIND_NO_BINDABLE, path, typeCodes.toString()) && ok;
@ -1006,7 +1009,12 @@ public class StructureDefinitionValidator extends BaseValidator {
if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs != null || serverSupportsValueSet(ref), I18nConstants.SD_ED_BIND_UNKNOWN_VS, path, ref)) { if (warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs != null || serverSupportsValueSet(ref), I18nConstants.SD_ED_BIND_UNKNOWN_VS, path, ref)) {
if (vs != null) { if (vs != null) {
ok = rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs instanceof ValueSet, I18nConstants.SD_ED_BIND_NOT_VS, path, ref, vs.fhirType()) && ok; if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), vs instanceof ValueSet, I18nConstants.SD_ED_BIND_NOT_VS, path, ref, vs.fhirType())) {
ValueSet vsr = (ValueSet) vs;
warning(errors, "2024-09-17", IssueType.BUSINESSRULE, stack.getLiteralPath(), !vsr.getExperimental() || experimental, I18nConstants.SD_ED_EXPERIMENTAL_BINDING, path, ref);
} else {
ok = false;
}
} }
} }
} }

View File

@ -362,6 +362,9 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
if (content.has("security-checks")) { if (content.has("security-checks")) {
val.setSecurityChecks(content.get("security-checks").getAsBoolean()); val.setSecurityChecks(content.get("security-checks").getAsBoolean());
} }
if (content.has("no-experimental-content")) {
val.setNoExperimentalContent(content.get("no-experimental-content").getAsBoolean());
}
if (content.has("noHtmlInMarkdown")) { if (content.has("noHtmlInMarkdown")) {
val.setHtmlInMarkdownCheck(HtmlInMarkdownCheck.ERROR); val.setHtmlInMarkdownCheck(HtmlInMarkdownCheck.ERROR);
} }

View File

@ -14,14 +14,14 @@
HAPI FHIR HAPI FHIR
--> -->
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.26-SNAPSHOT</version> <version>6.3.27-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>
<commons_compress_version>1.26.0</commons_compress_version> <commons_compress_version>1.26.0</commons_compress_version>
<guava_version>32.0.1-jre</guava_version> <guava_version>32.0.1-jre</guava_version>
<hapi_fhir_version>6.4.1</hapi_fhir_version> <hapi_fhir_version>6.4.1</hapi_fhir_version>
<validator_test_case_version>1.5.22-SNAPSHOT</validator_test_case_version> <validator_test_case_version>1.5.22</validator_test_case_version>
<jackson_version>2.17.0</jackson_version> <jackson_version>2.17.0</jackson_version>
<junit_jupiter_version>5.9.2</junit_jupiter_version> <junit_jupiter_version>5.9.2</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version> <junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>