So I think it would be nice to have a DSL for just data validation (think jsonschema but just the bits that do with validation, no annotations and a simpler referencing system)
A DSL means that the language can be designed from the ground up for the best user experience and then compile to native languages ( the approach protobufs use for example). I don't propose any syntax or semantics that is radically different from what exists in standard programming languages today so I don't expect the learning curve to be high
- No tooling support. General purpose languages come with tons of support with things like linters and autcomplete. If this is going to be actually successful, it would need these tools too.
- Need to write compilers for different languages.
So let's dive in.
# boolean operations to combine schemas. syntax stolen from F#
validator =
| str
| array
| object
validator =
& str
& object # obviously impossible to satisfy since an instance can not be both a str and object
validator = [str] # type that every item in the list/sequence needs to satisfy. shortform for
validator = iterable<str>
validator = [str | int] # string or int items
(required syntax borrows from gql :D)
Tree = {data!: any, children: [Tree]} # short form for
Tree = mapping<data!: any, children: iterable<Tree>>
NestedList = [NestedList | str]
validator = `4`
validator = `"a string"`
range06 = min(0) & max(6)
range<start: int, end: int> = min(start) & max(end)
range<end: int> = min(0) & max(end)
case =
str: rangeLength<1, 6>
int & range<1, 100>: True
default: None
rangeLength<start, end> =
& minLength(start)
& maxLength(end)
StringRangeLength =
case =
str: rangeLength<1, 6>
default: None
What is the basis of all constraint operations? define the smallest subset on top of which everything else could be built Does this need expressions - say I want to count that exactly five thing validate in a list?
How would I implement features that exist in Jsonschema? patternProps, additionalProps, contains, minContains, maxContains etc?
this is mostly descriptive to show that this can simulate every schema that can be written with json schema. Plus demonstrate the core schema.
items<schema> = [^, schema*, $]
contains<schema> = [schema+]
minContains<schema, num> = [schema{num,}]
maxContains<schema, num> = [schema{, num}]
minItems<num> = [any{num,}]
maxItems<num> = [any{, num}]
range<start, end> = [any{start, end}]
rangeItems<schema, start, end> = [schema{start, end}]
unique = unique
Profile = {"name": maxLength<20>} # properties
Profile = {"x-[a-z]+": minLength<10>} # patternProperties
Profile = {rest=~any} # additionalProperties
Profile = {required=`["name", "surname"]`} # required
Profile = {"x-[a-z]+": any, min=1, max=3} # min and maxProperties
Profile = {propertyNames="x-[a-z]+"} # propertyNames
Profile = { # DependentRequired
dependentRequired=`{"name": ["surname", "address"]}`
}
Profile =
& {"name": maxLength<20>}
& {required=["name", "surname"]}
& {dependentRequired=`{"name": ["surname", "address"]}`}
min = {3,}
max = {,5}
exclusiveMin = {3-,}
exlusiveMax = {,5-}
range = {3, 5}
caseSchema =
| caseSchema1: then1
| caseSchema2: then2
| default: then3
not<schema> = ~schema
Oh an idea just popped in my head. I can do make the basis - logic! so have things like "for all", "there exists", "belongs to" etc.