diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9af6931ee..766fa5549 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,17 +1,13 @@ -* TxClient: Remove "profile" from tx operations -* Validator: Validate contextInvariant in extension definitions -* Validator: Fix Typo in TI WG name -* Validator: Handle unknown constants properly in FHIRPath -* Validator: Fix handling of type ancestors at the root of FHIRPath expressions -* Validator: CDA templates with no extension value use urn:oid: not urn:hl7ii: -* Validator: Allow URL as a type of string in FHIRPath type checking -* Validator: Fix semver validation -* Validator: Fix problem resolving context in CDA invariants -* Validator: Fix for FHIRPath constant handling -* Renderer: SQL in FHIR Implementation of ViewDefinitions available as beta -* Renderer: Fixes to Search Parameter rendering of multiples per FHIR-I decision -* Renderer: Fix broken links in extension references done by [[[]]] -* Renderer: Fix broken links in code system rendering of parents -* Renderer: Support using names in [[[markdown]]] when rendering -* Renderer: Fix [[[ and ]]] in markdown processing, and allow names -* Test Cases: Add CDA to test IGs \ No newline at end of file +* General: Corrected spelling of 'supercedes' to 'supersedes' in IG… +* Snapshot Generation: Support suppress examples when generating snapshots +* Validator: Validate Vital signs Profiles when validating observations +* Validator: Hack around problem with vs-1 constraint in R4 +* Validator: Check for retired status when multiple OID matches exist +* Validator: Fix for validating extensions on R5 resources in R4 (R4 special case) +* Validator: Minor fixes for standalone ViewDefinition validator +* Renderer: Revised Capability Statement rendering (Thanks Vassil Peytchev) +* Renderer: Fix bug rendering primitive types with an extension that provides a value alternative +* Renderer: Add clickable links for references when rendering json and xml instances in IG publisher +* Renderer: Fix bug generating profile spreadsheets +* Cross-Version: Handle SubscriptionTopic in cross-version analysis +* Internal QA: track memory during IG tests 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 841cff129..ccdaf5bcb 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 @@ -77,8 +77,9 @@ public class IGKnowledgeProvider implements ProfileKnowledgeProvider, ParserBase private Set summaryRows = new HashSet<>(); private String altCanonical; private XVerExtensionManager xver; + private List files; - public IGKnowledgeProvider(IWorkerContext context, String pathToSpec, String canonical, JsonObject igs, List errors, boolean noXhtml, Template template, List listedURLExemptions, String altCanonical) throws Exception { + public IGKnowledgeProvider(IWorkerContext context, String pathToSpec, String canonical, JsonObject igs, List errors, boolean noXhtml, Template template, List listedURLExemptions, String altCanonical, List files) throws Exception { super(); this.context = context; this.pathToSpec = pathToSpec; @@ -90,6 +91,7 @@ public IGKnowledgeProvider(IWorkerContext context, String pathToSpec, String can this.template = template; this.listedURLExemptions = listedURLExemptions; this.altCanonical = altCanonical; + this.files = files; if (igs != null) { loadPaths(igs); } @@ -760,5 +762,30 @@ public Set summaryRows() { return summaryRows ; } + @Override + public String resolveReference(String ref) { + if (ref == null) { + return null; + } + Resource res = context.fetchResource(Resource.class, ref); + if (res != null && res.hasWebPath()) { + return res.getWebPath(); + } + if (ref.startsWith(canonical)) { + ref = Utilities.getRelativeUrlPath(canonical, ref); + } + String[] p = ref.split("/"); + if (p.length == 2 && files != null) { + for (FetchedFile f : files) { + for (FetchedResource r : f.getResources()) { + if (p[0].equals(r.fhirType()) && p[1].equals(r.getId())) { + return getLinkFor(r, true); + } + } + } + } + return null; + } + } 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 0530a4685..203385434 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 @@ -3016,7 +3016,7 @@ else if (vsCache == null) { checkTSVersion(vsCache, context.connectToTSServer(TerminologyClientFactory.makeClient("Tx-Server", webTxServer.getAddress(), "fhir/publisher", FhirPublication.fromCode(version)), txLog)); loadPubPack(); - igpkp = new IGKnowledgeProvider(context, checkAppendSlash(specPath), determineCanonical(sourceIg.getUrl(), "ImplementationGuide.url"), template.config(), errors, VersionUtilities.isR2Ver(version), template, listedURLExemptions, altCanonical); + igpkp = new IGKnowledgeProvider(context, checkAppendSlash(specPath), determineCanonical(sourceIg.getUrl(), "ImplementationGuide.url"), template.config(), errors, VersionUtilities.isR2Ver(version), template, listedURLExemptions, altCanonical, fileList); if (autoLoad) { igpkp.setAutoPath(true); } @@ -3522,7 +3522,7 @@ else if (mode == IGBuildMode.AUTOBUILD) loadPubPack(); - igpkp = new IGKnowledgeProvider(context, checkAppendSlash(specPath), cb.asString(), configuration, errors, VersionUtilities.isR2Ver(version), null, listedURLExemptions, altCanonical); + igpkp = new IGKnowledgeProvider(context, checkAppendSlash(specPath), cb.asString(), configuration, errors, VersionUtilities.isR2Ver(version), null, listedURLExemptions, altCanonical, fileList); igpkp.loadSpecPaths(specMaps.get(0)); fetcher.setPkp(igpkp); diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/R4ToR4BAnalyser.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/R4ToR4BAnalyser.java index 58d07f577..aeb3835e7 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/R4ToR4BAnalyser.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/R4ToR4BAnalyser.java @@ -11,6 +11,8 @@ import java.util.Map; import java.util.Map.Entry; +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_43_50; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.igtools.publisher.loaders.PublisherLoader; import org.hl7.fhir.r4b.model.Bundle; @@ -80,7 +82,7 @@ public String present() { private static final List R4BOnlyTypes = Collections.unmodifiableList( Arrays.asList(new String[] {"CodeableReference", "RatioRange", "NutritionProduct", "AdministrableProductDefinition", "ClinicalUseDefinition", "PackagedProductDefinition", "ManufacturedItemDefinition", "RegulatedAuthorization", - "MedicinalProductDefinition", "Ingredient", "SubstanceDefinition", "Citation", "EvidenceReport", "SubscriptionStatus", "SubscriptionTopic"})); + "MedicinalProductDefinition", "Ingredient", "SubstanceDefinition", "Citation", "EvidenceReport", "SubscriptionStatus"/*, "SubscriptionTopic"*/})); private static final List R4OnlyTypes = Collections.unmodifiableList( Arrays.asList(new String[] {"MedicinalProduct", "MedicinalProductIngredient", "SubstanceSpecification", "MedicinalProductAuthorization", @@ -269,17 +271,40 @@ public boolean canBeR4B() { public String generate(String pid, boolean inline) { if (VersionUtilities.isR4Ver(context.getVersion())) { - return gen(pid, "R4", "R4B", r4BOK, r4Problems, r4BProblems, r4Exemptions, r4BExemptions, inline); + return gen(pid, "R4", "R4B", r4OK, r4BOK, r4Problems, r4BProblems, r4Exemptions, r4BExemptions, inline); } else if (VersionUtilities.isR4BVer(context.getVersion())) { - return gen(pid, "R4B", "R4", r4OK, r4BProblems, r4Problems, r4BExemptions, r4Exemptions, inline); + return gen(pid, "R4B", "R4", r4BOK, r4OK, r4BProblems, r4Problems, r4BExemptions, r4Exemptions, inline); } else { return ""; } } - private String gen(String pid, String src, String dst, boolean dstOk, List srcProblems, List dstProblems, Map srcExempt, Map dstExempt, boolean inline) { + private String gen(String pid, String src, String dst, boolean srcOk, boolean dstOk, List srcProblems, List dstProblems, Map srcExempt, Map dstExempt, boolean inline) { StringBuilder b = new StringBuilder(); - if (dstOk) { + if (!srcOk) { + if (!inline) { + b.append("

"); + } + b.append("Something went wrong with the cross-version analysis because: \r\n"); + if (!inline) { + b.append("

\r\n"); + b.append("
    \r\n"); + } + boolean first = true; + for (String s : srcProblems) { + if (!inline) { + b.append("
  • "); + } + if (first) first = false; else if (inline) b.append(", "); + b.append(s); + if (!inline) { + b.append("
  • \r\n"); + } + } + if (!inline) { + b.append("
\r\n"); + } + } else if (dstOk) { if (!inline) { b.append("

"); } @@ -503,6 +528,11 @@ private void processFileOther(NPMPackageGenerator gen, String folder, String fil if (Utilities.existsInList(folder, "package", "example")) { if (!Utilities.existsInList(filename, "package.json", ".index.json", ".index.db")) { org.hl7.fhir.r4b.model.Resource res = new org.hl7.fhir.r4b.formats.JsonParser().parse(content); + if (VersionUtilities.isR4Ver(context.getVersion()) && "Basic".equals(res.fhirType())) { + org.hl7.fhir.r4.model.Resource r4 = new org.hl7.fhir.r4.formats.JsonParser().parse(content); + org.hl7.fhir.r5.model.Resource r5 = VersionConvertorFactory_40_50.convertResource(r4); + res = VersionConvertorFactory_43_50.convertResource(r5); + } boolean exempt = (exemptions.containsKey(res.fhirType()+"/"+res.getId()) || ((res instanceof org.hl7.fhir.r4b.model.CanonicalResource) && exemptions.containsKey(((org.hl7.fhir.r4b.model.CanonicalResource) res).getUrl()))); if (!exempt) { diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/SuppressedMessageInformation.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/SuppressedMessageInformation.java index 52d71739b..f37e3db20 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/SuppressedMessageInformation.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/SuppressedMessageInformation.java @@ -67,6 +67,10 @@ public int getUseCount() { } public boolean matches(String msg) { + return matchesInner(msg) || matchesInner(msg.replace(" (this may not be a problem, but you should check that it's not intended to match a slice)", "")); + } + + private boolean matchesInner(String msg) { switch (compType) { case 0: return msg.equals(messageComp); case 1: return msg.startsWith(messageComp); diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/comparators/IpaComparator.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/comparators/IpaComparator.java index a377c531d..ed4a8cc4c 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/comparators/IpaComparator.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/comparators/IpaComparator.java @@ -186,7 +186,7 @@ public void startChecks(ImplementationGuide ig) { vi.context.setLocale(context.getLocale()); vi.context.setLogger(context.getLogger()); vi.context.loadFromPackageAndDependencies(current, new PublisherLoader(current, SpecMapManager.fromPackage(current), current.getWebLocation(), null).makeLoader(), pcm); - vi.pkp = new IGKnowledgeProvider(vi.context, current.getWebLocation(), current.canonical(), null, null, false, null, null, null); + vi.pkp = new IGKnowledgeProvider(vi.context, current.getWebLocation(), current.canonical(), null, null, false, null, null, null, null); } catch (Exception e) { vi.errMsg = "Unable to find load package "+pid+"#"+vi.version+" ("+e.getMessage()+" on file "+filename+")"; e.printStackTrace(); diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/comparators/PreviousVersionComparator.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/comparators/PreviousVersionComparator.java index 6d1244ba0..de9d04986 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/comparators/PreviousVersionComparator.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/comparators/PreviousVersionComparator.java @@ -208,7 +208,7 @@ public void startChecks(ImplementationGuide ig) { vi.context.setLocale(context.getLocale()); vi.context.setLogger(context.getLogger()); vi.context.loadFromPackageAndDependencies(current, new PublisherLoader(current, SpecMapManager.fromPackage(current), current.getWebLocation(), null).makeLoader(), pcm); - vi.pkp = new IGKnowledgeProvider(vi.context, current.getWebLocation(), current.canonical(), null, null, false, null, null, null); + vi.pkp = new IGKnowledgeProvider(vi.context, current.getWebLocation(), current.canonical(), null, null, false, null, null, null, null); } catch (Exception e) { vi.errMsg = "Unable to find load package "+pid+"#"+vi.version+" ("+e.getMessage()+" on file "+filename+")"; e.printStackTrace(); diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/JsonXhtmlRenderer.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/JsonXhtmlRenderer.java index 6b8242ae6..f6f45aebe 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/JsonXhtmlRenderer.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/JsonXhtmlRenderer.java @@ -215,5 +215,10 @@ public void anchor(String name) { b.append(""); } + @Override + public void externalLink(String ref) { + b.append("🔗 "); + } + } diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/XmlXHtmlRenderer.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/XmlXHtmlRenderer.java index becb7c9ee..246435614 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/XmlXHtmlRenderer.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/XmlXHtmlRenderer.java @@ -785,4 +785,18 @@ public void decorate(ElementDecoration decoration) throws IOException { @Override public void setSchemaLocation(String s, String s1) throws IOException { } + + + @Override + public void externalLink(String ref) throws IOException { + if (pendingClose) { + b.append(">"); + writeDecorations(); + writePendingComment(); + pendingClose = false; + } + b.append("🔗 "); + } + + } diff --git a/org.hl7.fhir.publisher.core/src/test/java/tests/AllGuidesTests.java b/org.hl7.fhir.publisher.core/src/test/java/tests/AllGuidesTests.java index 6becf8700..cf24ff4b6 100644 --- a/org.hl7.fhir.publisher.core/src/test/java/tests/AllGuidesTests.java +++ b/org.hl7.fhir.publisher.core/src/test/java/tests/AllGuidesTests.java @@ -46,6 +46,7 @@ private void testIg(String id, String path) throws Exception { String version = readVersion(); File statsFile = determineStatsFile(); long time = System.currentTimeMillis(); + long startingMem = getCurrentmem(); System.out.println("======================================================================================="); String p = (path == null ? Utilities.path(FhirSettings.getTestIgsPath(), id) : Utilities.path(FhirSettings.getTestIgsPath(), id, path)); @@ -84,7 +85,7 @@ private void testIg(String id, String path) throws Exception { si.set("warnings", cWarn); si.set("hints", cHint); si.set("time", System.currentTimeMillis() - time); - si.set("memory", pub.getMaxMemory()); + si.set("memory", pub.getMaxMemory() - startingMem); JsonParser.compose(stats, statsFile, true); Map> statsMap = new HashMap<>(); @@ -134,6 +135,15 @@ private void testIg(String id, String path) throws Exception { dumpMem(id); } + private long getCurrentmem() { + + Runtime runtime = Runtime.getRuntime(); + long totalMemory = runtime.totalMemory(); + long freeMemory = runtime.freeMemory(); + long usedMemory = totalMemory - freeMemory; + return usedMemory; + } + private void dumpMem(String id) throws IOException { File f = new File(Utilities.path("[tmp]", "memory-dump-"+id+".hprof")); f.delete(); diff --git a/pom.xml b/pom.xml index 64eaccac0..faa1ea29b 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 1.5.2-SNAPSHOT - 6.2.1 + 6.2.2-SNAPSHOT 3.0.0-M5 5.2.1 4.11.0 diff --git a/test-statistics.csv b/test-statistics.csv index 36d40b2cb..377e9a5f6 100644 --- a/test-statistics.csv +++ b/test-statistics.csv @@ -3,3 +3,4 @@ 1.4.17,45405,1152,90,,333893,713,576428,510291,688062,20062,77921,292184,255657,49109,182535 1.5.0,48649,1349,129,128937,254417,1494,385606,446970,760444,42358,73453,185270,225642,59841,200877 1.5.1,47973,1120,75,108608,331701,595,566979,500812,702868,32185,76394,300885,258990,49734,191994 +1.5.2,65891,1056,80,109119,545761,594,892711,392719,675203,32335,113522,538889,389926,51564,207463 diff --git a/test-statistics.json b/test-statistics.json index 5e7fcdd39..18ac149ca 100644 --- a/test-statistics.json +++ b/test-statistics.json @@ -407,5 +407,114 @@ "time" : 702868, "memory" : 5103103688 } + }, + "1.5.2" : { + "sync-date" : "2023-10-28", + "date" : "2023-11-07", + "hl7.fhir.template.ig" : { + "errors" : 0, + "warnings" : 0, + "hints" : 0, + "time" : 594, + "memory" : 9868864 + }, + "hl7.cda.uv.core" : { + "errors" : 0, + "warnings" : 1, + "hints" : 2, + "time" : 109119, + "memory" : 4793043584 + }, + "hl7.fhir.us.ecr" : { + "errors" : 6, + "warnings" : 27, + "hints" : 0, + "time" : 392719, + "memory" : 8445073096 + }, + "hl7.fhir.uv.ipa" : { + "errors" : 25, + "warnings" : 8, + "hints" : 32, + "time" : 113522, + "memory" : 1874596080 + }, + "hl7.fhir.uv.ips" : { + "errors" : 0, + "warnings" : 31, + "hints" : 17, + "time" : 538889, + "memory" : 2607124480 + }, + "ihe.mhd.fhir" : { + "errors" : 0, + "warnings" : 21, + "hints" : 21, + "time" : 207463, + "memory" : 2264503184 + }, + "hl7.fhir.uv.sdc" : { + "errors" : 125, + "warnings" : 38, + "hints" : 153, + "time" : 389926, + "memory" : 2254545928 + }, + "hl7.fhir.uv.tools" : { + "errors" : 68, + "warnings" : 4, + "hints" : 3, + "time" : 51564, + "memory" : 1694438320 + }, + "hl7.base.template.ig" : { + "errors" : 0, + "warnings" : 0, + "hints" : 0, + "time" : 80, + "memory" : 8390664 + }, + "hl7.fhir.uv.howto" : { + "errors" : 1, + "warnings" : 0, + "hints" : 0, + "time" : 32335, + "memory" : 1050476360 + }, + "fhir.base.template.ig" : { + "errors" : 0, + "warnings" : 0, + "hints" : 0, + "time" : 1056, + "memory" : 92963024 + }, + "hl7.fhir.au.base" : { + "errors" : 10, + "warnings" : 187, + "hints" : 78, + "time" : 545761, + "memory" : 4179752904 + }, + "example.fhir.uv.myig" : { + "errors" : 18, + "warnings" : 11, + "hints" : 7, + "time" : 65891, + "memory" : 1492180160 + }, + "hl7.fhir.us.core" : { + "errors" : 8, + "warnings" : 7, + "hints" : 211, + "time" : 892711, + "memory" : 9977895608 + }, + "hl7.fhir.uv.extensions" : { + "errors" : 126, + "warnings" : 92, + "hints" : 211, + "time" : 675203, + "memory" : 7181111928 + } } }