mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-17 06:29:57 +02:00
Update Handlebars Transformer logic (ReplaceNodeOptions) (#1036)
* Update Handlebars Transformer logic (ReplaceNodeOptions) * okeee * EvaluateAndKeep = Evaluate * fix? * linux * _ * tt * xxx * fx * x * fix test
This commit is contained in:
@@ -7,19 +7,16 @@ public enum ReplaceNodeOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Try to evaluate a templated value.
|
||||
/// In case this is valid, return the value and if the value can be converted to a primitive type, use that value.
|
||||
/// In case this is valid, return the value and if the value can be converted to a supported (primitive) type, use that value.
|
||||
///
|
||||
/// [Default behaviour]
|
||||
/// </summary>
|
||||
EvaluateAndTryToConvert = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Try to evaluate a templated value.
|
||||
/// In case this is valid, return the value, else fallback to the parse behavior.
|
||||
/// Parse templated string to a templated string.
|
||||
/// For example: keep a templated string value (which is always the case) as a string value.
|
||||
/// </summary>
|
||||
Evaluate = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Parse templated string to a templated string.
|
||||
/// (keep a templated string value as string value).
|
||||
/// </summary>
|
||||
Parse = 2
|
||||
EvaluateAndKeep = Evaluate
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using JsonConverter.Abstractions;
|
||||
using WireMock.Matchers;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Util;
|
||||
|
||||
namespace WireMock.RequestBuilders;
|
||||
|
||||
@@ -29,5 +29,5 @@ public interface ITransformResponseBuilder : IDelayResponseBuilder
|
||||
/// <returns>
|
||||
/// The <see cref="IResponseBuilder"/>.
|
||||
/// </returns>
|
||||
IResponseBuilder WithTransformer(TransformerType transformerType = TransformerType.Handlebars, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.Evaluate);
|
||||
IResponseBuilder WithTransformer(TransformerType transformerType = TransformerType.Handlebars, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.EvaluateAndTryToConvert);
|
||||
}
|
||||
@@ -205,7 +205,7 @@ public partial class Response : IResponseBuilder
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IResponseBuilder WithTransformer(TransformerType transformerType, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.Evaluate)
|
||||
public IResponseBuilder WithTransformer(TransformerType transformerType, bool transformContentFromBodyAsFile = false, ReplaceNodeOptions options = ReplaceNodeOptions.EvaluateAndTryToConvert)
|
||||
{
|
||||
UseTransformer = true;
|
||||
TransformerType = transformerType;
|
||||
|
||||
@@ -39,7 +39,7 @@ internal static class WebhookMapper
|
||||
|
||||
if (!Enum.TryParse<ReplaceNodeOptions>(model.Request.TransformerReplaceNodeOptions, out var option))
|
||||
{
|
||||
option = ReplaceNodeOptions.Evaluate;
|
||||
option = ReplaceNodeOptions.EvaluateAndTryToConvert;
|
||||
}
|
||||
webhook.Request.TransformerReplaceNodeOptions = option;
|
||||
}
|
||||
|
||||
@@ -264,14 +264,16 @@ public partial class WireMockServer
|
||||
transformerType = TransformerType.Handlebars;
|
||||
}
|
||||
|
||||
if (!Enum.TryParse<ReplaceNodeOptions>(responseModel.TransformerReplaceNodeOptions, out var option))
|
||||
if (!Enum.TryParse<ReplaceNodeOptions>(responseModel.TransformerReplaceNodeOptions, out var replaceNodeOptions))
|
||||
{
|
||||
option = ReplaceNodeOptions.Evaluate;
|
||||
replaceNodeOptions = ReplaceNodeOptions.EvaluateAndTryToConvert;
|
||||
}
|
||||
|
||||
responseBuilder = responseBuilder.WithTransformer(
|
||||
transformerType,
|
||||
responseModel.UseTransformerForBodyAsFile == true,
|
||||
option);
|
||||
replaceNodeOptions
|
||||
);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(responseModel.ProxyUrl))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using HandlebarsDotNet.Helpers.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Stef.Validation;
|
||||
@@ -13,8 +13,6 @@ namespace WireMock.Transformers;
|
||||
|
||||
internal class Transformer : ITransformer
|
||||
{
|
||||
private static readonly Type[] SupportedTypes = { typeof(bool), typeof(long), typeof(int), typeof(double), typeof(Guid), typeof(DateTime), typeof(TimeSpan), typeof(Uri) };
|
||||
|
||||
private readonly JsonSerializer _jsonSerializer;
|
||||
private readonly ITransformerContextFactory _factory;
|
||||
|
||||
@@ -268,9 +266,10 @@ internal class Transformer : ITransformer
|
||||
return;
|
||||
|
||||
case string transformedString:
|
||||
if (TryConvert(transformedString, out var convertedFromStringValue))
|
||||
var (isConvertedFromString, convertedValueFromString) = TryConvert(options, transformedString);
|
||||
if (isConvertedFromString)
|
||||
{
|
||||
node.Replace(JToken.FromObject(convertedFromStringValue, _jsonSerializer));
|
||||
node.Replace(JToken.FromObject(convertedValueFromString, _jsonSerializer));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -292,7 +291,8 @@ internal class Transformer : ITransformer
|
||||
break;
|
||||
|
||||
case { }:
|
||||
if (TryConvert(transformedValue, out var convertedValue))
|
||||
var (isConverted, convertedValue) = TryConvert(options, transformedValue);
|
||||
if (isConverted)
|
||||
{
|
||||
node.Replace(JToken.FromObject(convertedValue, _jsonSerializer));
|
||||
}
|
||||
@@ -308,23 +308,28 @@ internal class Transformer : ITransformer
|
||||
return JsonUtils.TryParseAsJObject(stringValue, out var parsedAsjObject) ? parsedAsjObject : stringValue;
|
||||
}
|
||||
|
||||
private static bool TryConvert(object? transformedValue, [NotNullWhen(true)] out object? convertedValue)
|
||||
private static (bool IsConverted, object ConvertedValue) TryConvert(ReplaceNodeOptions options, object value)
|
||||
{
|
||||
foreach (var supportedType in SupportedTypes)
|
||||
var valueAsString = value as string;
|
||||
|
||||
if (options == ReplaceNodeOptions.Evaluate)
|
||||
{
|
||||
try
|
||||
if (valueAsString != null && WrappedString.TryDecode(valueAsString, out var decoded))
|
||||
{
|
||||
convertedValue = Convert.ChangeType(transformedValue, supportedType);
|
||||
return convertedValue is not null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore
|
||||
return (true, decoded);
|
||||
}
|
||||
|
||||
return (false, value);
|
||||
}
|
||||
|
||||
convertedValue = null;
|
||||
return false;
|
||||
if (valueAsString != null)
|
||||
{
|
||||
return WrappedString.TryDecode(valueAsString, out var decoded) ?
|
||||
(true, decoded) :
|
||||
StringUtils.TryConvertToKnownType(valueAsString);
|
||||
}
|
||||
|
||||
return (false, value);
|
||||
}
|
||||
|
||||
private static IBodyData TransformBodyAsString(ITransformerContext transformerContext, object model, IBodyData original)
|
||||
|
||||
@@ -8,6 +8,48 @@ namespace WireMock.Util;
|
||||
|
||||
internal static class StringUtils
|
||||
{
|
||||
private static readonly string[] ValidUriSchemes =
|
||||
{
|
||||
"ftp://",
|
||||
"http://",
|
||||
"https://"
|
||||
};
|
||||
|
||||
private static readonly Func<string, (bool IsConverted, object ConvertedValue)>[] ConversionsFunctions =
|
||||
{
|
||||
s => bool.TryParse(s, out var result) ? (true, result) : (false, s),
|
||||
s => int.TryParse(s, out var result) ? (true, result) : (false, s),
|
||||
s => long.TryParse(s, out var result) ? (true, result) : (false, s),
|
||||
s => double.TryParse(s, out var result) ? (true, result) : (false, s),
|
||||
s => Guid.TryParse(s, out var result) ? (true, result) : (false, s),
|
||||
s => TimeSpan.TryParse(s, out var result) ? (true, result) : (false, s),
|
||||
s => DateTime.TryParse(s, out var result) ? (true, result) : (false, s),
|
||||
s =>
|
||||
{
|
||||
if (ValidUriSchemes.Any(u => s.StartsWith(u, StringComparison.OrdinalIgnoreCase)) &&
|
||||
Uri.TryCreate(s, UriKind.RelativeOrAbsolute, out var uri))
|
||||
{
|
||||
return (true, uri);
|
||||
}
|
||||
|
||||
return (false, s);
|
||||
}
|
||||
};
|
||||
|
||||
public static (bool IsConverted, object ConvertedValue) TryConvertToKnownType(string value)
|
||||
{
|
||||
foreach (var func in ConversionsFunctions)
|
||||
{
|
||||
var result = func(value);
|
||||
if (result.IsConverted)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return (false, value);
|
||||
}
|
||||
|
||||
public static MatchOperator ParseMatchOperator(string? value)
|
||||
{
|
||||
return value != null && Enum.TryParse<MatchOperator>(value, out var matchOperator)
|
||||
|
||||
@@ -189,13 +189,13 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Handlebars.Net.Helpers" Version="2.4.1.2" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.4.1.2" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Humanizer" Version="2.4.1.2" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.4.1.2" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.4.1.2" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.4.1.2" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.4.1.2" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers" Version="2.4.1.4" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.DynamicLinq" Version="2.4.1.4" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Humanizer" Version="2.4.1.4" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Json" Version="2.4.1.4" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Random" Version="2.4.1.4" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.XPath" Version="2.4.1.4" />
|
||||
<PackageReference Include="Handlebars.Net.Helpers.Xeger" Version="2.4.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user