Gg v5114 b (#356)
* Ensure "I" flag in profile table representation is not used for underlying infrastructural constraints that exist everywhere * render multiple values for properties if they exist * fix for npe * fix for use of "current" as version * fix bad package URLs as they are loaded * RELEASE_NOTES.md * Add rendering for must support on types, profiles, targets * Add new validation for must-support on types / profiles / targets + improve extension validation * add <code> when rendering turtle to HTML * RELEASE_NOTES.md * fix notes
This commit is contained in:
parent
8eeffb8979
commit
b578cfbc0d
|
@ -1,5 +1,5 @@
|
|||
Validator:
|
||||
* no changes with impact
|
||||
* Add new validation for must-support on types / profiles / targets + improve Extension validation
|
||||
|
||||
Other code changes:
|
||||
* Ensure "I" flag in profile table representation is not used just for infrastructural constraints
|
||||
|
@ -7,3 +7,5 @@ Other code changes:
|
|||
* Fix for npe rendering resources based on profiles
|
||||
* fix for use of "current" as version
|
||||
* hack for past bad package URLs
|
||||
* Add rendering for must support on types, profiles, targets
|
||||
* add <code> when rendering turtle to HTML
|
|
@ -3245,14 +3245,22 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
tl = t;
|
||||
if (t.hasTarget()) {
|
||||
c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null));
|
||||
if (isMustSupportDirect(t) && e.getMustSupport()) {
|
||||
c.addPiece(gen.new Piece(null, " ", null));
|
||||
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
|
||||
}
|
||||
c.getPieces().add(gen.new Piece(null, "(", null));
|
||||
boolean tfirst = true;
|
||||
for (UriType u : t.getTargetProfile()) {
|
||||
for (CanonicalType u : t.getTargetProfile()) {
|
||||
if (tfirst)
|
||||
tfirst = false;
|
||||
else
|
||||
c.addPiece(gen.new Piece(null, " | ", null));
|
||||
genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue());
|
||||
if (isMustSupport(u) && e.getMustSupport()) {
|
||||
c.addPiece(gen.new Piece(null, " ", null));
|
||||
c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false);
|
||||
}
|
||||
}
|
||||
c.getPieces().add(gen.new Piece(null, ")", null));
|
||||
if (t.getAggregation().size() > 0) {
|
||||
|
@ -3289,6 +3297,10 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
} else
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null)));
|
||||
if (isMustSupport(p) && e.getMustSupport()) {
|
||||
c.addPiece(gen.new Piece(null, " ", null));
|
||||
c.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String tc = t.getWorkingCode();
|
||||
|
@ -3301,8 +3313,13 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
} else if (pkp != null && pkp.hasLinkFor(tc)) {
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null)));
|
||||
} else
|
||||
} else {
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null)));
|
||||
}
|
||||
if (isMustSupportDirect(t) && e.getMustSupport()) {
|
||||
c.addPiece(gen.new Piece(null, " ", null));
|
||||
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
|
@ -3931,6 +3948,10 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null));
|
||||
else
|
||||
c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null));
|
||||
if (isMustSupportDirect(tr) && element.getMustSupport()) {
|
||||
c.addPiece(gen.new Piece(null, " ", null));
|
||||
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
|
||||
}
|
||||
c.getPieces().add(gen.new Piece(null, "(", null));
|
||||
}
|
||||
boolean first = true;
|
||||
|
@ -3938,6 +3959,10 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
if (!first)
|
||||
c.getPieces().add(gen.new Piece(null, " | ", null));
|
||||
genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue());
|
||||
if (isMustSupport(rt) && element.getMustSupport()) {
|
||||
c.addPiece(gen.new Piece(null, " ", null));
|
||||
c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
if (first)
|
||||
|
@ -3956,20 +3981,23 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
choicerow.getCells().add(gen.new Cell());
|
||||
choicerow.getCells().add(gen.new Cell(null, null, "", null, null));
|
||||
choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE);
|
||||
choicerow.getCells().add(gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null));
|
||||
// } else if (definitions.getConstraints().contthnsKey(t)) {
|
||||
// ProfiledType pt = definitions.getConstraints().get(t);
|
||||
// choicerow.getCells().add(gen.new Cell(null, null, e.getName().replace("[x]", Utilities.capitalize(pt.getBaseType())), definitions.getTypes().containsKey(t) ? definitions.getTypes().get(t).getDefinition() : null, null));
|
||||
// choicerow.getCells().add(gen.new Cell());
|
||||
// choicerow.getCells().add(gen.new Cell(null, null, "", null, null));
|
||||
// choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE);
|
||||
// choicerow.getCells().add(gen.new Cell(null, definitions.getSrcFile(t)+".html#"+t.replace("*", "open"), t, null, null));
|
||||
Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null);
|
||||
choicerow.getCells().add(c);
|
||||
if (isMustSupport(tr) && element.getMustSupport()) {
|
||||
c.addPiece(gen.new Piece(null, " ", null));
|
||||
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
|
||||
}
|
||||
} else {
|
||||
choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null));
|
||||
choicerow.getCells().add(gen.new Cell());
|
||||
choicerow.getCells().add(gen.new Cell(null, null, "", null, null));
|
||||
choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE);
|
||||
choicerow.getCells().add(gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null));
|
||||
Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null);
|
||||
choicerow.getCells().add(c);
|
||||
if (isMustSupport(tr) && element.getMustSupport()) {
|
||||
c.addPiece(gen.new Piece(null, " ", null));
|
||||
c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
|
||||
}
|
||||
}
|
||||
if (tr.hasProfile()) {
|
||||
Cell typeCell = choicerow.getCells().get(3);
|
||||
|
@ -3982,6 +4010,10 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null));
|
||||
else
|
||||
typeCell.addPiece(gen.new Piece(psd.getUserString("path"), psd.getName(), psd.present()));
|
||||
if (isMustSupport(pt) && element.getMustSupport()) {
|
||||
typeCell.addPiece(gen.new Piece(null, " ", null));
|
||||
typeCell.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false);
|
||||
}
|
||||
|
||||
}
|
||||
typeCell.addPiece(gen.new Piece(null, ")", null));
|
||||
|
@ -6177,6 +6209,32 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
return grp;
|
||||
}
|
||||
|
||||
public static boolean isMustSupportDirect(TypeRefComponent tr) {
|
||||
return ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT)));
|
||||
}
|
||||
|
||||
public static boolean isMustSupport(TypeRefComponent tr) {
|
||||
if ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))) {
|
||||
return true;
|
||||
}
|
||||
if (isMustSupport(tr.getProfile())) {
|
||||
return true;
|
||||
}
|
||||
return isMustSupport(tr.getTargetProfile());
|
||||
}
|
||||
|
||||
public static boolean isMustSupport(List<CanonicalType> profiles) {
|
||||
for (CanonicalType ct : profiles) {
|
||||
if (isMustSupport(ct)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isMustSupport(CanonicalType profile) {
|
||||
return "true".equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_MUST_SUPPORT));
|
||||
}
|
||||
|
||||
}
|
|
@ -180,6 +180,7 @@ public class ToolingExtensions {
|
|||
public static final String EXT_OLD_CONCEPTMAP_EQUIVALENCE = "http://hl7.org/fhir/1.0/StructureDefinition/extension-ConceptMap.element.target.equivalence";
|
||||
public static final String EXT_EXP_FRAGMENT = "http://hl7.org/fhir/tools/StructureDefinition/expansion-codesystem-fragment";
|
||||
public static final String EXT_EXP_TOOCOSTLY = "http://hl7.org/fhir/StructureDefinition/valueset-toocostly";
|
||||
public static final String EXT_MUST_SUPPORT = "http://hl7.org/fhir/StructureDefinition/elementdefinition-type-must-support";
|
||||
|
||||
// specific extension helpers
|
||||
|
||||
|
@ -335,6 +336,8 @@ public class ToolingExtensions {
|
|||
return ((DecimalType) ex.getValue()).asStringValue();
|
||||
if ((ex.getValue() instanceof MarkdownType))
|
||||
return ((MarkdownType) ex.getValue()).getValue();
|
||||
if ((ex.getValue() instanceof PrimitiveType))
|
||||
return ((PrimitiveType) ex.getValue()).primitiveValue();
|
||||
if (!(ex.getValue() instanceof StringType))
|
||||
return null;
|
||||
return ((StringType) ex.getValue()).getValue();
|
||||
|
|
|
@ -341,6 +341,8 @@ public class I18nConstants {
|
|||
public static final String RESOURCE_TYPE_MISMATCH_FOR___ = "Resource_type_mismatch_for___";
|
||||
public static final String SAME_ID_ON_MULTIPLE_ELEMENTS__IN_ = "Same_id_on_multiple_elements__in_";
|
||||
public static final String SD_MUST_HAVE_DERIVATION = "SD_MUST_HAVE_DERIVATION";
|
||||
public static final String SD_NESTED_MUST_SUPPORT_DIFF = "SD_NESTED_MUST_SUPPORT_DIFF";
|
||||
public static final String SD_NESTED_MUST_SUPPORT_SNAPSHOT = "SD_NESTED_MUST_SUPPORT_SNAPSHOT";
|
||||
public static final String SEARCHPARAMETER_BASE_WRONG = "SEARCHPARAMETER_BASE_WRONG";
|
||||
public static final String SEARCHPARAMETER_EXP_WRONG = "SEARCHPARAMETER_EXP_WRONG";
|
||||
public static final String SEARCHPARAMETER_NOTFOUND = "SEARCHPARAMETER_NOTFOUND";
|
||||
|
|
|
@ -384,12 +384,12 @@ public class Turtle {
|
|||
|
||||
public String asHtml() throws Exception {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<pre class=\"rdf\">\r\n");
|
||||
b.append("<pre class=\"rdf\"><code class=\"language-turtle\">\r\n");
|
||||
commitPrefixes(b);
|
||||
for (Section s : sections) {
|
||||
commitSection(b, s);
|
||||
}
|
||||
b.append("</pre>\r\n");
|
||||
b.append("</code></pre>\r\n");
|
||||
b.append("\r\n");
|
||||
return b.toString();
|
||||
}
|
||||
|
|
|
@ -609,3 +609,6 @@ TYPE_SPECIFIC_CHECKS_DT_QTY_NO_ANNOTATIONS = UCUM Codes that contain human reada
|
|||
XHTML_XHTML_ELEMENT_ILLEGAL_IN_PARA = Illegal element name inside in a paragraph in the XHTML (''{0}'')
|
||||
UNSUPPORTED_IDENTIFIER_PATTERN_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE = Unsupported property {3} on type {2} for pattern for discriminator({0}) for slice {1}
|
||||
UNSUPPORTED_IDENTIFIER_PATTERN_NO_PROPERTY_NOT_SUPPORTED_FOR_DISCRIMINATOR_FOR_SLICE = Unsupported: no properties with values found on type {2} for pattern for discriminator({0}) for slice {1}
|
||||
SD_NESTED_MUST_SUPPORT_DIFF = The element {0} has types/profiles/targets that are marked as must support, but the element itself is not marked as must-support. The inner must-supports will be ignored unless the element inherits must-support = true
|
||||
SD_NESTED_MUST_SUPPORT_SNAPSHOT = The element {0} has types/profiles/targets that are marked as must support, but the element itself is not marked as must-support
|
||||
|
|
@ -296,9 +296,10 @@ public class BaseValidator {
|
|||
* Set this parameter to <code>false</code> if the validation does not pass
|
||||
* @return Returns <code>thePass</code> (in other words, returns <code>true</code> if the rule did not fail validation)
|
||||
*/
|
||||
protected boolean hint(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) {
|
||||
protected boolean hint(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
|
||||
if (!thePass) {
|
||||
addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.INFORMATION, null);
|
||||
String message = context.formatMessage(theMessage, theMessageArguments);
|
||||
addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.INFORMATION, null);
|
||||
}
|
||||
return thePass;
|
||||
}
|
||||
|
|
|
@ -483,7 +483,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
|
||||
private boolean isKnownExtension(String url) {
|
||||
// Added structuredefinition-expression and following extensions explicitly because they weren't defined in the version of the spec they need to be used with
|
||||
if ((allowExamples && (url.contains("example.org") || url.contains("acme.com"))) || url.contains("nema.org") || url.startsWith("http://hl7.org/fhir/tools/StructureDefinition/") || url.equals("http://hl7.org/fhir/StructureDefinition/structuredefinition-expression") || url.equals(VersionConvertorConstants.IG_DEPENDSON_PACKAGE_EXTENSION))
|
||||
if ((allowExamples && (url.contains("example.org") || url.contains("acme.com"))) || url.contains("nema.org") || url.startsWith("http://hl7.org/fhir/tools/StructureDefinition/") || url.equals("http://hl7.org/fhir/StructureDefinition/structuredefinition-expression"))
|
||||
return true;
|
||||
for (String s : extensionDomains)
|
||||
if (url.startsWith(s))
|
||||
|
@ -1521,6 +1521,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (extensionUrl.equals(profile.getUrl())) {
|
||||
rule(errors, IssueType.INVALID, element.line(), element.col(), path + "[url='" + url + "']", hasExtensionSlice(profile, url), I18nConstants.EXTENSION_EXT_SUBEXTENSION_INVALID, url, profile.getUrl());
|
||||
}
|
||||
} else if (SpecialExtensions.isKnownExtension(url)) {
|
||||
ex = SpecialExtensions.getDefinition(url);
|
||||
} else if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, allowUnknownExtension(url), I18nConstants.EXTENSION_EXT_UNKNOWN_NOTHERE, url)) {
|
||||
hint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, isKnownExtension(url), I18nConstants.EXTENSION_EXT_UNKNOWN, url);
|
||||
}
|
||||
|
@ -1556,6 +1558,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return ex;
|
||||
}
|
||||
|
||||
|
||||
private boolean hasExtensionSlice(StructureDefinition profile, String sliceName) {
|
||||
for (ElementDefinition ed : profile.getSnapshot().getElement()) {
|
||||
if (ed.getPath().equals("Extension.extension.url") && ed.hasFixed() && sliceName.equals(ed.getFixed().primitiveValue())) {
|
||||
|
@ -1933,7 +1936,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (fetcher != null) {
|
||||
boolean found;
|
||||
try {
|
||||
found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) || (url.startsWith("http://hl7.org/fhir/tools")) || fetcher.resolveURL(appContext, path, url);
|
||||
found = isDefinitionURL(url) || (allowExamples && (url.contains("example.org") || url.contains("acme.com")) || url.contains("acme.org")) || (url.startsWith("http://hl7.org/fhir/tools")) || fetcher.resolveURL(appContext, path, url) ||
|
||||
SpecialExtensions.isKnownExtension(url);
|
||||
} catch (IOException e1) {
|
||||
found = false;
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -28,6 +28,7 @@ import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
|
|||
import org.hl7.fhir.r5.model.SearchParameter;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||
|
@ -95,6 +96,69 @@ public class StructureDefinitionValidator extends BaseValidator {
|
|||
} catch (FHIRException | IOException e) {
|
||||
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), false, I18nConstants.ERROR_GENERATING_SNAPSHOT, e.getMessage());
|
||||
}
|
||||
List<Element> differentials = src.getChildrenByName("differential");
|
||||
List<Element> snapshots = src.getChildrenByName("snapshot");
|
||||
for (Element differential : differentials) {
|
||||
validateElementList(errors, differential, stack.push(differential, -1, null, null), false, snapshots.size() > 0);
|
||||
}
|
||||
for (Element snapshot : snapshots) {
|
||||
validateElementList(errors, snapshot, stack.push(snapshot, -1, null, null), true, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateElementList(List<ValidationMessage> errors, Element elementList, NodeStack stack, boolean snapshot, boolean hasSnapshot) {
|
||||
List<Element> elements = elementList.getChildrenByName("element");
|
||||
int cc = 0;
|
||||
for (Element element : elements) {
|
||||
validateElementDefinition(errors, element, stack.push(element, cc, null, null), snapshot, hasSnapshot);
|
||||
cc++;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateElementDefinition(List<ValidationMessage> errors, Element element, NodeStack stack, boolean snapshot, boolean hasSnapshot) {
|
||||
boolean typeMustSupport = false;
|
||||
List<Element> types = element.getChildrenByName("type");
|
||||
for (Element type : types) {
|
||||
if (hasMustSupportExtension(type)) {
|
||||
typeMustSupport = true;
|
||||
}
|
||||
}
|
||||
if (typeMustSupport) {
|
||||
if (snapshot) {
|
||||
rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_SNAPSHOT, element.getNamedChildValue("path"));
|
||||
} else {
|
||||
hint(errors, IssueType.EXCEPTION, stack.getLiteralPath(), hasSnapshot || "true".equals(element.getChildValue("mustSupport")), I18nConstants.SD_NESTED_MUST_SUPPORT_DIFF, element.getNamedChildValue("path"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasMustSupportExtension(Element type) {
|
||||
if ("true".equals(getExtensionValue(type, ToolingExtensions.EXT_MUST_SUPPORT))) {
|
||||
return true;
|
||||
}
|
||||
List<Element> profiles = type.getChildrenByName("profile");
|
||||
for (Element profile : profiles) {
|
||||
if ("true".equals(getExtensionValue(profile, ToolingExtensions.EXT_MUST_SUPPORT))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
profiles = type.getChildrenByName("targetProfile");
|
||||
for (Element profile : profiles) {
|
||||
if ("true".equals(getExtensionValue(profile, ToolingExtensions.EXT_MUST_SUPPORT))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getExtensionValue(Element element, String url) {
|
||||
List<Element> extensions = element.getChildrenByName("extension");
|
||||
for (Element extension : extensions) {
|
||||
if (url.equals(extension.getNamedChildValue("url"))) {
|
||||
return extension.getNamedChildValue("value");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private StructureDefinition loadAsSD(Element src) throws FHIRException, IOException {
|
||||
|
|
Loading…
Reference in New Issue