Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into develop-6.0
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/Hl7.Fhir.Base/CompatibilitySuppressions.xml
#	src/Hl7.Fhir.Base/FhirPath/ElementNavFhirExtensions.cs
#	src/Hl7.Fhir.Base/FhirPath/EvaluationContext.cs
#	src/Hl7.Fhir.Base/FhirPath/FhirEvaluationContext.cs
#	src/Hl7.Fhir.Base/Model/Generated/Attachment.cs
#	src/Hl7.Fhir.Base/Specification/Snapshot/SnapshotGeneratorExtensions.cs
#	src/Hl7.Fhir.Support.Tests/Specification/LanguageTerminologyServiceTests.cs
#	src/firely-net-sdk.props
  • Loading branch information
Kasdejong committed Dec 5, 2024
2 parents fcfb244 + 90c0b04 commit a26298c
Show file tree
Hide file tree
Showing 29 changed files with 159 additions and 167 deletions.
5 changes: 3 additions & 2 deletions release-notes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
## Intro:
## Breaking changes:

Hotfix: Fixed an incorrect string concatenation and subsequent argument exception when the Id of a contained resource was not set.
- EvaluationContext.WithResourceOverrides() introduced in 5.10 is refactored to now be an extension method instead of a static construction method. It should now be called on an instance of EvaluationContext, and will mutate and return that instance.
- We changed the datatype of the Attachment.Url from FhirUrl to FhirUri. The type of this element was changed with the introduction of R4. (FhirUrl doesn't exist in STU3). When we moved Attachment to base, we wrongfully put FhirUrl here, which is the more specific datatype of the two. We have corrected this.
2 changes: 1 addition & 1 deletion src/Hl7.Fhir.Base/CompatibilitySuppressions.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
Expand Down
10 changes: 10 additions & 0 deletions src/Hl7.Fhir.Base/FhirPath/EvaluationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,14 @@ public static T WithResourceOverrides<T>(this T context, IScopedNode? resource,
context.RootResource = rootResource ?? resource;
return context;
}
}

public static class EvaluationContextExtensions
{
public static T WithResourceOverrides<T>(this T context, ITypedElement? resource, ITypedElement? rootResource = null) where T : EvaluationContext
{
context.Resource = resource;
context.RootResource = rootResource ?? resource;
return context;
}
}
2 changes: 1 addition & 1 deletion src/Hl7.Fhir.Base/Hl7.Fhir.Base.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="System.Buffers" Version="4.5.1" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
<PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/Hl7.Fhir.Base/Model/Generated/Attachment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public string Url
if (value == null)
UrlElement = null;
else
UrlElement = new Hl7.Fhir.Model.FhirUrl(value);
UrlElement = new Hl7.Fhir.Model.FhirUri(value);
OnPropertyChanged("Url");
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/Hl7.Fhir.Base/Model/ParametersExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Hl7.Fhir.Model
public static class ParametersExtensions
{
private const string CODEATTRIBUTE = "code";
private const string URLATTRIBUTE = "url";
private const string SYSTEMATTRIBUTE = "system";
private const string CONTEXTATTRIBUTE = "context";

Expand Down Expand Up @@ -39,12 +40,13 @@ internal static void CheckForValidityOfValidateCodeParams(this Parameters parame
{
parameters.NoDuplicates();

//If a code is provided, a system or a context must be provided (http://hl7.org/fhir/valueset-operation-validate-code.html)
if (parameters.Parameter.Any(p => p.Name == CODEATTRIBUTE) && !(parameters.Parameter.Any(p => p.Name == SYSTEMATTRIBUTE) ||
//This error was changed from system to url. See: https://chat.fhir.org/#narrow/channel/179202-terminology/topic/Required.20.24validate-code.20parameters/near/482250225
//If a code is provided, a url or a context must be provided (http://hl7.org/fhir/valueset-operation-validate-code.html)
if (parameters.Parameter.Any(p => p.Name == CODEATTRIBUTE) && !(parameters.Parameter.Any(p => p.Name == URLATTRIBUTE) ||
parameters.Parameter.Any(p => p.Name == CONTEXTATTRIBUTE)))
{
//422 Unproccesable Entity
throw new FhirOperationException($"If a code is provided, a system or a context must be provided", (HttpStatusCode)422);
throw new FhirOperationException($"If a code is provided, a url or a context must be provided", (HttpStatusCode)422);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ public static void RemoveAllConstrainedByDiffExtensions<T>(this IEnumerable<T> e
}
}


/// <summary>
/// This extension removes all non-inheritable extensions from the specified element definition and all it's child objects.
/// Non-inheritable extensions are extensions that should not be inherited by derived profiles.
/// </summary>
/// <param name="element"></param>
internal static void RemoveAllNonInheritableExtensions(this Element element)
{
if (element == null) { throw Error.ArgumentNull(nameof(element)); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class ValidateCodeParameters
private readonly string _dateAttribute = "date";
private readonly string _abstractAttribute = "abstract";
private readonly string _displayLanguageAttribute = "displayLanguage";
private readonly string _inferSystemAttribute = "inferSystem";

public ValidateCodeParameters(Parameters parameters)
{
Expand All @@ -41,6 +42,7 @@ public ValidateCodeParameters(Parameters parameters)
Date = parameters.GetSingleValue<FhirDateTime>(_dateAttribute);
Abstract = parameters.GetSingleValue<FhirBoolean>(_abstractAttribute);
DisplayLanguage = parameters.GetSingleValue<Code>(_displayLanguageAttribute);
InferSystem = parameters.GetSingleValue<FhirBoolean>(_inferSystemAttribute);
}


Expand All @@ -58,14 +60,15 @@ public ValidateCodeParameters WithValueSet(string url, string context = null, Re
return this;
}

public ValidateCodeParameters WithCode(string code = null, string system = null, string systemVersion = null, string display = null, string displayLanguage = null, string context = null)
public ValidateCodeParameters WithCode(string code = null, string system = null, string systemVersion = null, string display = null, string displayLanguage = null, string context = null, bool? inferSystem = null)
{
if (!string.IsNullOrWhiteSpace(code)) Code = new Code(code);
if (!string.IsNullOrWhiteSpace(system)) System = new FhirUri(system);
if (!string.IsNullOrWhiteSpace(systemVersion)) SystemVersion = new FhirString(systemVersion);
if (!string.IsNullOrWhiteSpace(display)) Display = new FhirString(display);
if (!string.IsNullOrWhiteSpace(displayLanguage)) DisplayLanguage = new Code(displayLanguage);
if (!string.IsNullOrWhiteSpace(context)) Context = new FhirUri(context);
if (inferSystem is { }) InferSystem = new FhirBoolean(inferSystem);
return this;
}

Expand Down Expand Up @@ -151,6 +154,8 @@ public ValidateCodeParameters WithAbstract(bool? @abstract)
/// </summary>
public Code DisplayLanguage { get; private set; }

public FhirBoolean InferSystem { get; private set; }

/// <summary>
///
/// </summary>
Expand All @@ -160,8 +165,8 @@ public Parameters Build()
var result = new Parameters();

if (Url is { }) result.Add(_urlAttribute, Url);
if (Context is { }) result.Add(_contextAttribute, Context);
if (ValueSet is { }) result.Add(_valueSetAttribute, ValueSet);
if (Context is { }) result.Add(_contextAttribute, Context);
if (ValueSetVersion is { }) result.Add(_valueSetVersionAttribute, ValueSetVersion);
if (Code is { }) result.Add(_codeAttribute, Code);
if (System is { }) result.Add(_systemAttribute, System);
Expand All @@ -171,8 +176,8 @@ public Parameters Build()
if (CodeableConcept is { }) result.Add(_codeableConceptAttribute, CodeableConcept);
if (Date is { }) result.Add(_dateAttribute, Date);
if (Abstract is { }) result.Add(_abstractAttribute, Abstract);
if (DisplayLanguage is { }) result.Add(_displayAttribute, DisplayLanguage);

if (DisplayLanguage is { }) result.Add(_displayLanguageAttribute, DisplayLanguage);
if (InferSystem is { }) result.Add(_inferSystemAttribute, InferSystem);
return result;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2224,17 +2224,9 @@ private async Tasks.Task<bool> ensureSnapshot(StructureDefinition sd, string pro

try
{
var shouldGenerate = _settings.RegenerationBehaviour switch
{
RegenerationSettings.TRY_USE_EXISTING => !sd.HasSnapshot,
RegenerationSettings.REGENERATE_ONCE => !sd.HasSnapshot || !sd.Snapshot.IsCreatedBySnapshotGenerator(),
#pragma warning disable CS0618 // Type or member is obsolete
RegenerationSettings.FORCE_REGENERATE => true, // possible infinite recursion
#pragma warning restore CS0618 // Type or member is obsolete
_ => throw new InvalidOperationException($"Invalid RegenerationSettings value {_settings.RegenerationBehaviour}")
};

if (_settings.GenerateSnapshotForExternalProfiles && shouldGenerate)
if (_settings.GenerateSnapshotForExternalProfiles
&& (!sd.HasSnapshot || (_settings.ForceRegenerateSnapshots && !sd.Snapshot.IsCreatedBySnapshotGenerator()))
)
{
// Automatically expand external profiles on demand
// Debug.Print($"[{nameof(SnapshotGenerator)}.{nameof(ensureSnapshot)}] Recursively generate snapshot for type profile with url: '{sd.Url}' ...");
Expand Down Expand Up @@ -2316,18 +2308,9 @@ private async Tasks.Task<ElementDefinition> getSnapshotRootElement(StructureDefi
var cachedRoot = sd.GetSnapshotRootElementAnnotation();
if (cachedRoot != null) { return cachedRoot; }
#endif
var hasValidRoot = _settings.RegenerationBehaviour switch
{
RegenerationSettings.TRY_USE_EXISTING => sd.HasSnapshot,
RegenerationSettings.REGENERATE_ONCE => sd.HasSnapshot && sd.Snapshot.IsCreatedBySnapshotGenerator(),
#pragma warning disable CS0618 // Type or member is obsolete
RegenerationSettings.FORCE_REGENERATE => false,
#pragma warning restore CS0618 // Type or member is obsolete
_ => throw new InvalidOperationException($"Invalid RegenerationSettings value {_settings.RegenerationBehaviour}")
};


// 2. Return root element definition from existing (pre-generated) snapshot, if it exists
if (hasValidRoot)
if (sd.HasSnapshot && (sd.Snapshot.IsCreatedBySnapshotGenerator() || !_settings.ForceRegenerateSnapshots))
{
// Debug.Print($"[{nameof(SnapshotGenerator)}.{nameof(getSnapshotRootElement)}] {nameof(profileUri)} = '{profileUri}' - use existing root element definition from snapshot: #{sd.Snapshot.Element[0].GetHashCode()}");
// No need to save root ElemDef annotation, as the snapshot has already been fully expanded
Expand Down
27 changes: 5 additions & 22 deletions src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1941,17 +1941,9 @@ private async Tasks.Task<bool> ensureSnapshot(StructureDefinition sd, string pro

try
{
var shouldGenerate = _settings.RegenerationBehaviour switch
{
RegenerationSettings.TRY_USE_EXISTING => !sd.HasSnapshot,
RegenerationSettings.REGENERATE_ONCE => !sd.HasSnapshot || !sd.Snapshot.IsCreatedBySnapshotGenerator(),
#pragma warning disable CS0618 // Type or member is obsolete
RegenerationSettings.FORCE_REGENERATE => true,
#pragma warning restore CS0618 // Type or member is obsolete
_ => throw new InvalidOperationException($"Invalid RegenerationSettings value {_settings.RegenerationBehaviour}")
};

if (_settings.GenerateSnapshotForExternalProfiles && shouldGenerate)
if (_settings.GenerateSnapshotForExternalProfiles
&& (!sd.HasSnapshot || (_settings.ForceRegenerateSnapshots && !sd.Snapshot.IsCreatedBySnapshotGenerator()))
)
{
// Automatically expand external profiles on demand
// Debug.Print($"[{nameof(SnapshotGenerator)}.{nameof(ensureSnapshot)}] Recursively generate snapshot for type profile with url: '{sd.Url}' ...");
Expand Down Expand Up @@ -2033,18 +2025,9 @@ private async Tasks.Task<ElementDefinition> getSnapshotRootElement(StructureDefi
var cachedRoot = sd.GetSnapshotRootElementAnnotation();
if (cachedRoot != null) { return cachedRoot; }
#endif
var hasValidRoot = _settings.RegenerationBehaviour switch
{
RegenerationSettings.TRY_USE_EXISTING => sd.HasSnapshot,
RegenerationSettings.REGENERATE_ONCE => sd.HasSnapshot && sd.Snapshot.IsCreatedBySnapshotGenerator(),
#pragma warning disable CS0618 // Type or member is obsolete
RegenerationSettings.FORCE_REGENERATE => false,
#pragma warning restore CS0618 // Type or member is obsolete
_ => throw new InvalidOperationException($"Invalid RegenerationSettings value {_settings.RegenerationBehaviour}")
};


// 2. Return root element definition from existing (pre-generated) snapshot, if it exists
if (hasValidRoot)
if (sd.HasSnapshot && (sd.Snapshot.IsCreatedBySnapshotGenerator() || !_settings.ForceRegenerateSnapshots))
{
// Debug.Print($"[{nameof(SnapshotGenerator)}.{nameof(getSnapshotRootElement)}] {nameof(profileUri)} = '{profileUri}' - use existing root element definition from snapshot: #{sd.Snapshot.Element[0].GetHashCode()}");
// No need to save root ElemDef annotation, as the snapshot has already been fully expanded
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2017, Firely ([email protected]) and contributors
* See the file CONTRIBUTORS for details.
*
Expand All @@ -7,7 +7,6 @@
*/

using Hl7.Fhir.Utility;
using System;

namespace Hl7.Fhir.Specification.Snapshot
{
Expand Down Expand Up @@ -35,7 +34,7 @@ public void CopyTo(SnapshotGeneratorSettings other)
{
if (other == null) { throw Error.ArgumentNull(nameof(other)); }
other.GenerateSnapshotForExternalProfiles = GenerateSnapshotForExternalProfiles;
other.RegenerationBehaviour = RegenerationBehaviour;
other.ForceRegenerateSnapshots = ForceRegenerateSnapshots;
other.GenerateExtensionsOnConstraints = GenerateExtensionsOnConstraints;
other.GenerateAnnotationsOnConstraints = GenerateAnnotationsOnConstraints;
other.GenerateElementIds = GenerateElementIds;
Expand All @@ -56,18 +55,7 @@ public void CopyTo(SnapshotGeneratorSettings other)
/// Re-generated snapshots are annotated to prevent duplicate re-generation (assuming the provided resource resolver uses caching).
/// If disabled (default), then the snapshot generator relies on existing snapshot components, if they exist.
/// </summary>
[Obsolete(
"This setting does not work as intended. We will maintain the old behaviour for now, and we will consider removing it in a future major release. Use the new RegenerationBehaviour setting instead. See also https://github.com/FirelyTeam/firely-net-sdk/pull/2803")]
public bool ForceRegenerateSnapshots
{
get { return this.RegenerationBehaviour == RegenerationSettings.REGENERATE_ONCE; }
set { this.RegenerationBehaviour = value ? RegenerationSettings.REGENERATE_ONCE : RegenerationSettings.TRY_USE_EXISTING; }
} // ForceExpandAll

/// <summary>
/// Setting for the regeneration behaviour of the snapshot generator. see <see cref="RegenerationSettings"/>.
/// </summary>
public RegenerationSettings RegenerationBehaviour { get; set; }
public bool ForceRegenerateSnapshots { get; set; } = false; // ForceExpandAll

/// <summary>
/// Enable this setting to add a custom <see cref="SnapshotGeneratorExtensions.CONSTRAINED_BY_DIFF_EXT"/> extension
Expand Down Expand Up @@ -96,24 +84,4 @@ public bool ForceRegenerateSnapshots
// <remarks>See GForge #9791</remarks>
// public bool MergeTypeProfiles { get; set; }
}

/// <summary>
/// Settings for defining the behaviour of the snapshot generator with respect to regenerating snapshots.
/// </summary>
public enum RegenerationSettings
{
/// <summary>
/// Try to use an existing snapshot, if available.
/// </summary>
TRY_USE_EXISTING,
/// <summary>
/// Regenerate the snapshot once, to ensure it is up-to-date.
/// </summary>
REGENERATE_ONCE,
/// <summary>
/// Regenerate the snapshot every time. This is useful for debugging and testing purposes.
/// </summary>
[Obsolete("Watch out when using this setting! it could lead to infinite recursion and is mainly meant for debugging and testing purposes. If you previously had ForceRegenerateSnapshots set to true, consider using REGENERATE_ONCE instead.")]
FORCE_REGENERATE,
}
}
Loading

0 comments on commit a26298c

Please sign in to comment.