Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 3 additions & 121 deletions Fluid/Filters/MiscFilters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,61 +9,18 @@
using System.Threading.Tasks;
using System.Text;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Fluid.Filters
{
public static class MiscFilters
{
private static readonly string[] DefaultFormats = {
"yyyy-MM-ddTHH:mm:ss.FFF",
"yyyy-MM-ddTHH:mm:ss",
"yyyy-MM-ddTHH:mm",
"yyyy-MM-dd",
"yyyy-MM",
"yyyy"
};

private static readonly string[] SecondaryFormats = {
// Formats used in DatePrototype toString methods
"ddd MMM dd yyyy HH:mm:ss 'GMT'K",
"ddd MMM dd yyyy",
"HH:mm:ss 'GMT'K",

// standard formats
"yyyy-M-dTH:m:s.FFFK",
"yyyy/M/dTH:m:s.FFFK",
"yyyy-M-dTH:m:sK",
"yyyy/M/dTH:m:sK",
"yyyy-M-dTH:mK",
"yyyy/M/dTH:mK",
"yyyy-M-d H:m:s.FFFK",
"yyyy/M/d H:m:s.FFFK",
"yyyy-M-d H:m:sK",
"yyyy/M/d H:m:sK",
"yyyy-M-d H:mK",
"yyyy/M/d H:mK",
"yyyy-M-dK",
"yyyy/M/dK",
"yyyy-MK",
"yyyy/MK",
"yyyyK",
"THH:mm:ss.FFFK",
"THH:mm:ssK",
"THH:mmK",
"THHK"
};

private static readonly Regex HtmlCaseRegex =
new Regex(
"(?<!^)((?<=[a-zA-Z0-9])[A-Z][a-z])|((?<=[a-z])[A-Z])",
RegexOptions.None,
TimeSpan.FromMilliseconds(500));

private const string Now = "now";
private const string Today = "today";

public static FilterCollection WithMiscFilters(this FilterCollection filters)
{
filters.AddFilter("default", Default);
Expand Down Expand Up @@ -264,7 +221,7 @@ public static ValueTask<FluidValue> EscapeOnce(FluidValue input, FilterArguments

public static ValueTask<FluidValue> ChangeTimeZone(FluidValue input, FilterArguments arguments, TemplateContext context)
{
if (!TryGetDateTimeInput(input, context, out var value))
if (!input.TryGetDateTimeInput(context, out var value))
{
return NilValue.Instance;
}
Expand All @@ -285,7 +242,7 @@ public static ValueTask<FluidValue> ChangeTimeZone(FluidValue input, FilterArgum

public static ValueTask<FluidValue> Date(FluidValue input, FilterArguments arguments, TemplateContext context)
{
if (!TryGetDateTimeInput(input, context, out var value))
if (!input.TryGetDateTimeInput(context, out var value))
{
return NilValue.Instance;
}
Expand Down Expand Up @@ -520,7 +477,7 @@ void ForStrf(DateTimeOffset value, string format, StringBuilder result)

public static ValueTask<FluidValue> FormatDate(FluidValue input, FilterArguments arguments, TemplateContext context)
{
if (!TryGetDateTimeInput(input, context, out var value))
if (!input.TryGetDateTimeInput(context, out var value))
{
return NilValue.Instance;
}
Expand All @@ -542,81 +499,6 @@ public static ValueTask<FluidValue> FormatDate(FluidValue input, FilterArguments
return new StringValue(value.ToString(format, culture));
}

private static bool TryGetDateTimeInput(FluidValue input, TemplateContext context, out DateTimeOffset result)
{
result = context.Now();

if (input.Type == FluidValues.String)
{
var stringValue = input.ToStringValue();

if (stringValue == Now || stringValue == Today)
{
return true;
}
else
{
var success = true;

if (!DateTime.TryParseExact(stringValue, DefaultFormats, context.CultureInfo, DateTimeStyles.None, out var dateTime))
{
if (!DateTime.TryParseExact(stringValue, SecondaryFormats, context.CultureInfo, DateTimeStyles.None, out dateTime))
{
if (!DateTime.TryParse(stringValue, context.CultureInfo, DateTimeStyles.None, out dateTime))
{
if (!DateTime.TryParse(stringValue, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
{
success = false;
}
}
}
}

// If no timezone is specified, assume local using the configured timezone
if (success)
{
if (dateTime.Kind == DateTimeKind.Unspecified)
{
result = new DateTimeOffset(dateTime, context.TimeZone.GetUtcOffset(dateTime));
}
else
{
result = new DateTimeOffset(dateTime);
}
}

return success;
}
}
else if (input.Type == FluidValues.Number)
{
var dateTime = DateTimeOffset.FromUnixTimeSeconds((long)input.ToNumberValue());
result = dateTime.ToOffset(context.TimeZone.GetUtcOffset(dateTime));
}
else if (input.Type == FluidValues.DateTime)
{
result = (DateTimeOffset)input.ToObjectValue();
}
else
{
switch (input.ToObjectValue())
{
case DateTime dateTime:
result = dateTime;
break;

case DateTimeOffset dateTimeOffset:
result = dateTimeOffset;
break;

default:
return false;
}
}

return true;
}

private static async ValueTask WriteJson(Utf8JsonWriter writer, FluidValue input, TemplateContext ctx, HashSet<object> stack = null)
{
switch (input.Type)
Expand Down
121 changes: 120 additions & 1 deletion Fluid/Values/FluidValueExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,126 @@
namespace Fluid.Values
using System;
using System.Globalization;

namespace Fluid.Values
{
public static class FluidValueExtensions
{
private const string Now = "now";
private const string Today = "today";

private static readonly string[] DefaultFormats = {
"yyyy-MM-ddTHH:mm:ss.FFF",
"yyyy-MM-ddTHH:mm:ss",
"yyyy-MM-ddTHH:mm",
"yyyy-MM-dd",
"yyyy-MM",
"yyyy"
};

private static readonly string[] SecondaryFormats = {
// Formats used in DatePrototype toString methods
"ddd MMM dd yyyy HH:mm:ss 'GMT'K",
"ddd MMM dd yyyy",
"HH:mm:ss 'GMT'K",

// standard formats
"yyyy-M-dTH:m:s.FFFK",
"yyyy/M/dTH:m:s.FFFK",
"yyyy-M-dTH:m:sK",
"yyyy/M/dTH:m:sK",
"yyyy-M-dTH:mK",
"yyyy/M/dTH:mK",
"yyyy-M-d H:m:s.FFFK",
"yyyy/M/d H:m:s.FFFK",
"yyyy-M-d H:m:sK",
"yyyy/M/d H:m:sK",
"yyyy-M-d H:mK",
"yyyy/M/d H:mK",
"yyyy-M-dK",
"yyyy/M/dK",
"yyyy-MK",
"yyyy/MK",
"yyyyK",
"THH:mm:ss.FFFK",
"THH:mm:ssK",
"THH:mmK",
"THHK"
};

public static bool TryGetDateTimeInput(this FluidValue input, TemplateContext context, out DateTimeOffset result)
{
result = context.Now();

if (input.Type == FluidValues.String)
{
var stringValue = input.ToStringValue();

if (stringValue == Now || stringValue == Today)
{
return true;
}
else
{
var success = true;

if (!DateTime.TryParseExact(stringValue, DefaultFormats, context.CultureInfo, DateTimeStyles.None, out var dateTime))
{
if (!DateTime.TryParseExact(stringValue, SecondaryFormats, context.CultureInfo, DateTimeStyles.None, out dateTime))
{
if (!DateTime.TryParse(stringValue, context.CultureInfo, DateTimeStyles.None, out dateTime))
{
if (!DateTime.TryParse(stringValue, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
{
success = false;
}
}
}
}

// If no timezone is specified, assume local using the configured timezone
if (success)
{
if (dateTime.Kind == DateTimeKind.Unspecified)
{
result = new DateTimeOffset(dateTime, context.TimeZone.GetUtcOffset(dateTime));
}
else
{
result = new DateTimeOffset(dateTime);
}
}

return success;
}
}
else if (input.Type == FluidValues.Number)
{
var dateTime = DateTimeOffset.FromUnixTimeSeconds((long)input.ToNumberValue());
result = dateTime.ToOffset(context.TimeZone.GetUtcOffset(dateTime));
}
else if (input.Type == FluidValues.DateTime)
{
result = (DateTimeOffset)input.ToObjectValue();
}
else
{
switch (input.ToObjectValue())
{
case DateTime dateTime:
result = dateTime;
break;

case DateTimeOffset dateTimeOffset:
result = dateTimeOffset;
break;

default:
return false;
}
}

return true;
}

public static FluidValue Or(this FluidValue self, FluidValue other)
{
Expand Down