From 04ec134224a2a481d8ce3845bd63a480fbf0150c Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 21 Nov 2024 22:57:03 +1100 Subject: [PATCH 1/7] more support for canonical logical models --- .../igtools/publisher/FetchedResource.java | 13 + .../publisher/IGKnowledgeProvider.java | 13 +- .../hl7/fhir/igtools/publisher/Publisher.java | 231 +++++++++++++++++- 3 files changed, 255 insertions(+), 2 deletions(-) diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/FetchedResource.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/FetchedResource.java index 5807416fd..3ab2028c1 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/FetchedResource.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/FetchedResource.java @@ -25,10 +25,12 @@ import java.util.HashSet; import java.util.List; +import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.model.ImplementationGuide.ImplementationGuideDefinitionResourceComponent; import org.hl7.fhir.r5.utils.UserDataNames; import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.utilities.json.model.JsonObject; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -370,6 +372,17 @@ public boolean isCustomResource() { return getElement().getProperty().getStructure().hasUserData(UserDataNames.loader_custom_resource); } } + + public boolean isCanonical(IWorkerContext context) { + StructureDefinition sd = getElement().getProperty().getStructure(); + while (sd != null) { + if ("CanonicalResource".equals(sd.getType())) { + return true; + } + sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + } + return false; + } } diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/IGKnowledgeProvider.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/IGKnowledgeProvider.java index a4c1b1fd6..cc5023125 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/IGKnowledgeProvider.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/IGKnowledgeProvider.java @@ -399,7 +399,18 @@ public String getSourceFor(String ref) { public void findConfiguration(FetchedFile f, FetchedResource r) { if (template != null) { JsonObject cfg = null; - if (r.isExample()) { + if (r.isCanonical(context)) { + if (r.isExample()) { + cfg = defaultConfig.getJsonObject("example:canonical"); + } + if (cfg == null) { + cfg = defaultConfig.getJsonObject(r.fhirType()+":canonical"); + } + if (cfg == null) { + cfg = defaultConfig.getJsonObject("Any:canonical"); + } + } + if (cfg == null && r.isExample()) { cfg = defaultConfig.getJsonObject("example"); } if (cfg == null && r.fhirType().equals("StructureDefinition")) { diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/Publisher.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/Publisher.java index 89a54e30f..1d1c45aaa 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/Publisher.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/Publisher.java @@ -9212,6 +9212,8 @@ private void generateSummaryOutputs(DBBuilder db) throws Exception { } if (r.getResource() != null) { populateResourceEntry(r, item, null); + } else if (r.isCustomResource()) { + populateCustomResourceEntry(r, item, null); } JsonArray contained = null; // contained resources get added twice - once as sub-entries under the resource that contains them, and once as an entry in their own right, for their own rendering @@ -9272,7 +9274,233 @@ private void generateSummaryOutputs(DBBuilder db) throws Exception { json = org.hl7.fhir.utilities.json.parser.JsonParser.compose(data, true); TextFile.stringToFile(json, Utilities.path(tempDir, "_data", "languages.json")); - + } + + private void populateCustomResourceEntry(FetchedResource r, JsonObject item, Object object) { + Element e = r.getElement(); +// item.add("layout-type", "canonical"); + if (e.getChildren("url").size() == 1) { + item.add("url", e.getNamedChildValue("url")); + } + if (e.hasChildren("identifier")) { + List ids = new ArrayList(); + for (Element id : e.getChildren("identifier")) { + if (id.hasChild("value")) { + ids.add(dr.displayDataType(ResourceWrapper.forType(cu, id))); + } + } + if (!ids.isEmpty()) { + item.add("identifiers", String.join(", ", ids)); + } + } + if (e.getChildren("version").size() == 1) { + item.add("version", e.getNamedChildValue("version")); + } + if (e.getChildren("name").size() == 1) { + item.add("name", e.getNamedChildValue("name")); + } + if (e.getChildren("title").size() == 1) { + item.add("title", e.getNamedChildValue("title")); +// addTranslationsToJson(item, "title", e.getNamedChild("title"), false); + } + if (e.getChildren("experimental").size() == 1) { + item.add("experimental", e.getNamedChildValue("experimental")); + } + if (e.getChildren("date").size() == 1) { + item.add("date", e.getNamedChildValue("date")); + } + if (e.getChildren("description").size() == 1) { + item.add("description", ProfileUtilities.processRelativeUrls(e.getNamedChildValue("description"), "", igpkp.specPath(), context.getResourceNames(), specMaps.get(0).listTargets(), pageTargets(), false)); +// addTranslationsToJson(item, "description", e.getNamedChild("description"), false); + } + +// if (cr.hasUseContext() && !containedCr) { +// List contexts = new ArrayList(); +// for (UsageContext uc : cr.getUseContext()) { +// String label = dr.displayDataType(uc.getCode()); +// if (uc.hasValueCodeableConcept()) { +// String value = dr.displayDataType(uc.getValueCodeableConcept()); +// if (value!=null) { +// contexts.add(label + ":\u00A0" + value); +// } +// } else if (uc.hasValueQuantity()) { +// String value = dr.displayDataType(uc.getValueQuantity()); +// if (value!=null) +// contexts.add(label + ":\u00A0" + value); +// } else if (uc.hasValueRange()) { +// String value = dr.displayDataType(uc.getValueRange()); +// if (!value.isEmpty()) +// contexts.add(label + ":\u00A0" + value); +// +// } else if (uc.hasValueReference()) { +// String value = null; +// String reference = null; +// if (uc.getValueReference().hasReference()) { +// reference = uc.getValueReference().getReference().contains(":") ? "" : igpkp.getCanonical() + "/"; +// reference += uc.getValueReference().getReference(); +// } +// if (uc.getValueReference().hasDisplay()) { +// if (reference != null) +// value = "[" + uc.getValueReference().getDisplay() + "](" + reference + ")"; +// else +// value = uc.getValueReference().getDisplay(); +// } else if (reference!=null) +// value = "[" + uc.getValueReference().getReference() + "](" + reference + ")"; +// else if (uc.getValueReference().hasIdentifier()) { +// String idLabel = dr.displayDataType(uc.getValueReference().getIdentifier().getType()); +// value = idLabel!=null ? label + ":\u00A0" + uc.getValueReference().getIdentifier().getValue() : uc.getValueReference().getIdentifier().getValue(); +// } +// if (value != null) +// contexts.add(value); +// } else if (uc.hasValue()) { +// throw new FHIRException("Unsupported type for UsageContext.value - " + uc.getValue().fhirType()); +// } +// } +// if (!contexts.isEmpty()) +// item.add("contexts", String.join(", ", contexts)); +// } +// if (cr.hasJurisdiction() && !containedCr) { +// File flagDir = new File(tempDir + "/assets/images"); +// if (!flagDir.exists()) +// flagDir.mkdirs(); +// JsonArray jNodes = new JsonArray(); +// item.add("jurisdictions", jNodes); +// ValueSet jvs = context.fetchResource(ValueSet.class, "http://hl7.org/fhir/ValueSet/jurisdiction"); +// for (CodeableConcept cc : cr.getJurisdiction()) { +// JsonObject jNode = new JsonObject(); +// jNodes.add(jNode); +// ValidationResult vr = jvs==null ? null : context.validateCode(new ValidationOptions(FhirPublication.R5, "en-US"), cc, jvs); +// if (vr != null && vr.asCoding()!=null) { +// Coding cd = vr.asCoding(); +// jNode.add("code", cd.getCode()); +// if (cd.getSystem().equals("http://unstats.un.org/unsd/methods/m49/m49.htm") && cd.getCode().equals("001")) { +// jNode.add("name", "International"); +// jNode.add("flag", "001"); +// } else if (cd.getSystem().equals("urn:iso:std:iso:3166")) { +// String code = translateCountryCode(cd.getCode()).toLowerCase(); +// jNode.add("name", displayForCountryCode(cd.getCode())); +// File flagFile = new File(vsCache + "/" + code + ".svg"); +// if (!flagFile.exists() && !ignoreFlags.contains(code)) { +// URL url2 = new URL("https://flagcdn.com/" + shortCountryCode.get(code.toUpperCase()).toLowerCase() + ".svg"); +// try { +// InputStream in = url2.openStream(); +// Files.copy(in, Paths.get(flagFile.getAbsolutePath())); +// } catch (Exception e2) { +// ignoreFlags.add(code); +// System.out.println("Unable to access " + url2 + " or " + url2+" ("+e2.getMessage()+")"); +// } +// } +// if (flagFile.exists()) { +// FileUtils.copyFileToDirectory(flagFile, flagDir); +// jNode.add("flag", code); +// } +// } else if (cd.getSystem().equals("urn:iso:std:iso:3166:-2")) { +// String code = cd.getCode(); +// String[] codeParts = cd.getCode().split("-"); +// jNode.add("name", displayForStateCode(cd.getCode()) + " (" + displayForCountryCode(codeParts[0]) + ")"); +// File flagFile = new File(vsCache + "/" + code + ".svg"); +// if (!flagFile.exists()) { +// URL url = new URL("http://flags.ox3.in/svg/" + codeParts[0].toLowerCase() + "/" + codeParts[1].toLowerCase() + ".svg"); +// try (InputStream in = url.openStream()) { +// Files.copy(in, Paths.get(flagFile.getAbsolutePath())); +// } catch (Exception e) { +// // If we can't find the file, that's ok. +// } +// } +// if (flagFile.exists()) { +// FileUtils.copyFileToDirectory(flagFile, flagDir); +// jNode.add("flag", code); +// } +// } +// } else { +// jNode.add("name", dr.displayDataType(cc)); +// } +// } +// } + + if (e.getChildren("purpose").size() == 1) { + item.add("purpose", ProfileUtilities.processRelativeUrls(e.getNamedChildValue("purpose"), "", igpkp.specPath(), context.getResourceNames(), specMaps.get(0).listTargets(), pageTargets(), false)); +// addTranslationsToJson(item, "purpose", e.getNamedChild("purpose"), false); + } + if (e.getChildren("status").size() == 1) { + item.add("status", e.getNamedChildValue("status")); + } + if (e.getChildren("copyright").size() == 1) { + item.add("copyright", ProfileUtilities.processRelativeUrls(e.getNamedChildValue("copyright"), "", igpkp.specPath(), context.getResourceNames(), specMaps.get(0).listTargets(), pageTargets(), false)); +// addTranslationsToJson(item, "description", e.getNamedChild("description"), false); + } + +// if (pcr!=null && pcr.hasExtension(ToolingExtensions.EXT_FMM_LEVEL)) { +// IntegerType fmm = pcr.getExtensionByUrl(ToolingExtensions.EXT_FMM_LEVEL).getValueIntegerType(); +// item.add("fmm", fmm.asStringValue()); +// if (fmm.hasExtension(ToolingExtensions.EXT_FMM_DERIVED)) { +// String derivedFrom = "FMM derived from: "; +// for (Extension ext: fmm.getExtensionsByUrl(ToolingExtensions.EXT_FMM_DERIVED)) { +// derivedFrom += "\r\n" + ext.getValueCanonicalType().asStringValue(); +// } +// item.add("fmmSource", derivedFrom); +// } +// } +// List keywords = new ArrayList(); +// if (r.getResource() instanceof StructureDefinition) { +// StructureDefinition sd = (StructureDefinition)r.getResource(); +// if (sd.hasKeyword()) { +// for (Coding coding : sd.getKeyword()) { +// String value = dr.displayDataType(coding); +// if (value != null) +// keywords.add(value); +// } +// } +// } else if (r.getResource() instanceof CodeSystem) { +// CodeSystem cs = (CodeSystem)r.getResource(); +// for (Extension e : cs.getExtensionsByUrl(ToolingExtensions.EXT_CS_KEYWORD)) { +// keywords.add(e.getValueStringType().asStringValue()); +// } +// } else if (r.getResource() instanceof ValueSet) { +// ValueSet vs = (ValueSet)r.getResource(); +// for (Extension e : vs.getExtensionsByUrl(ToolingExtensions.EXT_VS_KEYWORD)) { +// keywords.add(e.getValueStringType().asStringValue()); +// } +// } +// if (!keywords.isEmpty()) +// item.add("keywords", String.join(", ", keywords)); +// +// + org.hl7.fhir.igtools.renderers.StatusRenderer.ResourceStatusInformation info = StatusRenderer.analyse(e); + JsonObject jo = new JsonObject(); + if (info.getColorClass() != null) { + jo.add("class", info.getColorClass()); + } + if (info.getOwner() != null) { + jo.add("owner", info.getOwner()); + } + if (info.getOwnerLink() != null) { + jo.add("link", info.getOwnerLink()); + } + if (info.getSstatus() != null) { + jo.add("standards-status", info.getSstatus()); + } else if (sourceIg.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { + jo.add("standards-status","informative"); + } + if (info.getSstatusSupport() != null) { + jo.add("standards-status-support", info.getSstatusSupport()); + } + if (info.getNormVersion() != null) { + item.add("normativeVersion", info.getNormVersion()); + } + if (info.getFmm() != null) { + jo.add("fmm", info.getFmm()); + } + if (info.getSstatusSupport() != null) { + jo.add("fmm-support", info.getFmmSupport()); + } + if (info.getStatus() != null && !jo.has("status")) { + jo.add("status", info.getStatus()); + } + if (!jo.getProperties().isEmpty()) { + item.set("status", jo); + } + } private void genBasePages() throws IOException, Exception { @@ -9556,6 +9784,7 @@ private List makeDependencies() { public void populateResourceEntry(FetchedResource r, JsonObject item, ContainedResourceDetails crd) throws Exception { if (r.getResource() instanceof CanonicalResource || (crd!= null && crd.getCanonical() != null)) { +// item.add("layout-type", "canonical"); boolean containedCr = crd != null && crd.getCanonical() != null; CanonicalResource cr = containedCr ? crd.getCanonical() : (CanonicalResource) r.getResource(); CanonicalResource pcr = r.getResource() instanceof CanonicalResource ? (CanonicalResource) r.getResource() : null; From b86df6f4f5152d2b16b92f80f2e9ba1efb2192c6 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 21 Nov 2024 22:57:22 +1100 Subject: [PATCH 2/7] support resolving /_history/ URLs in IG publisher --- .../org/hl7/fhir/igtools/publisher/ValidationServices.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/ValidationServices.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/ValidationServices.java index efae33cba..6602577fa 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/ValidationServices.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/ValidationServices.java @@ -107,6 +107,9 @@ public ValidationServices(IWorkerContext context, IGKnowledgeProvider ipg, Imple public Element fetch(IResourceValidator validator, Object appContext, String url) throws FHIRException, IOException { if (url == null) return null; + if (url.contains("/_history/")) { + url = url.substring(0, url.indexOf("/_history")); + } String turl = (!Utilities.isAbsoluteUrl(url)) ? Utilities.pathURL(ipg.getCanonical(), url) : url; Resource res = context.fetchResource(getResourceType(turl), turl); if (res != null) { From ac154eec1be1044b5958eca229b64c0497ada331 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 21 Nov 2024 22:57:39 +1100 Subject: [PATCH 3/7] Fix NPE building package.db --- .../hl7/fhir/igtools/renderers/DBBuilder.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/DBBuilder.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/DBBuilder.java index 0231ff767..b327f0601 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/DBBuilder.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/DBBuilder.java @@ -328,12 +328,12 @@ public void saveResource(FetchedFile f, FetchedResource r, byte[] json) { psql.setInt(3, r.getElement().getProperty().getStructure().hasUserData(UserDataNames.loader_custom_resource) ? 1 : 0); bindString(psql, 4, r.getId()); bindString(psql, 5, r.getElement().getWebPath()); - bindString(psql, 6, r.getElement().getNamedChildValue("url")); - bindString(psql, 7, r.getElement().getNamedChildValue("version")); - bindString(psql, 8, r.getElement().getNamedChildValue("status")); - bindString(psql, 9, r.getElement().getNamedChildValue("date")); - bindString(psql, 10, r.getElement().getChildren("name").size() == 1 && r.getElement().getNamedChild("name").isPrimitive() ? r.getElement().getNamedChildValue("name") : r.getResourceName()); - bindString(psql, 11, r.getElement().getNamedChildValue("title")); + bindString(psql, 6, getSingleChildValue(r, "url", null)); + bindString(psql, 7, getSingleChildValue(r, "version", null)); + bindString(psql, 8, getSingleChildValue(r, "status", null)); + bindString(psql, 9, getSingleChildValue(r, "date", null)); + bindString(psql, 10, getSingleChildValue(r, "name", r.getResourceName())); + bindString(psql, 11, getSingleChildValue(r, "title", null)); bindString(psql, 12, r.getResourceDescription()); psql.setBytes(13, json); psql.executeUpdate(); @@ -380,6 +380,10 @@ public void saveResource(FetchedFile f, FetchedResource r, byte[] json) { time(start); } + private String getSingleChildValue(FetchedResource r, String name, String defaultValue) { + return r.getElement().getChildren(name).size() == 1 && r.getElement().getNamedChild(name).isPrimitive() ? r.getElement().getNamedChildValue(name) : defaultValue; + } + public void finishResources() { long start = System.currentTimeMillis(); if (con == null) { From aff9523fc26f9fb754bf7496fc39f5cbb49eca8b Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 21 Nov 2024 22:57:55 +1100 Subject: [PATCH 4/7] i18n for HTA LOINC & SCT statements --- .../fhir/igtools/renderers/IPStatementsRenderer.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/IPStatementsRenderer.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/IPStatementsRenderer.java index bb5a7041e..9a5d1c504 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/IPStatementsRenderer.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/IPStatementsRenderer.java @@ -28,6 +28,7 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext.RenderingContextLangs; import org.hl7.fhir.utilities.MarkDownProcessor; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.xhtml.XhtmlComposer; import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.hl7.fhir.utilities.xhtml.XhtmlParser; @@ -216,14 +217,12 @@ private boolean isHL7Ig() { private String getCopyRightStatement(SystemUsage system) throws IOException { if ("http://snomed.info/sct".equals(system.system)) { - system.desc = "SNOMED Clinical Terms® (SNOMED CT®)"; - return "This material contains content that is copyright of SNOMED International. Implementers of these specifications must have the appropriate SNOMED CT Affiliate license - "+ - "for more information contact https://www.snomed.org/get-snomed or info@snomed.org."; + system.desc = ctxt.formatMessage(I18nConstants.HTA_SCT_DESC); + return ctxt.formatMessage(I18nConstants.HTA_SCT_MESSAGE); } if ("http://loinc.org".equals(system.system)) { - system.desc = "LOINC"; - return "This material contains content from LOINC. LOINC is copyright © 1995-2020, Regenstrief Institute, Inc. and the Logical Observation Identifiers Names and Codes (LOINC) "+ - "Committee and is available at no cost under the license. LOINC® is a registered United States trademark of Regenstrief Institute, Inc."; + system.desc = ctxt.formatMessage(I18nConstants.HTA_LOINC_DESC); + return ctxt.formatMessage(I18nConstants.HTA_LOINC_MESSAGE); } if (system.cs != null) { system.desc = system.cs.present(); From 41c4929b94bf7cdf7ba8db3e1609822bc9c0032d Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 21 Nov 2024 22:58:20 +1100 Subject: [PATCH 5/7] Fix bug in publication checker - space in sequence blows logic up --- .../java/org/hl7/fhir/igtools/renderers/PublicationChecker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/PublicationChecker.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/PublicationChecker.java index 0fb38e8f0..4452dc304 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/PublicationChecker.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/PublicationChecker.java @@ -181,7 +181,7 @@ private void checkPublicationRequest(List messages, NpmPackage npm, Pack summary.add(new StringPair("path", pr.asString("path"))); } if ("milestone".equals(pr.asString("mode"))) { - check(messages, pr.asString("path").equals(Utilities.pathURL(npm.canonical(), pr.asString("sequence"))) || pr.asString("path").equals(Utilities.pathURL(npm.canonical(), pr.asString("version"))), + check(messages, pr.asString("path").equals(Utilities.pathURL(npm.canonical(), pr.asString("sequence").replace(" ", ""))) || pr.asString("path").equals(Utilities.pathURL(npm.canonical(), pr.asString("version"))), "Proposed path for this milestone publication should usually be canonical with either sequence or version appended"+mkWarning()); if (pl != null) { for (PackageListEntry e : pl.list()) { From 92b95ab6fecd5af8af714969b43f56e62381ec90 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 21 Nov 2024 22:58:35 +1100 Subject: [PATCH 6/7] Support for custom resources --- .../igtools/renderers/StatusRenderer.java | 73 ++++++++++++++++++- pom.xml | 2 +- test-statistics.csv | 2 +- test-statistics.json | 7 ++ 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StatusRenderer.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StatusRenderer.java index a3d9c7214..f2a7c36e1 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StatusRenderer.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StatusRenderer.java @@ -2,6 +2,7 @@ import java.util.List; +import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.ContactDetail; import org.hl7.fhir.r5.model.ContactPoint; @@ -96,7 +97,23 @@ else if (fmm.hasExtension(ToolingExtensions.EXT_FMM_DERIVED)) { } } } - public void processSstatus(DomainResource resource) { + public void processFmm(Element resource) { + if (resource.hasExtension(ToolingExtensions.EXT_FMM_LEVEL)) { + setFmm(resource.getExtensionString(ToolingExtensions.EXT_FMM_LEVEL)); + Element fmm = resource.getExtension(ToolingExtensions.EXT_FMM_LEVEL).getNamedChild("value"); + if (fmm.hasExtension(ToolingExtensions.EXT_FMM_SUPPORT)) + setFmmSupport(fmm.getExtensionString(ToolingExtensions.EXT_FMM_SUPPORT)); + else if (fmm.hasExtension(ToolingExtensions.EXT_FMM_DERIVED)) { + List derivations = fmm.getExtensions(ToolingExtensions.EXT_FMM_DERIVED); + String s = "Inherited from "; + for (Element ex: derivations) { + s += ", " + ex.primitiveValue(); + } + setFmmSupport(s); + } + } + } + public void processSStatus(DomainResource resource) { if (ToolingExtensions.hasExtension(resource, ToolingExtensions.EXT_STANDARDS_STATUS)) { setSstatus(ToolingExtensions.readStringExtension(resource, ToolingExtensions.EXT_STANDARDS_STATUS)); StringType sstatus = resource.getExtensionByUrl(ToolingExtensions.EXT_STANDARDS_STATUS).getValueStringType(); @@ -112,6 +129,23 @@ else if (sstatus.hasExtension(ToolingExtensions.EXT_FMM_DERIVED)) { } } } + + public void processSStatus(Element resource) { + if (resource.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { + setSstatus(resource.getExtensionString(ToolingExtensions.EXT_STANDARDS_STATUS)); + Element sstatus = resource.getExtension(ToolingExtensions.EXT_STANDARDS_STATUS).getNamedChild("value"); + if (sstatus.hasExtension(ToolingExtensions.EXT_FMM_SUPPORT)) + setFmmSupport(sstatus.getExtensionString(ToolingExtensions.EXT_FMM_SUPPORT)); + else if (sstatus.hasExtension(ToolingExtensions.EXT_FMM_DERIVED)) { + List derivations = sstatus.getExtensions(ToolingExtensions.EXT_FMM_DERIVED); + String s = "Inherited from "; + for (Element ex: derivations) { + s += ", " + ex.primitiveValue(); + } + setFmmSupport(s); + } + } + } } public static ResourceStatusInformation analyse(DomainResource resource) { @@ -120,7 +154,19 @@ public static ResourceStatusInformation analyse(DomainResource resource) { info.setOwner(readOwner(resource)); info.setOwnerLink(readOwnerLink(resource)); info.setStatus(readStatus(resource)); - info.processSstatus(resource); + info.processSStatus(resource); + info.setNormVersion(readNormativeVersion(resource)); + info.setColorClass(getColor(info)); + return info; + } + + public static ResourceStatusInformation analyse(Element resource) { + ResourceStatusInformation info = new ResourceStatusInformation(); + info.processFmm(resource); + info.setOwner(readOwner(resource)); + info.setOwnerLink(readOwnerLink(resource)); + info.setStatus(readStatus(resource)); + info.processSStatus(resource); info.setNormVersion(readNormativeVersion(resource)); info.setColorClass(getColor(info)); return info; @@ -160,6 +206,10 @@ private static String readNormativeVersion(DomainResource resource) { return ToolingExtensions.readStringExtension(resource, ToolingExtensions.EXT_NORMATIVE_VERSION); } + private static String readNormativeVersion(Element resource) { + return resource.getExtensionString(ToolingExtensions.EXT_NORMATIVE_VERSION); + } + private static String readStatus(DomainResource resource) { if (resource instanceof CanonicalResource) { @@ -167,7 +217,10 @@ private static String readStatus(DomainResource resource) { } return null; } - + + private static String readStatus(Element resource) { + return resource.getNamedChildValue("status"); + } private static String readOwnerLink(DomainResource resource) { if (resource instanceof CanonicalResource) { @@ -182,6 +235,16 @@ private static String readOwnerLink(DomainResource resource) { return null; } + private static String readOwnerLink(Element resource) { + for (Element cd : resource.getChildren("contact")) { + for (Element cp : cd.getChildren("telecom")) { + if ("url".equals(cp.getNamedChildValue("system"))) { + return cp.getNamedChildValue("value"); + } + } + } + return null; + } private static String readOwner(DomainResource resource) { if (resource instanceof CanonicalResource) { @@ -190,6 +253,10 @@ private static String readOwner(DomainResource resource) { return null; } + private static String readOwner(Element resource) { + return resource.hasChild("publisher") ? resource.getNamedChildValue("publisher") : null; + } + public static String render(String src, ResourceStatusInformation info, RenderingContext rc) { StringBuilder b = new StringBuilder(); diff --git a/pom.xml b/pom.xml index 898b5246e..47415df4d 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ pom - 6.4.2 + 6.4.3-SNAPSHOT 3.0.0-M5 5.2.1 1.18.32 diff --git a/test-statistics.csv b/test-statistics.csv index 8782ac7ca..9b2e25065 100644 --- a/test-statistics.csv +++ b/test-statistics.csv @@ -36,4 +36,4 @@ Version,example.fhir.uv.myig,fhir.base.template.ig,hl7.base.template.ig,hl7.cda. 1.6.31,74408,934,88,116831,302345,1085,1563643,925565,613025,42689,151744,864504,634988,81602,234197 1.7.0,67385,947,87,116042,276551,773,1291011,711790,615710,26255,93022,569245,570301,57877,215056 1.7.2,85673,1922,93,118751,265472,1380,1681712,1072974,742736,33289,122122,753126,701645,79859,280102 -1.7.3,65779,879,80,114030,281590,594,1399770,767803,,24190,102435,634954,621179,60254,231856 +1.7.3,65779,879,80,114030,281590,594,1399770,767803,638217,24190,102435,634954,621179,60254,231856 diff --git a/test-statistics.json b/test-statistics.json index 1764b1490..3cdf84c08 100644 --- a/test-statistics.json +++ b/test-statistics.json @@ -4014,6 +4014,13 @@ "hints" : 3, "time" : 1399770, "memory" : 14258066952 + }, + "hl7.fhir.uv.extensions" : { + "errors" : 1079, + "warnings" : 822, + "hints" : 1612, + "time" : 638217, + "memory" : 6997330912 } } } From 57fe2a9449742d9b32641bc74b1f92dd05d5dec4 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 21 Nov 2024 23:12:00 +1100 Subject: [PATCH 7/7] release notes --- RELEASE_NOTES.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..14bdfdf8d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,15 @@ +* Security: Enforce that XML can't load XML entity declarations +* Loader: Fix missing isModifierReason on modifier extensions +* Version Convertor: fix bug converting NamingSystem.url between versions +* Version Convertor: Fix IG dependsOn.reason conversion +* Validator: fix value set validation on import validation to find external value sets +* Validator: Fix terminology tester for change to language header +* Validator: Adjust wording of R5 slicing check +* Validator: Sort entries in error message about profiles to make the order reproducible +* Validator: support resolving /_history/ URLs in IG publisher +* Renderer: make HTA messages translatable +* Renderer: new release - pubpack +* Renderer: suppress Json resourceType property in some logical models +* Renderer: more support for canonical logical models +* SQL: Fix NPE building package.db +* Go-Publish: Fix bug in publication checker - space in sequence blows logic up