2026-05-12 02:23:01 +01:00
|
|
|
# Reusable Validation Library for Nickel
|
|
|
|
|
{
|
|
|
|
|
IpV4Contract = {
|
|
|
|
|
label = "ValidIPv4",
|
|
|
|
|
predicate = fun ip =>
|
|
|
|
|
std.string.is_match ip "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
CidrContract = {
|
|
|
|
|
label = "ValidCIDR",
|
|
|
|
|
predicate = fun cidr =>
|
|
|
|
|
std.string.is_match cidr "^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/\\d{1,2}$"
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
PortContract = {
|
|
|
|
|
label = "ValidPort",
|
|
|
|
|
predicate = fun p =>
|
|
|
|
|
p > 0 && p < 65536
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
SemverContract = {
|
|
|
|
|
label = "ValidSemver",
|
|
|
|
|
predicate = fun v =>
|
|
|
|
|
std.string.is_match v "^\\d+\\.\\d+\\.\\d+$"
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
DomainContract = {
|
|
|
|
|
label = "ValidDomain",
|
|
|
|
|
predicate = fun d =>
|
|
|
|
|
std.string.is_match d "^[a-z0-9]([a-z0-9-\\.]{0,253}[a-z0-9])?$"
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
OciTagContract = {
|
|
|
|
|
label = "ValidOCITag",
|
|
|
|
|
predicate = fun tag =>
|
|
|
|
|
std.string.is_match tag "^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$"
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
Iso8601Contract = {
|
|
|
|
|
label = "ValidISO8601",
|
|
|
|
|
predicate = fun ts =>
|
|
|
|
|
std.string.is_match ts "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$"
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
PathContract = {
|
|
|
|
|
label = "ValidPath",
|
|
|
|
|
predicate = fun path =>
|
|
|
|
|
std.string.length path > 0 && !std.string.contains path "//"
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
min_length = fun min_val => {
|
2026-01-08 09:55:37 +00:00
|
|
|
label = "MinLength%{std.to_string min_val}",
|
2026-05-12 02:23:01 +01:00
|
|
|
predicate = fun s => std.string.length s >= min_val,
|
|
|
|
|
},
|
2026-01-08 09:55:37 +00:00
|
|
|
|
2026-05-12 02:23:01 +01:00
|
|
|
max_length = fun max_val => {
|
2026-01-08 09:55:37 +00:00
|
|
|
label = "MaxLength%{std.to_string max_val}",
|
2026-05-12 02:23:01 +01:00
|
|
|
predicate = fun s => std.string.length s <= max_val,
|
|
|
|
|
},
|
2026-01-08 09:55:37 +00:00
|
|
|
|
2026-05-12 02:23:01 +01:00
|
|
|
range = fun min_val max_val => {
|
2026-01-08 09:55:37 +00:00
|
|
|
label = "Range[%{std.to_string min_val}-%{std.to_string max_val}]",
|
2026-05-12 02:23:01 +01:00
|
|
|
predicate = fun n => n >= min_val && n <= max_val,
|
|
|
|
|
},
|
2026-01-08 09:55:37 +00:00
|
|
|
|
2026-05-12 02:23:01 +01:00
|
|
|
enum = fun values => {
|
2026-01-08 09:55:37 +00:00
|
|
|
label = "Enum[%{std.string.join "," values}]",
|
2026-05-12 02:23:01 +01:00
|
|
|
predicate = fun v => std.array.elem v values,
|
|
|
|
|
},
|
2026-01-08 09:55:37 +00:00
|
|
|
|
2026-05-12 02:23:01 +01:00
|
|
|
non_empty_string = {
|
|
|
|
|
label = "NonEmptyString",
|
|
|
|
|
predicate = fun s => std.string.length s > 0
|
|
|
|
|
},
|
2026-01-08 09:55:37 +00:00
|
|
|
|
2026-05-12 02:23:01 +01:00
|
|
|
non_negative = {
|
|
|
|
|
label = "NonNegative",
|
|
|
|
|
predicate = fun n => n >= 0
|
|
|
|
|
},
|
2026-01-08 09:55:37 +00:00
|
|
|
|
2026-05-12 02:23:01 +01:00
|
|
|
positive = {
|
|
|
|
|
label = "Positive",
|
|
|
|
|
predicate = fun n => n > 0
|
|
|
|
|
},
|
2026-01-08 09:55:37 +00:00
|
|
|
|
2026-05-12 02:23:01 +01:00
|
|
|
boolean_value = {
|
|
|
|
|
label = "Boolean",
|
|
|
|
|
predicate = fun b => b == true || b == false
|
|
|
|
|
},
|
2026-01-08 09:55:37 +00:00
|
|
|
|
2026-05-12 02:23:01 +01:00
|
|
|
all_items = fun pred => fun items => std.array.all pred items,
|
2026-01-08 09:55:37 +00:00
|
|
|
|
2026-05-12 02:23:01 +01:00
|
|
|
any_items = fun pred => fun items => std.array.any pred items,
|
2026-01-08 09:55:37 +00:00
|
|
|
|
2026-05-12 02:23:01 +01:00
|
|
|
has_keys = fun required_keys => fun record =>
|
2026-01-08 09:55:37 +00:00
|
|
|
std.array.all
|
2026-05-12 02:23:01 +01:00
|
|
|
(fun key => std.record.has_field record key)
|
|
|
|
|
required_keys,
|
|
|
|
|
|
|
|
|
|
IpRef =
|
|
|
|
|
std.contract.custom (
|
|
|
|
|
fun _label =>
|
|
|
|
|
fun value =>
|
|
|
|
|
if value == ""
|
|
|
|
|
|| std.string.is_match "^(\\d{1,3}\\.){3}\\d{1,3}$" value
|
|
|
|
|
|| std.string.contains ":" value
|
|
|
|
|
|| std.string.contains "fip" value
|
|
|
|
|
then 'Ok value
|
|
|
|
|
else 'Error {
|
|
|
|
|
message = "expected empty, an IPv4 address, an IPv6 address (contains ':'), or a FIP name (contains 'fip'); got '%{value}'"
|
|
|
|
|
}
|
|
|
|
|
),
|
2026-01-08 09:55:37 +00:00
|
|
|
}
|