Skip to content

Commit c199c61

Browse files
committed
Lazily resolve contract property types and default values to make use of the new symbol name resolver (This tempoarily disables unused contract validation)
1 parent 2b124ee commit c199c61

6 files changed

Lines changed: 122 additions & 144 deletions

File tree

src/Dibix.Sdk/CodeGeneration/Model/CodeGenerationModelLoader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ string projectName
7777
IDictionary<string, SecurityScheme> securitySchemeMap = new Dictionary<string, SecurityScheme>();
7878

7979
ISchemaProvider builtInSchemaProvider = new BuiltInSchemaProvider();
80-
IContractDefinitionProvider contractDefinitionProvider = new ContractDefinitionProvider(fileSystemProvider, logger, normalizedContracts, productName, areaName);
80+
IContractDefinitionProvider contractDefinitionProvider = new ContractDefinitionProvider(fileSystemProvider, typeResolver, logger, normalizedContracts, productName, areaName);
8181
IUserDefinedTypeProvider userDefinedTypeProvider = new UserDefinedTypeProvider(rootNamespace, productName, areaName, normalizedSources, typeResolver, logger);
8282
//ISchemaProvider externalSchemaProvider = new ExternalSchemaProvider(assemblyResolver);
8383
schemaRegistry.ImportSchemas(builtInSchemaProvider, contractDefinitionProvider, userDefinedTypeProvider/*, externalSchemaProvider*/);

src/Dibix.Sdk/CodeGeneration/Model/ContractDefinition.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ public sealed class ContractDefinition
66
public string FilePath { get; }
77
public int Line { get; }
88
public int Column { get; }
9-
public bool HasReferences { get; internal set; }
109

1110
public ContractDefinition(SchemaDefinition schema, string filePath, int line, int column)
1211
{

src/Dibix.Sdk/CodeGeneration/Model/ContractDefinitionProvider.cs

Lines changed: 35 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ internal sealed class ContractDefinitionProvider : JsonSchemaDefinitionReader, I
1313
{
1414
#region Fields
1515
private const string RootFolderName = "Contracts";
16+
private readonly ITypeResolverFacade _typeResolver;
1617
private readonly string _productName;
1718
private readonly string _areaName;
1819
private readonly IDictionary<string, ContractDefinition> _contracts;
19-
private readonly ICollection<string> _referencedContracts;
2020
#endregion
2121

2222
#region Properties
@@ -26,13 +26,13 @@ internal sealed class ContractDefinitionProvider : JsonSchemaDefinitionReader, I
2626
#endregion
2727

2828
#region Constructor
29-
public ContractDefinitionProvider(IFileSystemProvider fileSystemProvider, ILogger logger, IEnumerable<string> contracts, string productName, string areaName) : base(fileSystemProvider, logger)
29+
public ContractDefinitionProvider(IFileSystemProvider fileSystemProvider, ITypeResolverFacade typeResolver, ILogger logger, IEnumerable<string> contracts, string productName, string areaName) : base(fileSystemProvider, logger)
3030
{
31+
this._typeResolver = typeResolver;
3132
this._productName = productName;
3233
this._areaName = areaName;
3334
this._contracts = new Dictionary<string, ContractDefinition>();
34-
this._referencedContracts = new HashSet<string>();
35-
this.CollectCore(contracts);
35+
base.Collect(contracts);
3636
}
3737
#endregion
3838

@@ -44,8 +44,6 @@ public bool TryGetSchema(string fullName, out SchemaDefinition schema)
4444
schema = null;
4545
return false;
4646
}
47-
48-
contract.HasReferences = true;
4947
schema = contract.Schema;
5048
return true;
5149
}
@@ -67,34 +65,25 @@ protected override void Read(string filePath, JObject json)
6765
string relativeNamespace = String.Join(".", parts.Skip(1));
6866
NamespacePath currentNamespace = PathUtility.BuildAbsoluteNamespace(this._productName, this._areaName, LayerName.DomainModel, relativeNamespace);
6967

70-
string root = multipleAreas ? parts[1] : null;
71-
NamespacePath rootNamespace = PathUtility.BuildAbsoluteNamespace(this._productName, this._areaName, LayerName.DomainModel, relativeNamespace: root);
72-
73-
this.ReadContracts(rootNamespace, currentNamespace, json, filePath);
68+
this.ReadContracts(currentNamespace, relativeNamespace, json, filePath);
7469
}
7570
#endregion
7671

7772
#region Private Methods
78-
private void CollectCore(IEnumerable<string> contracts)
79-
{
80-
base.Collect(contracts);
81-
this.CollectReferenceCounts();
82-
}
83-
84-
private void ReadContracts(NamespacePath rootNamespace, NamespacePath currentNamespace, JObject contracts, string filePath)
73+
private void ReadContracts(NamespacePath currentNamespace, string relativeNamespace, JObject contracts, string filePath)
8574
{
8675
foreach (JProperty definitionProperty in contracts.Properties())
8776
{
88-
this.ReadContract(rootNamespace, currentNamespace, definitionProperty.Name, definitionProperty.Value, filePath, definitionProperty.GetLineInfo());
77+
this.ReadContract(currentNamespace, relativeNamespace, definitionProperty.Name, definitionProperty.Value, filePath, definitionProperty.GetLineInfo());
8978
}
9079
}
9180

92-
private void ReadContract(NamespacePath rootNamespace, NamespacePath currentNamespace, string definitionName, JToken value, string filePath, IJsonLineInfo lineInfo)
81+
private void ReadContract(NamespacePath currentNamespace, string relativeNamespace, string definitionName, JToken value, string filePath, IJsonLineInfo lineInfo)
9382
{
9483
switch (value.Type)
9584
{
9685
case JTokenType.Object:
97-
this.ReadObjectContract(rootNamespace, currentNamespace, definitionName, value, filePath, lineInfo);
86+
this.ReadObjectContract(currentNamespace, relativeNamespace, definitionName, value, filePath, lineInfo);
9887
break;
9988

10089
case JTokenType.Array:
@@ -106,7 +95,7 @@ private void ReadContract(NamespacePath rootNamespace, NamespacePath currentName
10695
}
10796
}
10897

109-
private void ReadObjectContract(NamespacePath rootNamespace, NamespacePath currentNamespace, string definitionName, JToken value, string filePath, IJsonLineInfo lineInfo)
98+
private void ReadObjectContract(NamespacePath currentNamespace, string relativeNamespace, string definitionName, JToken value, string filePath, IJsonLineInfo lineInfo)
11099
{
111100
ObjectSchema contract = new ObjectSchema(currentNamespace.Path, definitionName, SchemaDefinitionSource.Defined);
112101
foreach (JProperty property in ((JObject)value).Properties())
@@ -150,17 +139,34 @@ private void ReadObjectContract(NamespacePath rootNamespace, NamespacePath curre
150139
throw new ArgumentOutOfRangeException(nameof(property.Type), property.Type, null);
151140
}
152141

153-
TypeReference type = this.ParsePropertyType(typeName, rootNamespace, filePath, typeNameValue);
154-
ValueReference defaultValue = null;
155-
if (defaultValueJson != null)
142+
IJsonLineInfo propertyLineInfo = property.GetLineInfo();
143+
Token<string> propertyName = new Token<string>(property.Name, filePath, propertyLineInfo.LineNumber, propertyLineInfo.LinePosition);
144+
145+
TypeReference ResolveType()
156146
{
157-
IJsonLineInfo defaultValueLocation = defaultValueJson.GetLineInfo();
158-
defaultValue = JsonValueReferenceParser.Parse(type, defaultValueJson, filePath, defaultValueLocation, Logger);
147+
bool isEnumerable = typeName.EndsWith("*", StringComparison.Ordinal);
148+
typeName = typeName.TrimEnd('*');
149+
150+
// TODO: Remove support
151+
typeName = typeName.TrimStart('#');
152+
153+
IJsonLineInfo location = value.GetLineInfo();
154+
TypeReference type = this._typeResolver.ResolveType(typeName, relativeNamespace, filePath, location.LineNumber, location.LinePosition, isEnumerable);
155+
return type;
159156
}
160157

161-
IJsonLineInfo propertyLineInfo = property.GetLineInfo();
162-
Token<string> propertyName = new Token<string>(property.Name, filePath, propertyLineInfo.LineNumber, propertyLineInfo.LinePosition);
163-
ObjectSchemaProperty objectSchemaProperty = new ObjectSchemaProperty(propertyName, type, defaultValue, serializationBehavior, dateTimeKind, isPartOfKey, isOptional, isDiscriminator, isObfuscated, isRelativeHttpsUrl);
158+
ValueReference ResolveDefaultValue(TypeReference typeReference)
159+
{
160+
ValueReference defaultValue = null;
161+
if (defaultValueJson != null)
162+
{
163+
IJsonLineInfo defaultValueLocation = defaultValueJson.GetLineInfo();
164+
defaultValue = JsonValueReferenceParser.Parse(typeReference, defaultValueJson, filePath, defaultValueLocation, Logger);
165+
}
166+
return defaultValue;
167+
}
168+
169+
ObjectSchemaProperty objectSchemaProperty = new ObjectSchemaProperty(propertyName, ResolveType, ResolveDefaultValue, serializationBehavior, dateTimeKind, isPartOfKey, isOptional, isDiscriminator, isObfuscated, isRelativeHttpsUrl);
164170
contract.Properties.Add(objectSchemaProperty);
165171
}
166172
}
@@ -241,47 +247,6 @@ private static EnumValue ReadEnumValue(string name, JValue value, JTokenType typ
241247
default: throw new ArgumentOutOfRangeException(nameof(type), type, null);
242248
}
243249
}
244-
245-
private TypeReference ParsePropertyType(string typeName, NamespacePath rootNamespace, string filePath, JToken value)
246-
{
247-
bool isEnumerable = typeName.EndsWith("*", StringComparison.Ordinal);
248-
typeName = typeName.TrimEnd('*');
249-
250-
bool isNullable = typeName.EndsWith("?", StringComparison.Ordinal);
251-
typeName = typeName.TrimEnd('?');
252-
253-
bool isTypeReference = typeName.StartsWith("#", StringComparison.Ordinal);
254-
typeName = typeName.TrimStart('#');
255-
256-
IJsonLineInfo location = value.GetLineInfo();
257-
if (isTypeReference)
258-
{
259-
// TODO: Actually the contracts should have a namespace group, just like the procedures.
260-
// The folder itself should not indicate a namespace (just like in C#).
261-
// Therefore a namespace property should be added to the contract schema.
262-
// This would however introduce a breaking change, since in C#, when you are within a namespace group,
263-
// and you want to reference a type from outside of the namespace, an absolute namespace must be used.
264-
string key = $"{rootNamespace}.{typeName}";
265-
this._referencedContracts.Add(key);
266-
return new SchemaTypeReference(key, isNullable, isEnumerable, filePath, location.LineNumber, location.LinePosition);
267-
}
268-
269-
PrimitiveType dataType = (PrimitiveType)Enum.Parse(typeof(PrimitiveType), typeName, ignoreCase: true /* JSON is camelCase while C# is PascalCase */);
270-
return new PrimitiveTypeReference(dataType, isNullable, isEnumerable, filePath, location.LineNumber, location.LinePosition);
271-
}
272-
273-
private void CollectReferenceCounts()
274-
{
275-
foreach (string name in this._referencedContracts)
276-
{
277-
if (!this._contracts.TryGetValue(name, out ContractDefinition contractDefinition))
278-
{
279-
// The contract is quite possibly not defined in this project
280-
continue;
281-
}
282-
contractDefinition.HasReferences = true;
283-
}
284-
}
285250
#endregion
286251

287252
#region Nested types

src/Dibix.Sdk/CodeGeneration/Model/ObjectSchemaProperty.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ namespace Dibix.Sdk.CodeGeneration
44
{
55
public sealed class ObjectSchemaProperty
66
{
7+
private readonly Lazy<TypeReference> _typeResolver;
8+
private readonly Lazy<ValueReference> _defaultValueResolver;
9+
710
public Token<string> Name { get; }
8-
public TypeReference Type { get; }
9-
public ValueReference DefaultValue { get; }
11+
public TypeReference Type => this._typeResolver.Value;
12+
public ValueReference DefaultValue => this._defaultValueResolver.Value;
1013
public DateTimeKind DateTimeKind { get; }
1114
public SerializationBehavior SerializationBehavior { get; }
1215
public bool IsPartOfKey { get; }
@@ -15,11 +18,12 @@ public sealed class ObjectSchemaProperty
1518
public bool IsObfuscated { get; }
1619
public bool IsRelativeHttpsUrl { get; }
1720

18-
public ObjectSchemaProperty(Token<string> name, TypeReference type, ValueReference defaultValue = default, SerializationBehavior serializationBehavior = default, DateTimeKind dateTimeKind = default, bool isPartOfKey = default, bool isOptional = default, bool isDiscriminator = default, bool isObfuscated = default, bool isRelativeHttpsUrl = default)
21+
public ObjectSchemaProperty(Token<string> name, TypeReference type, ValueReference defaultValue = default, SerializationBehavior serializationBehavior = default, DateTimeKind dateTimeKind = default, bool isPartOfKey = default, bool isOptional = default, bool isDiscriminator = default, bool isObfuscated = default, bool isRelativeHttpsUrl = default) : this(name, () => type, _ => defaultValue, serializationBehavior, dateTimeKind, isPartOfKey, isOptional, isDiscriminator, isObfuscated, isRelativeHttpsUrl) { }
22+
internal ObjectSchemaProperty(Token<string> name, Func<TypeReference> typeResolver, Func<TypeReference, ValueReference> defaultValueResolver, SerializationBehavior serializationBehavior, DateTimeKind dateTimeKind, bool isPartOfKey, bool isOptional, bool isDiscriminator, bool isObfuscated, bool isRelativeHttpsUrl)
1923
{
24+
this._typeResolver = new Lazy<TypeReference>(typeResolver);
25+
this._defaultValueResolver = new Lazy<ValueReference>(() => defaultValueResolver(this.Type));
2026
this.Name = name;
21-
this.Type = type;
22-
this.DefaultValue = defaultValue;
2327
this.DateTimeKind = dateTimeKind;
2428
this.SerializationBehavior = !isDiscriminator ? serializationBehavior : SerializationBehavior.Never;
2529
this.IsPartOfKey = isPartOfKey;

0 commit comments

Comments
 (0)