corvus-dotnet / Corvus.JsonSchema

Support for Json Schema validation and entity generation
Apache License 2.0
98 stars 9 forks source link

Provide access to pattern regular expressions in generated types #392

Closed coldacid closed 3 weeks ago

coldacid commented 1 month ago

For schemas which include a pattern, the code generator generates a Regex object inside the generated type for the schema. However, the regular expression is not available to consumers of the generated type in any form, meaning that developers would have to duplicate the regex if they need it for additional parsing of the value expressed by the schema. I request that the schema's pattern value be made available in some form on the generated type, whether as the pattern string itself, or (more preferably) either as a static Regex property on the generated type or via a Match() method on the type which would return the result of the regex's Matches() method.

As a workaround, for now I am taking advantage of the fact that all types generated by the code generator are partial, allowing me to set up what I need in an additional handwritten code file, but it would be greatly appreciated if this could come right out of code generation itself.

mwadams commented 1 month ago

This is interesting. Can you post a code snippet showing what you are adding to your partial? (Also :+1: for using the partials the way they were intended!)

coldacid commented 1 month ago

Sure...

public readonly partial struct PatternedString : IJsonStringWithPattern
{
    public static Regex Pattern => __CorvusPatternExpression;

    public MatchCollection GetPatternMatches()
    {
        if (this.ValueKind == ValueKind.String && __CorvusPatternExpression != null)
        {
            return __CorvusPatternExpression.Matches((string)this.AsString);
        }
        throw new InvalidOperationException();
    }
}

Because I actually have a schema in my project with multiple pattern-using anyOf subschemas, I defined an interface IJsonStringWithPattern defining the GetPatternMatches() method. I think there's definitely room for improvement on the method (since it should be known at code generation time to only build these for string types with a pattern anyway).

coldacid commented 1 month ago

It might also be useful to provide a GetPatternMatches() method on the schema containing anyOf subschemas using patterns, but for now I've not done that myself to avoid any headaches that might come with handling cases where the actual value is not a string or does not have a pattern.

mwadams commented 1 month ago

vNext will expose a public type which gives you all the validation constants on your type in one handy place. You can also access all the individual validation methods for the capabilities - these are internal so only available to you in the assembly in which the partial is emitted (or, obviously, in partial extensions you create.)

    /// <summary>
    /// Validation constants for the type.
    /// </summary>
    public static partial class CorvusValidation
    {
        /// <summary>
        /// A regular expression for the <c>pattern</c> keyword.
        /// </summary>
        public static readonly Regex Pattern = CreatePattern();

        /// <summary>
        /// String validation.
        /// </summary>
        /// <param name="value">The value to validate.</param>
        /// <param name="valueKind">The <see cref="JsonValueKind" /> of the value to validate.</param>
        /// <param name="validationContext">The current validation context.</param>
        /// <param name="level">The current validation level.</param>
        /// <returns>The resulting validation context after validation.</returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static ValidationContext StringValidationHandler(
            in Schema value,
            JsonValueKind valueKind,
            in ValidationContext validationContext,
            ValidationLevel level = ValidationLevel.Flag)
        {
        }
}
mwadams commented 3 weeks ago

Fixed in #393 - please try the Preview packages on nuget.

coldacid commented 3 weeks ago

@mwadams works for me in 4.0.0-preview.4, thanks!