From 17a42b3d376447bf9b621e5bd44dc628afbf82c4 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 7 Jan 2025 14:12:43 +1100 Subject: [PATCH 1/4] add use-context fragment for version contest restrictions + Lookup compliesWithProfile target from link-only dependencies + Accessibility - role=presentation on appropriate tables --- .../fhir/igtools/publisher/HTMLInspector.java | 15 ++-- .../hl7/fhir/igtools/publisher/Publisher.java | 51 ++++++++++- .../publisher/modules/CrossVersionModule.java | 4 +- .../igtools/renderers/CrossViewRenderer.java | 6 +- .../igtools/renderers/HistoryGenerator.java | 2 +- .../igtools/renderers/StatusRenderer.java | 2 +- .../StructureDefinitionRenderer.java | 84 ++++++++++++++++++- .../renderers/ValidationPresenter.java | 6 +- .../hl7/fhir/igtools/web/IndexMaintainer.java | 4 +- 9 files changed, 150 insertions(+), 24 deletions(-) diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/HTMLInspector.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/HTMLInspector.java index 3cd247c27..cc59e14f8 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/HTMLInspector.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/HTMLInspector.java @@ -40,6 +40,7 @@ import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.igtools.publisher.Publisher.FragmentUseRecord; +import org.hl7.fhir.igtools.publisher.Publisher.LinkedSpecification; import org.hl7.fhir.igtools.publisher.SpecMapManager.SpecialPackageType; import org.hl7.fhir.igtools.publisher.modules.IPublisherModule; import org.hl7.fhir.r5.context.ILoggingService; @@ -199,7 +200,7 @@ public String getNextId() { private String rootFolder; private String altRootFolder; private List specs; - private List linkSpecs; + private List linkSpecs; private Map cache = new HashMap(); private int iteration = 0; private List otherlinks = new ArrayList(); @@ -226,7 +227,7 @@ public String getNextId() { private Map jsmsgs = new HashMap<>(); private Map fragmentUses = new HashMap<>(); - public HTMLInspector(String rootFolder, List specs, List linkSpecs, ILoggingService log, String canonical, String packageId, Map> trackedFragments, List sources, IPublisherModule module, boolean isCIBuild, Map fragmentUses) { + public HTMLInspector(String rootFolder, List specs, List linkSpecs, ILoggingService log, String canonical, String packageId, Map> trackedFragments, List sources, IPublisherModule module, boolean isCIBuild, Map fragmentUses) { this.rootFolder = rootFolder.replace("/", File.separator); this.specs = specs; this.linkSpecs = linkSpecs; @@ -805,12 +806,12 @@ private boolean checkTarget(String filename, String ref, String rref, StringBuil } } if (!resolved && linkSpecs != null){ - for (SpecMapManager spec : linkSpecs) { - if (!resolved && spec.getBase() != null) { - resolved = resolved || spec.getBase().equals(rref) || (spec.getBase()).equals(rref+"/") || (spec.getBase()+"/").equals(rref)|| spec.hasTarget(rref) || Utilities.existsInList(rref, Utilities.pathURL(spec.getBase(), "history.html")); + for (LinkedSpecification spec : linkSpecs) { + if (!resolved && spec.getSpm().getBase() != null) { + resolved = resolved || spec.getSpm().getBase().equals(rref) || (spec.getSpm().getBase()).equals(rref+"/") || (spec.getSpm().getBase()+"/").equals(rref)|| spec.getSpm().hasTarget(rref) || Utilities.existsInList(rref, Utilities.pathURL(spec.getSpm().getBase(), "history.html")); } - if (!resolved && spec.getBase2() != null) { - resolved = spec.getBase2().equals(rref) || (spec.getBase2()).equals(rref+"/"); + if (!resolved && spec.getSpm().getBase2() != null) { + resolved = spec.getSpm().getBase2().equals(rref) || (spec.getSpm().getBase2()).equals(rref+"/"); } } } 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 c4f41a28c..fdf354c59 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 @@ -288,6 +288,7 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext.ExampleScenarioRendererMode; import org.hl7.fhir.r5.renderers.utils.RenderingContext.FixedValueFormat; import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules; +import org.hl7.fhir.r5.renderers.utils.RenderingContext.IResourceLinkResolver; import org.hl7.fhir.r5.renderers.utils.RenderingContext.ITypeParser; import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType; import org.hl7.fhir.r5.renderers.utils.RenderingContext.QuestionnaireRendererMode; @@ -360,6 +361,7 @@ import org.hl7.fhir.utilities.npm.CommonPackages; import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; import org.hl7.fhir.utilities.npm.NpmPackage; +import org.hl7.fhir.utilities.npm.NpmPackage.PackageResourceInformation; import org.hl7.fhir.utilities.npm.PackageGenerator.PackageType; import org.hl7.fhir.utilities.npm.PackageHacker; import org.hl7.fhir.utilities.npm.PackageList; @@ -447,7 +449,7 @@ * ToC is generated by java, needs to be translated */ -public class Publisher implements ILoggingService, IReferenceResolver, IValidationProfileUsageTracker { +public class Publisher implements ILoggingService, IReferenceResolver, IValidationProfileUsageTracker, IResourceLinkResolver { public class FragmentUseRecord { @@ -654,6 +656,21 @@ public enum LinkTargetType { } + public static class LinkedSpecification { + private SpecMapManager spm; + private NpmPackage npm; + public LinkedSpecification(SpecMapManager spm, NpmPackage npm) { + super(); + this.spm = spm; + this.npm = npm; + } + public SpecMapManager getSpm() { + return spm; + } + public NpmPackage getNpm() { + return npm; + } + } public enum CacheOption { LEAVE, CLEAR_ERRORS, CLEAR_ALL; @@ -732,7 +749,7 @@ public enum CacheOption { private IGKnowledgeProvider igpkp; private List specMaps = new ArrayList(); private List npms = new ArrayList(); - private List linkSpecMaps = new ArrayList(); + private List linkSpecMaps = new ArrayList<>(); private List suppressedIds = new ArrayList<>(); private Map mappingSpaces = new HashMap(); @@ -4132,7 +4149,7 @@ private void loadLinkIg(String packageId) throws Exception { igm.setName(pi.title()); igm.setBase(pi.canonical()); igm.setBase2(PackageHacker.fixPackageUrl(pi.url())); - linkSpecMaps.add(igm); + linkSpecMaps.add(new LinkedSpecification(igm, pi)); } } @@ -4808,6 +4825,7 @@ private boolean load() throws Exception { rc.setParser(getTypeLoader(version)); rc.addLink(KnownLinkType.SELF, targetOutput); rc.setFixedFormat(fixedFormat); + rc.setResolveLinkResolver(this); module.defineTypeMap(rc.getTypeMap()); if (publishedIg.hasJurisdiction()) { Locale locale = null; @@ -13412,6 +13430,10 @@ private void generateOutputsStructureDefinition(FetchedFile f, FetchedResource r long start = System.currentTimeMillis(); fragment("StructureDefinition-"+prefixForContainer+sd.getId()+"-sd-xref"+langSfx, sdr.references(), f.getOutputNames(), r, vars, null, start, "xref", "StructureDefinition"); } + if (igpkp.wantGen(r, "use-context")) { + long start = System.currentTimeMillis(); + fragment("StructureDefinition-"+prefixForContainer+sd.getId()+"-sd-use-context"+langSfx, sdr.useContext(), f.getOutputNames(), r, vars, null, start, "use-context", "StructureDefinition"); + } if (igpkp.wantGen(r, "changes")) { long start = System.currentTimeMillis(); fragment("StructureDefinition-"+prefixForContainer+sd.getId()+"-sd-changes"+langSfx, sdr.changeSummary(), f.getOutputNames(), r, vars, null, start, "changes", "StructureDefinition"); @@ -14840,7 +14862,6 @@ public static void publishDirect(String path) throws Exception { if (self.countErrs(self.errors) > 0) { throw new Exception("Building IG '"+path+"' caused an error"); } - } public long getMaxMemory() { @@ -14859,4 +14880,26 @@ public String resolveUri(RenderingContext context, String uri) { return null; } + @Override + public T findLinkableResource(Class class_, String uri) throws IOException { + for (LinkedSpecification spec : linkSpecMaps) { + String name = class_.getSimpleName(); + for (PackageResourceInformation pri : spec.getNpm().listIndexedResources(name)) { + boolean match = false; + if (uri.contains("|")) { + match = uri.equals(pri.getUrl()+"|"+pri.getVersion()); + } else { + match = uri.equals(pri.getUrl()); + } + if (match) { + InputStream s = spec.getNpm().load(pri); + IContextResourceLoader pl = new PublisherLoader(spec.getNpm(), spec.getSpm(), PackageHacker.fixPackageUrl(spec.getNpm().getWebLocation()), igpkp).makeLoader(); + Resource res = pl.loadResource(s, true); + return (T) res; + } + } + } + return null; + } + } diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/modules/CrossVersionModule.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/modules/CrossVersionModule.java index 7e2526899..e9d8e1690 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/modules/CrossVersionModule.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/modules/CrossVersionModule.java @@ -191,7 +191,7 @@ private void genExtensionPage(String path, StructureDefinition sd) throws IOExce } XhtmlNode body = new XhtmlNode(NodeType.Element, "div"); body.h1().tx(sd.getTitle()); - var tbl = body.table("grid"); + var tbl = body.table("grid", false); var tr = tbl.tr(); tr.td().b().tx("URL"); tr.td().tx(sd.getUrl()); @@ -336,7 +336,7 @@ private void genVersionType(String path, StructureDefinition sd, ImplementationG XhtmlNode body = new XhtmlNode(NodeType.Element, "div"); body.h1().tx(sd.getName()); body.para().tx("FHIR Cross-version Mappings for "+sd.getType()+" based on the R5 structure"); - XhtmlNode tbl = body.table("grid"); + XhtmlNode tbl = body.table("grid", false); XhtmlNode tr = tbl.tr(); // we're going to generate a table with a column for each target structure definition in the chains that terminate in the provided sd diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/CrossViewRenderer.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/CrossViewRenderer.java index 85ba3b56b..1a6396771 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/CrossViewRenderer.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/CrossViewRenderer.java @@ -795,7 +795,7 @@ private String buildExtensionTable(String type, List defini } else { kind = "data type"; } - var tbl = x.table("list"); + var tbl = x.table("list", false); var tr = tbl.tr(); var td = tr.td(); td.b().tx("Identity"); @@ -1318,7 +1318,7 @@ public String renderVSList(String versionToAnnotate, List vslist, bool XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); Collections.sort(vslist, new CanonicalResourceSortByUrl()); - var tbl = x.table("grid"); + var tbl = x.table("grid", false); var tr = tbl.tr(); tr.th().tx("URL"); if (versions) { @@ -1613,7 +1613,7 @@ private void resolveCS(List list, String url, Resource source) { public String renderCSList(String versionToAnnotate, List cslist, boolean versions, boolean used) throws IOException { XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); Collections.sort(cslist, new CanonicalResourceSortByUrl()); - var tbl = x.table("grid"); + var tbl = x.table("grid", false); var tr = tbl.tr(); tr.th().tx("URL"); if (versions) { diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/HistoryGenerator.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/HistoryGenerator.java index 0bbd463e6..c0f0265af 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/HistoryGenerator.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/HistoryGenerator.java @@ -60,7 +60,7 @@ public XhtmlNode internalGenerate(List entries, boolean showT XhtmlNode div = new XhtmlNode(NodeType.Element, "div"); div.hr(); div.para().b().tx("History"); - XhtmlNode tbl = div.table("grid"); + XhtmlNode tbl = div.table("grid", false); // headers XhtmlNode tr = tbl.tr(); 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 f2a7c36e1..f60426b77 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 @@ -260,7 +260,7 @@ private static String readOwner(Element resource) { public static String render(String src, ResourceStatusInformation info, RenderingContext rc) { StringBuilder b = new StringBuilder(); - b.append(""); String pub = rc.formatPhrase(RenderingContext.MATURITY_PUBLISHER, Utilities.escapeXml(info.getOwner())); diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java index 6b2bc332d..aed6d747d 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java @@ -1206,7 +1206,7 @@ public String dict(boolean incProfiledOut, int mode, String anchorPrefix) throws var p = x.para(); p.tx("Guidance on how to interpret the contents of this table can be found "); p.ah("https://build.fhir.org/ig/FHIR/ig-guidance//readingIgs.html#data-dictionaries").tx("here"); - XhtmlNode t = x.table("dict"); + XhtmlNode t = x.table("dict", false); List elements = elementsForMode(mode); @@ -2571,4 +2571,86 @@ public String experimentalWarning() { public String adl() { return "
"+Utilities.escapeXml(sd.getUserString(UserDataNames.archetypeSource))+"
"; } + + public String useContext() throws IOException { + XhtmlNode div = new XhtmlNode(NodeType.Element, "div"); + if (sd.getContext().isEmpty()) { + div.para().tx("This extension does not specify which elements it should be used on"); + } else { + div.para().tx("This extension may be used on the following element(s):"); + var ul = div.ul(); + for (StructureDefinitionContextComponent c : sd.getContext()) { + var li = ul.li(); + switch (c.getType()) { + case ELEMENT: + li.tx("Element ID: "); + String tn = c.getExpression(); + if (tn.contains(".")) { + tn = tn.substring(0, tn.indexOf(".")); + } + StructureDefinition t = context.fetchTypeDefinition(tn); + var code = li.code(); + if (t != null && t.hasWebPath()) { + code.ah(t.getWebPath()).tx(c.getExpression()); + } else { + code.tx(c.getExpression()); + } + break; + case EXTENSION: + li.tx("Extension: "); + t = context.fetchResource(StructureDefinition.class, c.getExpression()); + if (t != null && t.hasWebPath()) { + li.ah(t.getWebPath()).tx(t.present()); + } else { + li.code().tx(c.getExpression()); + } + break; + case FHIRPATH: + li.ah(Utilities.pathURL(context.getSpecUrl(), "fhirpath.html")).tx("Path"); + li.tx(": "); + li.tx(c.getExpression()); + break; + default: + li.tx("??: "); + li.tx(c.getExpression()); + break; + } + } + } + if (sd.hasContextInvariant()) { + if (sd.getContextInvariant().size() == 1) { + div.para().tx("In addition, the extension can only be used when this FHIRPath expression is true:"); + div.para().code().tx(sd.getContextInvariant().get(0).asStringValue()); + } else { + div.para().tx("In addition, the extension can only be used when these FHIRPath expressions are true:"); + var ul = div.ul(); + for (StringType sv : sd.getContextInvariant()) { + ul.li().code().tx(sv.asStringValue()); + } + } + } + if (sd.hasExtension(ToolingExtensions.EXT_EARLIEST_FHIR_VERSION) || sd.hasExtension(ToolingExtensions.EXT_LATEST_FHIR_VERSION)) { + var p = div.para(); + if (!sd.hasExtension(ToolingExtensions.EXT_EARLIEST_FHIR_VERSION)) { + p.tx("This extension is defined for use with FHIR versions up to "); + linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_LATEST_FHIR_VERSION)); + } else if (!sd.hasExtension(ToolingExtensions.EXT_LATEST_FHIR_VERSION)) { + p.tx("This extension is defined for use with FHIR version "); + linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_EARLIEST_FHIR_VERSION)); + p.tx(" and after"); + } else { + p.tx("This extension is defined for use with FHIR versions "); + linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_EARLIEST_FHIR_VERSION)); + p.tx(" to "); + linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_LATEST_FHIR_VERSION)); + } + p.tx("."); + } + return new XhtmlComposer(false, true).compose(div.getChildNodes()); + } + + private void linkToVersion(XhtmlNode p, String version) { + String url = VersionUtilities.getSpecUrl(version); + p.ahOrNot(url).b().tx(VersionUtilities.getNameForVersion(version)); + } } diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/ValidationPresenter.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/ValidationPresenter.java index da6e45b9d..9cda546c2 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/ValidationPresenter.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/ValidationPresenter.java @@ -565,7 +565,7 @@ private void genTXServerQA(String title, String path) throws IOException { ul.li().tx("(No Errors/Reports - all good)"); } else { x.para().b().tx("Decisions"); - XhtmlNode tbl = x.table("grid"); + XhtmlNode tbl = x.table("grid", false); XhtmlNode tr = tbl.tr(); tr.td().b().tx("Message"); tr.td().b().tx("Server"); @@ -589,7 +589,7 @@ private void genTXServerQA(String title, String path) throws IOException { } if (isErr) { x.para().b().tx("Errors"); - tbl = x.table("grid"); + tbl = x.table("grid", false); tr = tbl.tr(); tr.td().b().tx("URL"); tr.td().b().tx("Message"); @@ -657,7 +657,7 @@ private void genServerReport(XhtmlNode x, TerminologyClientContext t) { XhtmlNode ul = x.ul(); ul.li().tx("(None)"); } else { - XhtmlNode tbl = x.table("grid"); + XhtmlNode tbl = x.table("grid", false); XhtmlNode tr = tbl.tr(); tr.th().b().tx("System"); tr.th().b().tx("#Exp."); diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/web/IndexMaintainer.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/web/IndexMaintainer.java index ab49d4385..805ddf6a2 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/web/IndexMaintainer.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/web/IndexMaintainer.java @@ -156,7 +156,7 @@ public void loadJson() throws JsonException, IOException, ParseException { } private String generateSummary() throws IOException { XhtmlNode div = new XhtmlNode(NodeType.Element, "div"); - XhtmlNode tbl = div.table("grid"); + XhtmlNode tbl = div.table("grid", false); XhtmlNode tr = tbl.tr(); tr.td().b().tx("IG"); tr.td().b().tx("Details"); @@ -200,7 +200,7 @@ private void release(XhtmlNode td, Instant date, String ver, String ref, String private String generateByDate() throws IOException { XhtmlNode div = new XhtmlNode(NodeType.Element, "div"); - XhtmlNode tbl = div.table("grid"); + XhtmlNode tbl = div.table("grid", false); XhtmlNode tr = tbl.tr(); tr.td().b().tx("IG"); tr.td().b().tx("Name"); From ff4aef6b2520accf751fb0a29e8c50c410842255 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 7 Jan 2025 16:39:57 +1100 Subject: [PATCH 2/4] resolve issues with references between IGs to example resources --- .../hl7/fhir/igtools/publisher/Publisher.java | 33 +++++++++++++++---- .../igtools/publisher/SpecMapManager.java | 20 ++++++++++- .../StructureDefinitionRenderer.java | 8 ++--- 3 files changed, 49 insertions(+), 12 deletions(-) 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 fdf354c59..dca2b2696 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 @@ -1599,7 +1599,7 @@ public void setCacheOption(CacheOption cacheOption) { @Override - public ResourceWithReference resolve(RenderingContext context, String url, String version) { + public ResourceWithReference resolve(RenderingContext context, String url, String version) throws IOException { if (url == null) { return null; } @@ -1667,9 +1667,24 @@ public ResourceWithReference resolve(RenderingContext context, String url, Strin path = null; } - if (path != null) - - return new ResourceWithReference(ResourceReferenceKind.EXTERNAL, url, path, null); + if (path != null) { + InputStream s = null; + if (sp.getNpm() != null && fp.contains("/") && sp.getLoader() != null) { + String[] pl = fp.split("\\/"); + String rt = pl[pl.length-2]; + String id = pl[pl.length-1]; + s = sp.getNpm().loadExampleResource(rt, id); + } + if (s == null) { + return new ResourceWithReference(ResourceReferenceKind.EXTERNAL, url, path, null); + } else { + IContextResourceLoader loader = sp.getLoader(); + Resource res = loader.loadResource(s, true); + res.setWebPath(path); + return new ResourceWithReference(ResourceReferenceKind.EXTERNAL, url, path, ResourceWrapper.forResource(context, res)); + + } + } } for (FetchedFile f : fileList) { @@ -4235,6 +4250,7 @@ private void loadIGPackage(String name, String canonical, String packageId, Stri igm.setName(name); igm.setBase(canonical); igm.setBase2(PackageHacker.fixPackageUrl(pi.url())); + igm.setNpm(pi); specMaps.add(igm); if (!VersionUtilities.versionsCompatible(version, pi.fhirVersion())) { if (!pi.isWarned()) { @@ -4244,7 +4260,7 @@ private void loadIGPackage(String name, String canonical, String packageId, Stri } } - loadFromPackage(name, canonical, pi, webref, igm, loadDeps); + igm.setLoader(loadFromPackage(name, canonical, pi, webref, igm, loadDeps)); } private boolean isValidIGToken(String tail) { @@ -4281,7 +4297,7 @@ private String getIgUri(NpmPackage pi) throws IOException { - public void loadFromPackage(String name, String canonical, NpmPackage pi, String webref, SpecMapManager igm, boolean loadDeps) throws IOException { + public IContextResourceLoader loadFromPackage(String name, String canonical, NpmPackage pi, String webref, SpecMapManager igm, boolean loadDeps) throws IOException { if (loadDeps) { // we do not load dependencies for packages the tooling loads on it's own initiative for (String dep : pi.dependencies()) { if (!context.hasPackage(dep)) { @@ -4308,6 +4324,7 @@ public void loadFromPackage(String name, String canonical, NpmPackage pi, String smm.setName(dpi.name()+"_"+dpi.version()); smm.setBase(dpi.canonical()); smm.setBase2(PackageHacker.fixPackageUrl(dpi.url())); + smm.setNpm(pi); specMaps.add(smm); } catch (Exception e) { if (!"hl7.fhir.core".equals(dpi.name())) { @@ -4316,7 +4333,7 @@ public void loadFromPackage(String name, String canonical, NpmPackage pi, String } try { - loadFromPackage(dpi.title(), dpi.canonical(), dpi, PackageHacker.fixPackageUrl(dpi.getWebLocation()), smm, true); + smm.setLoader(loadFromPackage(dpi.title(), dpi.canonical(), dpi, PackageHacker.fixPackageUrl(dpi.getWebLocation()), smm, true)); } catch (Exception e) { throw new IOException("Error loading "+dpi.name()+"#"+dpi.version()+": "+e.getMessage(), e); } @@ -4327,6 +4344,7 @@ public void loadFromPackage(String name, String canonical, NpmPackage pi, String } IContextResourceLoader loader = new PublisherLoader(pi, igm, webref, igpkp).makeLoader(); context.loadFromPackage(pi, loader); + return loader; } private String fixPackageReference(String dep) { @@ -4826,6 +4844,7 @@ private boolean load() throws Exception { rc.addLink(KnownLinkType.SELF, targetOutput); rc.setFixedFormat(fixedFormat); rc.setResolveLinkResolver(this); + rc.setDebug(debug); module.defineTypeMap(rc.getTypeMap()); if (publishedIg.hasJurisdiction()) { Locale locale = null; diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/SpecMapManager.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/SpecMapManager.java index 876036844..bfa396d79 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/SpecMapManager.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/publisher/SpecMapManager.java @@ -33,6 +33,7 @@ import java.util.Set; import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r5.context.IContextResourceLoader; import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; @@ -77,6 +78,7 @@ public enum SpecialPackageType { private String auth; private String realm; private String npmVId; + private IContextResourceLoader loader; private SpecMapManager() { @@ -459,7 +461,7 @@ public static SpecMapManager createSpecialPackage(NpmPackage pi, BasePackageCach res.special = SpecialPackageType.DICOM; } else if (pi.name().startsWith("hl7.fhir.") && pi.name().endsWith(".examples") ) { res.special = SpecialPackageType.Examples; - } else { + } else if (!pi.name().startsWith("hl7.fhir.us.core.v")) { res.special = SpecialPackageType.Simplifier; } res.pi = pi; @@ -511,5 +513,21 @@ public boolean isCore() { return "hl7.fhir.core".equals(getNpmName()); } + public NpmPackage getNpm() { + return pi; + } + + public void setNpm(NpmPackage pi) { + this.pi = pi; + } + + public IContextResourceLoader getLoader() { + return loader; + } + + public void setLoader(IContextResourceLoader loader) { + this.loader = loader; + } + } diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java index aed6d747d..b8efd7113 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java @@ -2611,7 +2611,7 @@ public String useContext() throws IOException { li.tx(c.getExpression()); break; default: - li.tx("??: "); + li.tx("?type?: "); li.tx(c.getExpression()); break; } @@ -2632,14 +2632,14 @@ public String useContext() throws IOException { if (sd.hasExtension(ToolingExtensions.EXT_EARLIEST_FHIR_VERSION) || sd.hasExtension(ToolingExtensions.EXT_LATEST_FHIR_VERSION)) { var p = div.para(); if (!sd.hasExtension(ToolingExtensions.EXT_EARLIEST_FHIR_VERSION)) { - p.tx("This extension is defined for use with FHIR versions up to "); + p.tx("This extension is allowed for use with FHIR versions up to "); linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_LATEST_FHIR_VERSION)); } else if (!sd.hasExtension(ToolingExtensions.EXT_LATEST_FHIR_VERSION)) { - p.tx("This extension is defined for use with FHIR version "); + p.tx("This extension is allowed for use with FHIR version "); linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_EARLIEST_FHIR_VERSION)); p.tx(" and after"); } else { - p.tx("This extension is defined for use with FHIR versions "); + p.tx("This extension is allowed for use with FHIR versions "); linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_EARLIEST_FHIR_VERSION)); p.tx(" to "); linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_LATEST_FHIR_VERSION)); From 27a1d2c63d6a8c4e19c8e2028b034a9355322ea3 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 9 Jan 2025 19:05:19 +1100 Subject: [PATCH 3/4] improved version specific extension rendering --- .../StructureDefinitionRenderer.java | 38 ++++++++++++------- .../renderers/ValidationPresenter.java | 2 +- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java index b8efd7113..58fae4c97 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/StructureDefinitionRenderer.java @@ -2615,6 +2615,11 @@ public String useContext() throws IOException { li.tx(c.getExpression()); break; } + if (c.hasExtension(ToolingExtensions.EXT_FHIRVERSION_SPECIFIC_USE)) { + li.tx(" ("); + renderVersionRange(c.getExtensionByUrl(ToolingExtensions.EXT_FHIRVERSION_SPECIFIC_USE), li); + li.tx(")"); + } } } if (sd.hasContextInvariant()) { @@ -2629,26 +2634,31 @@ public String useContext() throws IOException { } } } - if (sd.hasExtension(ToolingExtensions.EXT_EARLIEST_FHIR_VERSION) || sd.hasExtension(ToolingExtensions.EXT_LATEST_FHIR_VERSION)) { + if (sd.hasExtension(ToolingExtensions.EXT_FHIRVERSION_SPECIFIC_USE)) { var p = div.para(); - if (!sd.hasExtension(ToolingExtensions.EXT_EARLIEST_FHIR_VERSION)) { - p.tx("This extension is allowed for use with FHIR versions up to "); - linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_LATEST_FHIR_VERSION)); - } else if (!sd.hasExtension(ToolingExtensions.EXT_LATEST_FHIR_VERSION)) { - p.tx("This extension is allowed for use with FHIR version "); - linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_EARLIEST_FHIR_VERSION)); - p.tx(" and after"); - } else { - p.tx("This extension is allowed for use with FHIR versions "); - linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_EARLIEST_FHIR_VERSION)); - p.tx(" to "); - linkToVersion(p, ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_LATEST_FHIR_VERSION)); - } + p.tx("This extension is allowed for use with "); + renderVersionRange(sd.getExtensionByUrl(ToolingExtensions.EXT_FHIRVERSION_SPECIFIC_USE), p); p.tx("."); } return new XhtmlComposer(false, true).compose(div.getChildNodes()); } + public void renderVersionRange(Extension ext, XhtmlNode li) { + if (!ext.hasExtension(ToolingExtensions.EXT_FHIRVERSION_SPECIFIC_USE_START)) { + li.tx("FHIR versions up to "); + linkToVersion(li, ToolingExtensions.readStringExtension(ext, ToolingExtensions.EXT_FHIRVERSION_SPECIFIC_USE_END)); + } else if (!ext.hasExtension(ToolingExtensions.EXT_FHIRVERSION_SPECIFIC_USE_END)) { + li.tx("FHIR versions "); + linkToVersion(li, ToolingExtensions.readStringExtension(ext, ToolingExtensions.EXT_FHIRVERSION_SPECIFIC_USE_START)); + li.tx(" and after"); + } else { + li.tx("FHIR versions "); + linkToVersion(li, ToolingExtensions.readStringExtension(ext, ToolingExtensions.EXT_FHIRVERSION_SPECIFIC_USE_START)); + li.tx(" to "); + linkToVersion(li, ToolingExtensions.readStringExtension(ext, ToolingExtensions.EXT_FHIRVERSION_SPECIFIC_USE_END)); + } + } + private void linkToVersion(XhtmlNode p, String version) { String url = VersionUtilities.getSpecUrl(version); p.ahOrNot(url).b().tx(VersionUtilities.getNameForVersion(version)); diff --git a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/ValidationPresenter.java b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/ValidationPresenter.java index 9cda546c2..929887416 100644 --- a/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/ValidationPresenter.java +++ b/org.hl7.fhir.publisher.core/src/main/java/org/hl7/fhir/igtools/renderers/ValidationPresenter.java @@ -1138,7 +1138,7 @@ public static List filterMessages(List mes private final String detailsTemplate = "
\r\n"+ - " \r\n"+ + " \r\n"+ " \r\n"; private final String groupDetailsTemplate = From 7b61e34d28072c131b0dd1188ecc8acc90e90d1f Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 9 Jan 2025 19:09:18 +1100 Subject: [PATCH 4/4] release notes --- RELEASE_NOTES.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e69de29bb..b8532bad1 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -0,0 +1,22 @@ +* Loader: Lazy load binaries for reduced memory usage +* Loader: Support for Archetype processing in IG publisher +* Loader: Process Archetypes properly as both IG input and output + remove ig-r4.json +* Validator: Do not create issue about draft dependency for example bindings +* Validator: Beef up validation of CodeSystem properties that are codes +* Validator: Make sure all validation messages have a message id +* Validator: enforce version-set-specific value for Extension and Extension context +* Validator: Specific Error when ValueSet.compose.include.system refers to a ValueSet +* Renderer: improved version specific extension rendering +* Renderer: Add element view to generated fragments +* Renderer: improve Extension context of use presentation - generate a fragment for that +* Renderer: resolve issues with references between IGs to example resources +* Renderer: add use-context fragment for version contest restrictions +* Renderer: Lookup compliesWithProfile target from link-only dependencies +* Renderer: Accessibility - role=presentation on appropriate tables +* Renderer: Add archetype processing, and also path-other support +* Renderer: resolve issues with references between IGs to example resources +* Renderer: Lookup compliesWithProfile target from link-only dependencies +* Renderer: Update SNOMED editions related routines (add more editions) +* Renderer: Accessibility - role=presentation on appropriate tables +* Packages: Add support for ADL in packages +* Terminology Tests: Report count of tests in output from TxTester
$path$$level$$msg$$comment$$path$$level$$msg$$comment$ $mid$