Skip to content

Commit

Permalink
Merge pull request #7 from FirelyTeam/feature/support-for-generating-…
Browse files Browse the repository at this point in the history
…resourcereference-on-choice-types

Produce ResourceReference attributes for choice types
  • Loading branch information
ewoutkramer authored May 17, 2021
2 parents a08d61e + ebd29c1 commit 07bfc7f
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 50 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,4 @@ msbuild.wrn
/cytoscape
/fhirVersions/local-*
/generated/local_*
/fhirVersions
127 changes: 81 additions & 46 deletions src/Microsoft.Health.Fhir.SpecManager/Language/CSharpFirely2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ public sealed class CSharpFirely2 : ILanguage
"ValueSet", */
};

private static readonly string[] _allCommonTypes = _commmonComplexTypes
.Concat(_commmonResourceTypes)
.Concat(_commonR5DataTypes.Select(r5dt => r5dt.FhirName)).ToArray();

private static readonly List<string> _commonValueSets = new List<string>()
{
"http://hl7.org/fhir/ValueSet/filter-operator",
Expand Down Expand Up @@ -1480,6 +1484,7 @@ private void WriteCodedElement(

BuildElementOptionals(
element,
subset,
out string summary,
out string choice,
out string allowedTypes,
Expand Down Expand Up @@ -1668,6 +1673,7 @@ private void WriteElement(

BuildElementOptionals(
element,
subset,
out string summary,
out string choice,
out string allowedTypes,
Expand Down Expand Up @@ -1697,17 +1703,24 @@ private void WriteElement(
_writer.WriteLineIndented($"[DeclaredType(Type = typeof(Canonical), Since = FhirRelease.R4)]");
}

if ((!string.IsNullOrEmpty(resourceReferences)) && string.IsNullOrEmpty(allowedTypes))
// Generate the [AllowedTypes] and [ResourceReference] attributes, except when we are
// generating datatypes and resources in Common, since this list probably contains
// classes that we have not yet moved to common.
bool notClsCompliant = !string.IsNullOrEmpty(allowedTypes) ||
!string.IsNullOrEmpty(resourceReferences);

if (notClsCompliant)
{
_writer.WriteLineIndented("[CLSCompliant(false)]");
}

if (!string.IsNullOrEmpty(resourceReferences))
{
_writer.WriteLineIndented(resourceReferences);
}

// Generate the [AllowedTypes] attribute, except when we are generating datatypes and resources
// in Common, since this list probably contains classes that we have not yet moved to common.
if (!string.IsNullOrEmpty(allowedTypes) && !subset.HasFlag(GenSubset.Common))
if (!string.IsNullOrEmpty(allowedTypes))
{
_writer.WriteLineIndented("[CLSCompliant(false)]");
_writer.WriteLineIndented(allowedTypes);
}

Expand Down Expand Up @@ -1967,6 +1980,7 @@ private string BuildTypeFromPath(string type)
/// <param name="resourceReferences">[out] The resource references.</param>
private void BuildElementOptionals(
FhirElement element,
GenSubset subset,
out string summary,
out string choice,
out string allowedTypes,
Expand All @@ -1975,9 +1989,10 @@ private void BuildElementOptionals(
choice = string.Empty;
allowedTypes = string.Empty;
resourceReferences = string.Empty;

summary = element.IsSummary ? ", InSummary=true" : string.Empty;

bool inCommon = subset.HasFlag(GenSubset.Common);

if (element.ElementTypes != null)
{
if (element.ElementTypes.Count == 1)
Expand Down Expand Up @@ -2005,68 +2020,88 @@ private void BuildElementOptionals(
choice = ", Choice=ChoiceType.ResourceChoice";
}

StringBuilder sb = new StringBuilder();
sb.Append("[AllowedTypes(");

bool needsSep = false;
foreach (FhirElementType elementType in element.ElementTypes.Values)
// When we generating classes in Common, we have to avoid generating an
// [AllowedTypes] attribute that contains class names that are not
// present in the current version of the standard. So, in principle, we don't generate
// this attribute in Common, unless all types mentioned are present in the
// exception list above.
if (!inCommon || element.ElementTypes.Values
.Select(v => v.Name)
.All(en => _allCommonTypes.Contains(en)))
{
if (needsSep)
StringBuilder sb = new StringBuilder();
sb.Append("[AllowedTypes(");

bool needsSep = false;
foreach (FhirElementType elementType in element.ElementTypes.Values)
{
sb.Append(",");
}
if (needsSep)
{
sb.Append(",");
}

needsSep = true;
needsSep = true;

sb.Append("typeof(");
sb.Append(Namespace);
sb.Append(".");
sb.Append("typeof(");
sb.Append(Namespace);
sb.Append(".");

if (CSharpFirelyCommon.TypeNameMappings.ContainsKey(elementType.Name))
{
sb.Append(CSharpFirelyCommon.TypeNameMappings[elementType.Name]);
}
else
{
sb.Append(FhirUtils.SanitizedToConvention(elementType.Name, FhirTypeBase.NamingConvention.PascalCase));
if (CSharpFirelyCommon.TypeNameMappings.ContainsKey(elementType.Name))
{
sb.Append(CSharpFirelyCommon.TypeNameMappings[elementType.Name]);
}
else
{
sb.Append(FhirUtils.SanitizedToConvention(elementType.Name, FhirTypeBase.NamingConvention.PascalCase));
}

sb.Append(")");
}

sb.Append(")");
sb.Append(")]");
allowedTypes = sb.ToString();
}

sb.Append(")]");
allowedTypes = sb.ToString();
}
}

if (element.ElementTypes != null)
{
foreach (FhirElementType elementType in element.ElementTypes.Values)
{
if (elementType.Name == "Reference" && elementType.Profiles.Values.Any())
if (elementType.Name == "Reference" && elementType.Profiles.Any())
{
StringBuilder sb = new StringBuilder();
sb.Append("[References(");

bool needsSep = false;
foreach (FhirElementProfile profile in elementType.Profiles.Values)
// When we generating classes in Common, we have to avoid generating an
// [ResourceReference] attribute that contains class names that are not
// present in the current version of the standard. So, in principle, we don't generate
// this attribute in Common, unless all types mentioned are present in the
// exception list above.
if (!inCommon || elementType.Profiles.Values
.Select(v => v.Name)
.All(en => _allCommonTypes.Contains(en)))
{
if (needsSep)
StringBuilder sb = new StringBuilder();
sb.Append("[References(");

bool needsSep = false;
foreach (FhirElementProfile profile in elementType.Profiles.Values)
{
sb.Append(",");
}
if (needsSep)
{
sb.Append(",");
}

needsSep = true;
needsSep = true;

sb.Append("\"");
sb.Append(profile.Name);
sb.Append("\"");
}
sb.Append("\"");
sb.Append(profile.Name);
sb.Append("\"");
}

sb.Append(")]");
resourceReferences = sb.ToString();
sb.Append(")]");
resourceReferences = sb.ToString();

break;
break;
}
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/fhir-codegen-cli/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
},
"Firely 1.x R5": {
"commandName": "Project",
"commandLineArgs": "--output-path ..\\..\\..\\firely-net-sdk\\src\\Hl7.Fhir.Core\\Model --load-r5 latest --fhir-spec-directory ..\\..\\fhirVersions --language CSharpFirely --official-expansions-only true",
"commandLineArgs": "--output-path ..\\..\\..\\firely-net-sdk\\src\\Hl7.Fhir.Core\\Model --load-r5 4.5.0 --fhir-spec-directory ..\\..\\fhirVersions --language CSharpFirely --official-expansions-only true",
"workingDirectory": "$(MSBuildProjectDirectory)"
},
"Firely 2.x STU3": {
Expand All @@ -137,17 +137,17 @@
},
"Firely 2.x R5": {
"commandName": "Project",
"commandLineArgs": "--output-path ..\\..\\..\\firely-net-sdk\\src\\Hl7.Fhir.Core\\Model --load-r5 latest --fhir-spec-directory ..\\..\\fhirVersions --language CSharpFirely2 --official-expansions-only true",
"commandLineArgs": "--output-path ..\\..\\..\\firely-net-sdk\\src\\Hl7.Fhir.Core\\Model --load-r5 4.5.0 --fhir-spec-directory ..\\..\\fhirVersions --language CSharpFirely2 --official-expansions-only true",
"workingDirectory": "$(MSBuildProjectDirectory)"
},
"Firely 2.x Common": {
"commandName": "Project",
"commandLineArgs": "--output-path ..\\..\\..\\firely-net-sdk\\common\\src\\Hl7.Fhir.Support.Poco\\Model --load-r5 latest --fhir-spec-directory ..\\..\\fhirVersions --language CSharpFirely2 --language-options CSharpFirely2|subset=common --official-expansions-only true",
"commandLineArgs": "--output-path ..\\..\\..\\firely-net-sdk\\common\\src\\Hl7.Fhir.Support.Poco\\Model --load-r5 4.5.0 --fhir-spec-directory ..\\..\\fhirVersions --language CSharpFirely2 --language-options CSharpFirely2|subset=common --official-expansions-only true",
"workingDirectory": "$(MSBuildProjectDirectory)"
},
"FirelyAll": {
"commandName": "Project",
"commandLineArgs": "--output-path ..\\..\\firely --load-r2 latest --load-r3 latest --load-r4 latest --load-r5 latest --fhir-spec-directory ..\\..\\fhirVersions --language CSharpFirely --official-expansions-only true",
"commandLineArgs": "--output-path ..\\..\\firely --load-r2 latest --load-r3 latest --load-r4 latest --load-r5 4.5.0 --fhir-spec-directory ..\\..\\fhirVersions --language CSharpFirely --official-expansions-only true",
"workingDirectory": "$(MSBuildProjectDirectory)"
},
"server2": {
Expand Down

0 comments on commit 07bfc7f

Please sign in to comment.