Skip to content

Commit d443951

Browse files
committed
Add new pragmas for date and time
1 parent ff8d2da commit d443951

File tree

12 files changed

+107
-60
lines changed

12 files changed

+107
-60
lines changed

JsonSchema/RelogicLabs/JsonSchema/Time/DateTimeValidator.cs renamed to JsonSchema/RelogicLabs/JsonSchema/Time/DateTimeParser.cs

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88

99
namespace RelogicLabs.JsonSchema.Time;
1010

11-
internal sealed class DateTimeValidator
11+
internal sealed class DateTimeParser
1212
{
13-
public const string ISO_8601_DATE = "YYYY-MM-DD";
14-
public const string ISO_8601_TIME = "YYYY-MM-DD'T'hh:mm:ss.FZZ";
15-
1613
private static readonly Dictionary<string, SegmentProcessor> _Processors = new();
1714
private readonly DateTimeLexer _dateTimeLexer;
1815
private readonly IList<IToken> _lexerTokens;
1916

20-
static DateTimeValidator()
17+
public string Pattern { get; }
18+
public DateTimeType Type { get; }
19+
20+
static DateTimeParser()
2121
{
2222
AddProcessor(TEXT, Text);
2323
AddProcessor(SYMBOL, Symbol);
@@ -55,15 +55,17 @@ static DateTimeValidator()
5555
private static void AddProcessor(int index, SegmentProcessor processor)
5656
=> _Processors.Add(ruleNames[index - 1], processor);
5757

58-
public DateTimeValidator(string pattern)
58+
public DateTimeParser(string pattern, DateTimeType type)
5959
{
60+
Pattern = pattern;
61+
Type = type;
6062
_dateTimeLexer = new DateTimeLexer(CharStreams.fromString(pattern));
6163
_dateTimeLexer.RemoveErrorListeners();
6264
_dateTimeLexer.AddErrorListener(LexerErrorListener.DateTime);
6365
_lexerTokens = _dateTimeLexer.GetAllTokens();
6466
}
6567

66-
private void Validate(string input, DateTimeContext context)
68+
private JsonDateTime Parse(string input, DateTimeContext context)
6769
{
6870
foreach(var token in _lexerTokens)
6971
{
@@ -73,45 +75,26 @@ private void Validate(string input, DateTimeContext context)
7375
if(input.Length != 0) throw new InvalidDateTimeException(ErrorCode.DINV02,
7476
$"Invalid {context.Type} input format");
7577

76-
context.Validate();
78+
var dateTime = context.Validate();
7779
DebugUtilities.Print(context);
80+
return dateTime;
7881
}
7982

80-
public void ValidateDate(string input)
81-
=> Validate(input, new DateTimeContext(DateTimeType.DATE_TYPE));
82-
83-
public void ValidateTime(string input)
84-
=> Validate(input, new DateTimeContext(DateTimeType.TIME_TYPE));
85-
86-
public bool IsValidDate(string input, out string error)
87-
{
88-
error = string.Empty;
89-
try
90-
{
91-
ValidateDate(input);
92-
return true;
93-
}
94-
catch(InvalidDateTimeException ex)
95-
{
96-
DebugUtilities.Print(ex);
97-
error = ex.Message;
98-
return false;
99-
}
100-
}
83+
public JsonDateTime Parse(string input)
84+
=> Parse(input, new DateTimeContext(Type));
10185

102-
public bool IsValidTime(string input, out string error)
86+
public JsonDateTime? TryParse(string input, out string error)
10387
{
10488
error = string.Empty;
10589
try
10690
{
107-
ValidateTime(input);
108-
return true;
91+
return Parse(input);
10992
}
11093
catch(InvalidDateTimeException ex)
11194
{
11295
DebugUtilities.Print(ex);
11396
error = ex.Message;
114-
return false;
97+
return null;
11598
}
11699
}
117100
}

JsonSchema/RelogicLabs/JsonSchema/Tree/FunctionManager.cs renamed to JsonSchema/RelogicLabs/JsonSchema/Tree/FunctionRegistry.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,19 @@
99

1010
namespace RelogicLabs.JsonSchema.Tree;
1111

12-
internal sealed class FunctionManager
12+
public sealed class FunctionRegistry
1313
{
1414
private readonly HashSet<string> _includes = new();
1515
private readonly Dictionary<FunctionKey, List<MethodPointer>> _functions = new();
1616
private readonly RuntimeContext _runtime;
1717

18-
public FunctionManager(RuntimeContext runtime) => _runtime = runtime;
18+
public FunctionRegistry(RuntimeContext runtime) => _runtime = runtime;
19+
20+
public JInclude AddClass(JInclude include)
21+
{
22+
AddClass(include.ClassName, include.Context);
23+
return include;
24+
}
1925

2026
public void AddClass(string className, Context? context = null)
2127
{
@@ -103,7 +109,7 @@ private static int GetParameterCount(ICollection<ParameterInfo> parameters)
103109
}
104110

105111
private static bool IsMatch(ParameterInfo parameter, JNode argument)
106-
=> parameter.ParameterType.IsInstanceOfType(argument);
112+
=> parameter.ParameterType.IsInstanceOfType(argument.Derived);
107113

108114
private static bool IsParams(ParameterInfo parameter)
109115
=> parameter.IsDefined(typeof(ParamArrayAttribute), false);
@@ -120,7 +126,7 @@ public bool InvokeFunction(JFunction function, JNode target)
120126
var schemaArgs = ProcessArguments(_parameters, _arguments);
121127
if(schemaArgs == null) continue;
122128
if(IsMatch(_parameters[0], target)) return method.Invoke(function,
123-
AddTarget(schemaArgs, target));
129+
AddTarget(schemaArgs, target.Derived));
124130
mismatchParameter = _parameters[0];
125131
}
126132
if(mismatchParameter != null)

JsonSchema/RelogicLabs/JsonSchema/Tree/PragmaDescriptor.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@ internal abstract class PragmaDescriptor
66
{
77
private static readonly Dictionary<string, PragmaDescriptor> _Pragmas = new();
88

9+
public const string ISO_8601_DATE = "YYYY-MM-DD";
10+
public const string ISO_8601_TIME = "YYYY-MM-DD'T'hh:mm:ss.FZZ";
11+
912
public static readonly PragmaProfile<bool> IgnoreUndefinedProperties
1013
= new(nameof(IgnoreUndefinedProperties), typeof(JBoolean), false);
1114
public static readonly PragmaProfile<double> FloatingPointTolerance
1215
= new(nameof(FloatingPointTolerance), typeof(JNumber), 1E-10);
1316
public static readonly PragmaProfile<bool> IgnoreObjectPropertyOrder
1417
= new(nameof(IgnoreObjectPropertyOrder), typeof(JBoolean), true);
18+
public static readonly PragmaProfile<string> DateDataTypeFormat
19+
= new(nameof(DateDataTypeFormat), typeof(JString), ISO_8601_DATE);
20+
public static readonly PragmaProfile<string> TimeDataTypeFormat
21+
= new(nameof(TimeDataTypeFormat), typeof(JString), ISO_8601_TIME);
1522

1623
public string Name { get; }
1724
public Type Type { get; }

JsonSchema/RelogicLabs/JsonSchema/Tree/PragmaManager.cs renamed to JsonSchema/RelogicLabs/JsonSchema/Tree/PragmaRegistry.cs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
using RelogicLabs.JsonSchema.Exceptions;
22
using RelogicLabs.JsonSchema.Message;
3+
using RelogicLabs.JsonSchema.Time;
34
using RelogicLabs.JsonSchema.Types;
45
using static RelogicLabs.JsonSchema.Message.ErrorCode;
6+
using static RelogicLabs.JsonSchema.Time.DateTimeType;
57

68
namespace RelogicLabs.JsonSchema.Tree;
79

8-
internal sealed class PragmaManager
10+
public sealed class PragmaRegistry
911
{
10-
public const string IGNORE_UNDEFINED_PROPERTIES = "IgnoreUndefinedProperties";
11-
public const string FLOATING_POINT_TOLERANCE = "FloatingPointTolerance";
12-
public const string IGNORE_OBJECT_PROPERTY_ORDER = "IgnoreObjectPropertyOrder";
12+
private const string IGNORE_UNDEFINED_PROPERTIES = "IgnoreUndefinedProperties";
13+
private const string FLOATING_POINT_TOLERANCE = "FloatingPointTolerance";
14+
private const string IGNORE_OBJECT_PROPERTY_ORDER = "IgnoreObjectPropertyOrder";
15+
private const string DATE_DATA_TYPE_FORMAT = "DateDataTypeFormat";
16+
private const string TIME_DATA_TYPE_FORMAT = "TimeDataTypeFormat";
1317

1418
private readonly Dictionary<string, JPragma> _pragmas = new();
1519

@@ -19,6 +23,19 @@ internal sealed class PragmaManager
1923
= PragmaDescriptor.FloatingPointTolerance.DefaultValue;
2024
public bool IgnoreObjectPropertyOrder { get; private set; }
2125
= PragmaDescriptor.IgnoreObjectPropertyOrder.DefaultValue;
26+
public string DateDataTypeFormat { get; private set; }
27+
= PragmaDescriptor.DateDataTypeFormat.DefaultValue;
28+
public string TimeDataTypeFormat { get; private set; }
29+
= PragmaDescriptor.TimeDataTypeFormat.DefaultValue;
30+
31+
internal DateTimeParser DateTypeParser { get; private set; }
32+
internal DateTimeParser TimeTypeParser { get; private set; }
33+
34+
public PragmaRegistry()
35+
{
36+
DateTypeParser = new DateTimeParser(DateDataTypeFormat, DATE_TYPE);
37+
TimeTypeParser = new DateTimeParser(TimeDataTypeFormat, TIME_TYPE);
38+
}
2239

2340
public JPragma AddPragma(JPragma pragma) {
2441
if(_pragmas.ContainsKey(pragma.Name))
@@ -40,6 +57,14 @@ private void SetPragmaValue(string name, JPrimitive value) {
4057
case IGNORE_OBJECT_PROPERTY_ORDER:
4158
IgnoreObjectPropertyOrder = ((IPragmaValue<bool>) value).Value;
4259
break;
60+
case DATE_DATA_TYPE_FORMAT:
61+
DateDataTypeFormat = ((IPragmaValue<string>) value).Value;
62+
DateTypeParser = new DateTimeParser(DateDataTypeFormat, DATE_TYPE);
63+
break;
64+
case TIME_DATA_TYPE_FORMAT:
65+
TimeDataTypeFormat = ((IPragmaValue<string>) value).Value;
66+
TimeTypeParser = new DateTimeParser(TimeDataTypeFormat, TIME_TYPE);
67+
break;
4368
}
4469
}
4570

JsonSchema/RelogicLabs/JsonSchema/Tree/SchemaTreeVisitor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public override JNode VisitCoreSchema(SchemaParser.CoreSchemaContext context)
4040

4141
private List<JInclude> ProcessIncludes(SchemaParser.IncludeContext[] contexts)
4242
{
43-
_runtime.AddClass(typeof(CoreFunctions).FullName!);
43+
_runtime.Functions.AddClass(typeof(CoreFunctions).FullName!);
4444
return contexts.Select(i => (JInclude) Visit(i)).ToList();
4545
}
4646

@@ -71,7 +71,7 @@ public override JNode VisitInclude(SchemaParser.IncludeContext context)
7171
Context = new Context(context, _runtime),
7272
ClassName = context.IDENTIFIER().Select(n => n.GetText()).Join(",")
7373
}.Build();
74-
return _runtime.AddClass(include);
74+
return _runtime.Functions.AddClass(include);
7575
}
7676

7777
public override JNode VisitPragma(SchemaParser.PragmaContext context)
@@ -83,7 +83,7 @@ public override JNode VisitPragma(SchemaParser.PragmaContext context)
8383
Name = context.IDENTIFIER().GetText(),
8484
Value = (JPrimitive) Visit(context.primitive())
8585
}.Build();
86-
return _runtime.AddPragma(pragma);
86+
return _runtime.Pragmas.AddPragma(pragma);
8787
}
8888

8989
public override JNode VisitValidator(SchemaParser.ValidatorContext context)

JsonSchema/RelogicLabs/JsonSchema/Types/JFunction.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ private bool InvokeFunction(JNode node)
4040
{
4141
try
4242
{
43-
return Runtime.InvokeFunction(this, node);
43+
return Runtime.Functions.InvokeFunction(this, node);
4444
}
4545
catch(Exception ex)
4646
{

JsonSchema/RelogicLabs/JsonSchema/Types/JLeaf.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ namespace RelogicLabs.JsonSchema.Types;
33
public abstract class JLeaf : JNode
44
{
55
private protected JLeaf(Builder builder) : base(builder) { }
6+
private protected JLeaf(JLeaf node) : base(node) { }
67
}

JsonSchema/RelogicLabs/JsonSchema/Types/JNode.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public abstract class JNode
1414
// To make complete tree read only and immutable
1515
private readonly IDictionary<JNode, JNode> _relations;
1616
public Context Context { get; }
17+
internal JNode Derived { get; set; }
1718
public virtual JNode? Parent => _relations.GetValue(this);
1819
public virtual IEnumerable<JNode> Children
1920
{ get; private protected init; } = Enumerable.Empty<JNode>();
@@ -24,6 +25,14 @@ private protected JNode(Builder builder)
2425
{
2526
_relations = NonNull(builder.Relations);
2627
Context = NonNull(builder.Context);
28+
Derived = this;
29+
}
30+
31+
private protected JNode(JNode node)
32+
{
33+
_relations = NonNull(node._relations);
34+
Context = NonNull(node.Context);
35+
Derived = this;
2736
}
2837

2938
private T Initialize<T>() where T : JNode

JsonSchema/RelogicLabs/JsonSchema/Types/JObject.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public override bool Match(JNode node)
4242
ExpectedDetail.AsPropertyNotFound(thisProp),
4343
ActualDetail.AsPropertyNotFound(node, thisProp)));
4444
}
45-
if(unresolved.IsEmpty() || Runtime.IgnoreUndefinedProperties) return result;
45+
if(unresolved.IsEmpty() || Runtime.Pragmas.IgnoreUndefinedProperties) return result;
4646
foreach(var key in unresolved)
4747
{
4848
var property = other.Properties[key];
@@ -58,7 +58,7 @@ public override bool Match(JNode node)
5858
{
5959
var thisProp = Properties[index];
6060
JProperty? otherProp = null;
61-
if(!Runtime.IgnoreObjectPropertyOrder)
61+
if(!Runtime.Pragmas.IgnoreObjectPropertyOrder)
6262
{
6363
var atProp = GetPropAt(other.Properties, index);
6464
if(AreKeysEqual(atProp, thisProp)) otherProp = atProp;
@@ -91,7 +91,7 @@ public override bool Equals(object? obj)
9191
if(obj.GetType() != this.GetType()) return false;
9292
var other = (JObject) obj;
9393
if(Properties.Count != other.Properties.Count) return false;
94-
return Runtime.IgnoreObjectPropertyOrder? UnorderedEquals(other.Properties)
94+
return Runtime.Pragmas.IgnoreObjectPropertyOrder? UnorderedEquals(other.Properties)
9595
: OrderedEquals(other.Properties);
9696
}
9797

JsonSchema/RelogicLabs/JsonSchema/Types/JPrimitive.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ namespace RelogicLabs.JsonSchema.Types;
33
public abstract class JPrimitive : JLeaf, IJsonType
44
{
55
private protected JPrimitive(Builder builder) : base(builder) { }
6+
private protected JPrimitive(JPrimitive node) : base(node) { }
67
public virtual JsonType Type => JsonType.PRIMITIVE;
78
public JNode Node => this;
89

0 commit comments

Comments
 (0)