unexpected validation error which LSP is fine with
Closed this issue · 10 comments
I have the following schema.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"patternProperties": {
"(^{{[ ]+\\.[A-Za-z][A-Za-z0-9_-]+[ ]+}}$)|(^[A-Za-z][A-Za-z0-9_-]+$)": {
"properties": {
"Env": {
"patternProperties": {
"^[A-Za-z][A-Za-z0-9_-]+$": {
"type": [
"boolean",
"number",
"string"
]
}
},
"type": "object"
}
},
"patternProperties": {
"(^{{[ ]+\\.[A-Za-z][A-Za-z0-9_-]+[ ]+}}$)|(^[A-Za-z][A-Za-z0-9_-]+$)": {
"properties": {
"Default": {
"type": "string",
"enum": [
"ALLOW",
"DENY"
]
}
},
"patternProperties": {
"(^{{[ ]+\\.[A-Za-z][A-Za-z0-9_-]+[ ]+}}$)|(^[A-Za-z][A-Za-z0-9_-]+$)": {
"type": "string",
"title": "Policy"
}
},
"additionalProperties": false,
"type": [
"object",
"null"
]
}
},
"additionalProperties": false,
"type": [
"object",
"null"
]
}
},
"type": "object",
"title": "Resourcename"
}
And this test.yaml file
# yaml-language-server: $schema=./schema.json
resourcename1:
Env:
"keyname0": "something"
"keyname1": 42
aname0:
Default: ALLOW
pname0: hello
I am using version 5.3.1 and run this code
func schemaValidationTest() {
var v any
if b, e := ioutil.ReadFile("/tmp/test.yaml"); e != nil {
log.Fatal(e)
} else if sch, e := jsonschema.Compile("/tmp/schema.json"); e != nil {
log.Fatal(e)
} else if e = yaml.Unmarshal(b, &v); e != nil {
log.Fatal(e)
} else if e = sch.Validate(v); e != nil {
switch et := e.(type) {
default:
fmt.Println("not a model missing error")
case *jsonschema.ValidationError:
log.Fatalf("%#v", et)
}
}
}
I am getting this error:
[I#] [S#] doesn't validate with file:///tmp/schema.json#
[I#/resourcename1/Env/keyname1] [S#/patternProperties/%28%5E%7B%7B%5B%20%5D+%5C.%5BA-Za-z%5D%5BA-Za-z0-9_-%5D+%5B%20%5D+%7D%7D$%29%7C%28%5E%5BA-Za-z%5D%5BA-Za-z0-9_-%5D+$%29/patternProperties/%28%5E%7B%7B%5B%20%5D+%5C.%5BA-Za-z%5D%5BA-Za-z0-9_-%5D+%5B%20%5D+%7D%7D$%29%7C%28%5E%5BA-Za-z%5D%5BA-Za-z0-9_-%5D+$%29/patternProperties/%28%5E%7B%7B%5B%20%5D+%5C.%5BA-Za-z%5D%5BA-Za-z0-9_-%5D+%5B%20%5D+%7D%7D$%29%7C%28%5E%5BA-Za-z%5D%5BA-Za-z0-9_-%5D+$%29/type] expected string, but got number
My Lsp which seem to work fine does not complain in the same way.
I've tried to experiment a little and apparently it goes into the patternProperties that is on the same level as the properties where the Env property is for the "keyname1", but not for "keyname0"
Your LSP is giving wrong result. it should give error. I tested your example with online validate at https://www.jsonschemavalidator.net. it also gives the same result.
to explain the error, I constructed following simplified example:
schema.json
{
"properties": {
"x": {
"type": "string"
}
},
"patternProperties": {
"x*": {
"type": "number"
}
}
}
instance.json
{
"x": "y"
}
the above json gives following error:
[I#] [S#] doesn't validate with file:///Users/santhosh/gh/santhosh-tekuri/jsonschema/cmd/jv/sch.json#
[I#/x] [S#/patternProperties/x%2A/type] expected number, but got string
if you change json to following:
{
"x": 12
}
you get following error:
[I#] [S#] doesn't validate with file:///Users/santhosh/gh/santhosh-tekuri/jsonschema/cmd/jv/sch.json#
[I#/x] [S#/properties/x/type] expected string, but got number
you can see that it fails in both cases where x
value is string
and number
as per the schema the property x
matches two schemas /properties/x
and patternProperties/x*
. so the property value must satisfy both schemas.
/properties/x
says value must be string
.
patternProperties/x*
says value must be number
thus it is impossible to add property x
with valid value
Thank you for quick response!
Right, So I would need to not match on Env in patternProperties then or on x in your example.
Yes. You should use oneOf keyword for or behaviour
Ah, you mean instead of | in patternProperties? I guess if I got you right that would make it easier indeed. :)
{ "oneOf":[
{"properties": { "x": { "type": "string" } }},
{"patternProperties": { "x*": { "type": "number" } } }}
]}
I'm not sure if that will work in my example though? As I need both Env and aname0 to be valid
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"patternProperties": {
"(^{{[ ]+\\.[A-Za-z][A-Za-z0-9_-]+[ ]+}}$)|(^[A-Za-z][A-Za-z0-9_-]+$)": {
"oneOf": [
{
"properties": {
"Env": {
"patternProperties": {
"^[A-Za-z][A-Za-z0-9_-]+$": {
"type": [
"boolean",
"number",
"string"
]
}
},
"type": "object"
}
}
},
{
"patternProperties": {
"(^{{[ ]+\\.[A-Za-z][A-Za-z0-9_-]+[ ]+}}$)|(^[A-Za-z][A-Za-z0-9_-]+$)": {
"properties": {
"Default": {
"type": "string",
"enum": [
"ALLOW",
"DENY"
]
}
},
"patternProperties": {
"(^{{[ ]+\\.[A-Za-z][A-Za-z0-9_-]+[ ]+}}$)|(^[A-Za-z][A-Za-z0-9_-]+$)": {
"type": "string",
"title": "Policy"
}
},
"additionalProperties": false,
"type": [
"object",
"null"
]
}
}
}
],
"additionalProperties": false,
"type": [
"object",
"null"
]
}
},
"type": "object",
"title": "Resourcename"
}
You are right. It does not seem straight forward
Thanks anyway, I know why its not working and should be able to find a solution now :)
I found the solution using propertyNames
.
below is the working schema:
{
"$schema":"https://json-schema.org/draft/2020-12/schema",
"patternProperties":{
"(^{{[ ]+\\.[A-Za-z][A-Za-z0-9_-]+[ ]+}}$)|(^[A-Za-z][A-Za-z0-9_-]+$)":{
"propertyNames":{
"pattern":"(^{{[ ]+\\.[A-Za-z][A-Za-z0-9_-]+[ ]+}}$)|(^[A-Za-z][A-Za-z0-9_-]+$)"
},
"properties":{
"Env":{
"patternProperties":{
"^[A-Za-z][A-Za-z0-9_-]+$":{
"type":[
"boolean",
"number",
"string"
]
}
},
"type":"object"
}
},
"additionalProperties":{
"propertyNames":{
"pattern":"(^{{[ ]+\\.[A-Za-z][A-Za-z0-9_-]+[ ]+}}$)|(^[A-Za-z][A-Za-z0-9_-]+$)"
},
"properties":{
"Default":{
"type":"string",
"enum":[
"ALLOW",
"DENY"
]
}
},
"additionalProperties":{
"type":"string",
"title":"Policy"
},
"type":[
"object",
"null"
]
},
"type":[
"object",
"null"
]
}
},
"type":"object",
"title":"Resourcename"
}
Cool thanks will check it out.. on my phone atm. Thanks again :)