NeVeSpl / NTypewriter

File/code generator using Scriban text templates populated with C# code metadata from Roslyn API.
https://nevespl.github.io/NTypewriter/
MIT License
122 stars 25 forks source link

Attributes generate values that are region dependent #78

Closed ChaseGrant closed 1 year ago

ChaseGrant commented 1 year ago

I am generating TypeScript from our C# classes that include the attributes from C# as comments before the properties and we are having problems with the decimals using the local machine's regional settings for the number instead of a fixed (or defined) format.

Would it be possible to either specify the culture used to convert the values (or globally) or to enable the invariant conversion?

The code I am using to generate the attributes is as follows in the .nt file:

    if property.Attributes | Array.Size > 0
        for attribute in property.Attributes
            for argument in attribute.Arguments }}
    //{{ attribute.Name }}({{ argument }})
            {{- end
        end
    end }}

It generates like this on my machine (decimal separator set to ","):

    //Range(minimum : 0)
    //Range(maximum : 1,79769313486232E+308)

And like this on another machine (decimal separator set to "."):

    //Range(minimum : 0)
    //Range(maximum : 1.79769313486232E+308)
NeVeSpl commented 1 year ago

Have you tried to use argument.Value property? IAttributeArgument.Value it should contain the typed value of the argument, in that case double probably, and not its string representation.

ChaseGrant commented 1 year ago

I suspect something further down (possibly in the Scriban layer) is re-translating the string output by NTypeWriter into a localized version.

This works just fine in LINQPad:

object x = double.MaxValue;
Convert.ToString( x, CultureInfo.InvariantCulture ).Dump();
double.MaxValue.ToString( CultureInfo.InvariantCulture ).Dump();

Result:

1.79769313486232E+308
1.79769313486232E+308

But this code in NTypeWriter custom functions:

        public static string GetValueInvariant ( IAttributeArgument attributeArgument )
        {
            return Convert.ToString( attributeArgument.Value, CultureInfo.InvariantCulture );
        }
//{{ attribute.Name }}({{ argument | Custom.GetValueInvariant }})

Returns:

//Range(1,79769313486232E+308)
NeVeSpl commented 1 year ago

I have checked and IAttributeArgument.Value unfortunately is also a string, but it will be fixed in the next release and will return original value and not a string representation.