Skip to content

Commit

Permalink
Improve Enum Parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
viceroypenguin committed Nov 18, 2024
1 parent dfbf467 commit db9a7a8
Show file tree
Hide file tree
Showing 15 changed files with 140 additions and 47 deletions.
69 changes: 48 additions & 21 deletions src/Plaid.OpenApiParser/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Reflection;
using System.Reflection;
using System.Text.RegularExpressions;
using CaseExtensions;
using Microsoft.OpenApi.Any;
Expand Down Expand Up @@ -165,13 +165,14 @@ static string GetEnumName(string name) =>
BasePath = basePath,
Name = name,
Description = pd,
Properties = schema.Enum
Properties = GetEnumValues(schema)
.OfType<OpenApiString>()
.Select(e => new Property(
e.Value,
string.Empty,
GetEnumName(e.Value),
ed.GetValueOrDefault(e.Value)))
ed.GetValueOrDefault(e.Value)
))
.ToList(),
};
}
Expand Down Expand Up @@ -292,20 +293,19 @@ private static (string enumDescription, Dictionary<string, string> propertyDescr

private static string GetPropertyDescription(OpenApiSchema type)
{
var entityType = (type.Enum?.Any() ?? false) ? 2 : 1;
return
entityType == 2
? ParseEnumDescription(type.Description)
.enumDescription
: FixupDescription(type.Description);
var description = string.IsNullOrWhiteSpace(type.Description)
? type.AllOf.LastOrDefault()?.Description ?? ""
: type.Description;

return type.Enum is { Count: > 0 }
? ParseEnumDescription(description).enumDescription
: FixupDescription(description);
}

private static string GetPropertyType(string className, string propertyName, OpenApiSchema schema, SchemaType type)
{
if (schema.Type == "array")
{
return $"IReadOnlyList<{GetPropertyType(className, propertyName, schema.Items, type)}>";
}

if (schema.Type == "boolean")
return "bool";
Expand Down Expand Up @@ -333,25 +333,22 @@ private static string GetPropertyType(string className, string propertyName, Ope
}
}

var entityType = (schema.Enum?.Any() ?? false) ? SchemaType.Enum : type;
if (schema.Type == "string" && entityType != SchemaType.Enum)
if (schema.AllOf.FirstOrDefault(s => s.Enum is { Count: > 0 }) is { } enumSchema)
return GetPropertyType(className, propertyName, enumSchema, type);

var entityType = schema.Enum is { Count: > 0 } ? SchemaType.Enum : type;
if (schema.Type is "string" && entityType != SchemaType.Enum)
return "string";

if (schema.AllOf.Count == 1
&& schema.AllOf[0].Type == "string")
{
if (schema.AllOf is [{ Type: "string" }])
return "string";
}

if (schema.Reference != null)
{
if (schema.Reference.Id.EndsWith("Nullable", StringComparison.OrdinalIgnoreCase))
{
if (schema.AllOf.Count > 0)
{
var realType = schema.AllOf.First();
if (schema.AllOf is [{ } realType, ..])
return GetPropertyType(className, propertyName, realType, entityType);
}
}
else if (schema.AdditionalProperties != null)
return $"IReadOnlyDictionary<string, {GetPropertyType(className, propertyName, schema.AdditionalProperties, type)}>";
Expand Down Expand Up @@ -701,6 +698,36 @@ private static string GetTemplate(string templateName)
using var reader = new StreamReader(stream);
return reader.ReadToEnd();
}

private static bool IsEnum(OpenApiSchema schema)
{
if (schema.Enum is { Count: > 0 })
return true;

foreach (var s in schema.AllOf)
{
if (IsEnum(s))
return true;
}

return false;
}

private static IList<IOpenApiAny> GetEnumValues(OpenApiSchema schema)
{
if (schema.Enum is not null)
{
return schema.Enum;
}

foreach (var s in schema.AllOf)
{
if (GetEnumValues(s) is { Count: > 0 } values)
return values;
}

return [];
}
}

internal enum SchemaType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ namespace Going.Plaid.Entity;
public class LinkTokenCreateRequestIdentityVerification
{
/// <summary>
///
/// <para>ID of the associated Identity Verification template.</para>
/// </summary>
[JsonPropertyName("template_id")]
public string TemplateId { get; set; } = default!;

/// <summary>
///
/// <para>A flag specifying whether the end user has already agreed to a privacy policy specifying that their data will be shared with Plaid for verification purposes.</para>
/// <para>If <c>gave_consent</c> is set to <c>true</c>, the <c>accept_tos</c> step will be marked as <c>skipped</c> and the end user's session will start at the next step requirement.</para>
/// </summary>
[JsonPropertyName("consent")]
public Entity.LinkTokenCreateRequestIdentityVerificationConsentObject? Consent { get; set; } = default!;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
namespace Going.Plaid.Entity;

/// <summary>
///
/// <para>A flag specifying whether the end user has already agreed to a privacy policy specifying that their data will be shared with Plaid for verification purposes.</para>
/// <para>If <c>gave_consent</c> is set to <c>true</c>, the <c>accept_tos</c> step will be marked as <c>skipped</c> and the end user's session will start at the next step requirement.</para>
/// </summary>
public class LinkTokenCreateRequestIdentityVerificationConsentObject
{
Expand Down
6 changes: 3 additions & 3 deletions src/Plaid/Entity/LinkTokenCreateRequestUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class LinkTokenCreateRequestUser
public string? LegalName { get; set; } = default!;

/// <summary>
///
/// <para>The user's full name. Optional if using the <a href="https://plaid.com/docs/api/products/identity-verification">Identity Verification</a> product; if not using Identity Verification, this field is not allowed. Users will not be asked for their name when this field is provided.</para>
/// </summary>
[JsonPropertyName("name")]
public Entity.LinkTokenCreateRequestUserNameObject? Name { get; set; } = default!;
Expand Down Expand Up @@ -64,13 +64,13 @@ public class LinkTokenCreateRequestUser
public DateOnly? DateOfBirth { get; set; } = default!;

/// <summary>
///
/// <para>The user's address. Used only for Identity Verification. If provided, the user will not be shown fields to enter their address in the Identity Verification flow. May be omitted, but if not omitted, all fields marked as required must be provided.</para>
/// </summary>
[JsonPropertyName("address")]
public Entity.LinkTokenCreateRequestUserAddressObject? Address { get; set; } = default!;

/// <summary>
///
/// <para>The user's ID number. Used only for Identity Verification. If provided, the user will not be shown fields to enter their ID number in the Identity Verification flow. May be omitted, but if not omitted, all fields marked as required must be provided.</para>
/// </summary>
[JsonPropertyName("id_number")]
public Entity.LinkTokenCreateRequestUserIdNumberObject? IdNumber { get; set; } = default!;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Going.Plaid.Entity;

/// <summary>
///
/// <para>The user's address. Used only for Identity Verification. If provided, the user will not be shown fields to enter their address in the Identity Verification flow. May be omitted, but if not omitted, all fields marked as required must be provided.</para>
/// </summary>
public class LinkTokenCreateRequestUserAddressObject
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Going.Plaid.Entity;

/// <summary>
///
/// <para>The user's ID number. Used only for Identity Verification. If provided, the user will not be shown fields to enter their ID number in the Identity Verification flow. May be omitted, but if not omitted, all fields marked as required must be provided.</para>
/// </summary>
public class LinkTokenCreateRequestUserIdNumberObject
{
Expand Down
2 changes: 1 addition & 1 deletion src/Plaid/Entity/LinkTokenCreateRequestUserNameObject.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Going.Plaid.Entity;

/// <summary>
///
/// <para>The user's full name. Optional if using the <a href="https://plaid.com/docs/api/products/identity-verification">Identity Verification</a> product; if not using Identity Verification, this field is not allowed. Users will not be asked for their name when this field is provided.</para>
/// </summary>
public class LinkTokenCreateRequestUserNameObject
{
Expand Down
8 changes: 6 additions & 2 deletions src/Plaid/Entity/Transfer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,14 @@ public record Transfer
public IReadOnlyList<Entity.TransferExpectedSweepSettlementScheduleItem>? ExpectedSweepSettlementSchedule { get; init; } = default!;

/// <summary>
///
/// <para>This field is now deprecated. You may ignore it for transfers created on and after 12/01/2023.</para>
/// <para>Specifies the source of funds for the transfer. Only valid for <c>credit</c> transfers, and defaults to <c>sweep</c> if not specified. This field is not specified for <c>debit</c> transfers.</para>
/// <para><c>sweep</c> - Sweep funds from your funding account</para>
/// <para><c>prefunded_rtp_credits</c> - Use your prefunded RTP credit balance with Plaid</para>
/// <para><c>prefunded_ach_credits</c> - Use your prefunded ACH credit balance with Plaid</para>
/// </summary>
[JsonPropertyName("credit_funds_source")]
public string CreditFundsSource { get; init; } = default!;
public Entity.TransferCreditFundsSource CreditFundsSource { get; init; } = default!;

/// <summary>
/// <para>The amount to deduct from <c>transfer.amount</c> and distribute to the platform’s Ledger balance as a facilitator fee (decimal string with two digits of precision e.g. "10.00"). The remainder will go to the end-customer’s Ledger balance. This must be less than or equal to the <c>transfer.amount</c>.</para>
Expand Down
8 changes: 6 additions & 2 deletions src/Plaid/Entity/TransferAuthorizationProposedTransfer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,13 @@ public record TransferAuthorizationProposedTransfer
public string? OriginatorClientId { get; init; } = default!;

/// <summary>
///
/// <para>This field is now deprecated. You may ignore it for transfers created on and after 12/01/2023.</para>
/// <para>Specifies the source of funds for the transfer. Only valid for <c>credit</c> transfers, and defaults to <c>sweep</c> if not specified. This field is not specified for <c>debit</c> transfers.</para>
/// <para><c>sweep</c> - Sweep funds from your funding account</para>
/// <para><c>prefunded_rtp_credits</c> - Use your prefunded RTP credit balance with Plaid</para>
/// <para><c>prefunded_ach_credits</c> - Use your prefunded ACH credit balance with Plaid</para>
/// </summary>
[JsonPropertyName("credit_funds_source")]
public string CreditFundsSource { get; init; } = default!;
public Entity.TransferCreditFundsSource CreditFundsSource { get; init; } = default!;

}
32 changes: 32 additions & 0 deletions src/Plaid/Entity/TransferCreditFundsSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace Going.Plaid.Entity;

/// <summary>
/// <para>This field is now deprecated. You may ignore it for transfers created on and after 12/01/2023.</para>
/// </summary>
public enum TransferCreditFundsSource
{
/// <summary>
/// <para>Sweep funds from your funding account</para>
/// </summary>
[EnumMember(Value = "sweep")]
Sweep,

/// <summary>
/// <para>Use your prefunded RTP credit balance with Plaid</para>
/// </summary>
[EnumMember(Value = "prefunded_rtp_credits")]
PrefundedRtpCredits,

/// <summary>
/// <para>Use your prefunded ACH credit balance with Plaid</para>
/// </summary>
[EnumMember(Value = "prefunded_ach_credits")]
PrefundedAchCredits,

/// <summary>
/// <para>Catch-all for unknown values returned by Plaid. If you encounter this, please check if there is a later version of the Going.Plaid library.</para>
/// </summary>
[EnumMember(Value = "undefined")]
Undefined,

}
2 changes: 1 addition & 1 deletion src/Plaid/Income/IncomeVerificationPrecheckRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public partial class IncomeVerificationPrecheckRequest : RequestBase
public Entity.IncomeVerificationPrecheckPayrollInstitution? PayrollInstitution { get; set; } = default!;

/// <summary>
///
/// <para>The access token associated with the Item data is being requested for.</para>
/// </summary>
[JsonPropertyName("transactions_access_token")]
public string? TransactionsAccessToken { get; set; } = default!;
Expand Down
12 changes: 10 additions & 2 deletions src/Plaid/Link/LinkTokenCreateRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,18 @@ public partial class LinkTokenCreateRequest : RequestBase
public Entity.LinkTokenCreateRequestCraOptions? CraOptions { get; set; } = default!;

/// <summary>
///
/// <para>Describes the reason you are generating a Consumer Report for this user. This parameter is required if you want to generate a Consumer Report for the user automatically after the Link session. If you omit this parameter during Link token creation, you can later call the <c>/cra/check_report/create</c> endpoint to generate a report.</para>
/// <para><c>ACCOUNT_REVIEW_CREDIT</c>: In connection with a consumer credit transaction for the review or collection of an account pursuant to FCRA Section 604(a)(3)(A).</para>
/// <para><c>ACCOUNT_REVIEW_NON_CREDIT</c>: For a legitimate business need of the information to review a non-credit account provided primarily for personal, family, or household purposes to determine whether the consumer continues to meet the terms of the account pursuant to FCRA Section 604(a)(3)(F)(2).</para>
/// <para><c>EMPLOYMENT</c>: For employment purposes pursuant to FCRA 604(a)(3)(B), including hiring, retention and promotion purposes.</para>
/// <para><c>EXTENSION_OF_CREDIT</c>: In connection with a credit transaction initiated by and involving the consumer pursuant to FCRA Section 604(a)(3)(A).</para>
/// <para><c>LEGITIMATE_BUSINESS_NEED_TENANT_SCREENING</c>: For a legitimate business need in connection with a business transaction initiated by the consumer primarily for personal, family, or household purposes in connection with a property rental assessment pursuant to FCRA Section 604(a)(3)(F)(i).</para>
/// <para><c>LEGITIMATE_BUSINESS_NEED_OTHER</c>: For a legitimate business need in connection with a business transaction made primarily for personal, family, or household initiated by the consumer pursuant to FCRA Section 604(a)(3)(F)(i).</para>
/// <para><c>WRITTEN_INSTRUCTION_PREQUALIFICATION</c>: In accordance with the written instructions of the consumer pursuant to FCRA Section 604(a)(2), to evaluate an application’s profile to make an offer to the consumer.</para>
/// <para><c>WRITTEN_INSTRUCTION_OTHER</c>: In accordance with the written instructions of the consumer pursuant to FCRA Section 604(a)(2), such as when an individual agrees to act as a guarantor or assumes personal liability for a consumer, business, or commercial loan.</para>
/// </summary>
[JsonPropertyName("consumer_report_permissible_purpose")]
public Entity.LinkTokenCreateRequestConsumerReportPermissiblePurposeObject? ConsumerReportPermissiblePurpose { get; set; } = default!;
public Entity.ConsumerReportPermissiblePurpose? ConsumerReportPermissiblePurpose { get; set; } = default!;

/// <summary>
/// <para>Specifies options for initializing Link for use with the Auth product. This field can be used to enable or disable extended Auth flows for the resulting Link session. Omitting any field will result in a default that can be configured by your account manager. The default behavior described in the documentation is the default behavior that will apply if you have not requested your account manager to apply a different default.</para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@ public partial class PaymentInitiationConsentPaymentExecuteRequest : RequestBase
public string? Reference { get; set; } = default!;

/// <summary>
///
/// <para>Deprecated, payments will be executed within the type of the consent. </para>
/// <para>A scope of the payment. Must be one of the scopes mentioned in the consent. </para>
/// <para>Optional if the appropriate consent has only one scope defined, required otherwise.</para>
/// </summary>
[JsonPropertyName("scope")]
public Entity.PaymentInitiationConsentPaymentExecuteRequestScopeObject? Scope { get; set; } = default!;
public Entity.PaymentInitiationConsentScope? Scope { get; set; } = default!;

/// <summary>
/// <para>Decides the mode under which the payment processing should be performed, using <c>IMMEDIATE</c> as default.</para>
Expand Down
8 changes: 6 additions & 2 deletions src/Plaid/Transfer/TransferAuthorizationCreateRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,14 @@ public partial class TransferAuthorizationCreateRequest : RequestBase
public string? OriginatorClientId { get; set; } = default!;

/// <summary>
///
/// <para>This field is now deprecated. You may ignore it for transfers created on and after 12/01/2023.</para>
/// <para>Specifies the source of funds for the transfer. Only valid for <c>credit</c> transfers, and defaults to <c>sweep</c> if not specified. This field is not specified for <c>debit</c> transfers.</para>
/// <para><c>sweep</c> - Sweep funds from your funding account</para>
/// <para><c>prefunded_rtp_credits</c> - Use your prefunded RTP credit balance with Plaid</para>
/// <para><c>prefunded_ach_credits</c> - Use your prefunded ACH credit balance with Plaid</para>
/// </summary>
[JsonPropertyName("credit_funds_source")]
public string? CreditFundsSource { get; set; } = default!;
public Entity.TransferCreditFundsSource? CreditFundsSource { get; set; } = default!;

/// <summary>
/// <para>Plaid’s unique identifier for a test clock. This field may only be used when using <c>sandbox</c> environment. If provided, the <c>authorization</c> is created at the <c>virtual_time</c> on the provided test clock.</para>
Expand Down
Loading

0 comments on commit db9a7a8

Please sign in to comment.