我如何使用扩展定义并且不允许以与多个验证器兼容的方式添加其他属性(JSON 架构草案 7)?

How do I use an extended definition and not allow additional properties in a way that is compatible with multiple validators (JSON schema draft 7)?

我正在为一个复杂的 JSON 文件创建一个严格的验证器,并希望重新使用各种定义以保持模式易于管理和更易于更新。

根据 documentation 有必要使用 allOf 扩展定义以添加更多属性。这正是我所做的,但我发现不使用 additionalProperties 设置为 false 验证不会阻止添加任意其他属性。

以下大量精简的架构演示了我正在做的事情:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://example.com/schema/2021/02/example.json",
  "description": "This schema demonstrates how VSCode's JSON schema mechanism fails with allOf used to extend a definition",
  "definitions": {
    "valueProvider": {
      "type": "object",
      "properties": {
        "example": {
          "type": "string"
        },
        "alternative": {
          "type": "string"
        }
      },
      "oneOf": [
        {
          "required": [
            "example"
          ]
        },
        {
          "required": [
            "alternative"
          ]
        }
      ]
    },
    "selector": {
      "type": "object",
      "allOf": [
        {
          "$ref": "#/definitions/valueProvider"
        },
        {
          "required": [
            "operator",
            "value"
          ],
          "properties": {
            "operator": {
              "type": "string",
              "enum": [
                "IsNull",
                "Equals",
                "NotEquals",
                "Greater",
                "GreaterOrEquals",
                "Less",
                "LessOrEquals"
              ]
            },
            "value": {
              "type": "string"
            }
          }
        }
      ],
      "additionalProperties": false
    }
  },
  "properties": {
    "show": {
      "properties": {
        "name": {
          "type": "string"
        },
        "selector": {
          "description": "This property does not function correctly in VSCode",
          "allOf": [
            {
              "$ref": "#/definitions/selector"
            },
            {
              "additionalProperties": false
            }
          ]
        }
      },
      "additionalProperties": false
    }
  }
}

这在 IntelliJ IDEA 的 JSON 编辑器(2020.3.2 终极版)中针对此架构(使用架构映射)编辑 JSON 时很有用。例如文件ex-fail.json的内容为:

{
  "show": {
    "name": "a",
    "selector": {
      "example": "a",
      "operator": "IsNull",
      "value": "false",
      "d": "a"
    }
  }
}

已正确验证,只是将“d”突出显示为不允许,因此:

但是,当我使用完全相同的架构和 JSON 文件时 VSCode (1.53.2) 具有原始配置(架构映射除外)VSCode 错误地标记“示例”、“运算符”、“值”和“d”是不允许的。在 VSCode 编辑器中看起来像这样:

如果我从 show.selector 属性 中删除 additionalProperties 定义,IDEA 和 VSCode 都表明一切正常,包括允许“d” 属性 - 这样做我可以将 属性 定义简化为:

        "selector": {
          "description": "This property does not function correctly in VSCode",
          "$ref": "#/definitions/selector"
        }

我可以对模式做些什么来支持 IDEA 和 VSCode 同时禁止不应出现的其他属性?

PS:VSCode 中的模式映射简单地遵循:

{
    "json.schemas": [
    {
        "fileMatch": [
            "*/config/ex-*.json"
        ],
        "url": "file:///C:/my/path/to/example-schema.json"
    }
    ]
}

您无法使用 JSON 架构草稿 07 或更早版本执行您的要求。

原因是,当在架构对象中使用 $ref 时,必须忽略所有其他属性。

An object schema with a "$ref" property MUST be interpreted as a
"$ref" reference. The value of the "$ref" property MUST be a URI
Reference. Resolved against the current URI base, it identifies the
URI of a schema to use. All other properties in a "$ref" object MUST be ignored.

https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-01#section-8.3

我们将此更改为 2019-09 草案并非如此。

听起来 VSCode 正在将 applicators 中的属性向上合并到最近的模式对象(这是错误的),而 IntelliJ IDEA 正在以不同的方式做类似的事情(这也是错误的)。

您的模式和实例的正确验证结果是有效的。在此处查看现场演示:https://jsonschema.dev/s/C6ent

additionalProperties 依赖于 SAME 模式对象中 propertiespatternProperties 的值。它不能“看穿”涂抹器,例如 $refallOf.

对于 2019-09 草案,我们添加了 unevaluatedProperties,它可以“看穿”涂抹器关键字(尽管它比那更复杂一点)。


更新:

查看您的更新后,遗憾的是,情况仍然如此。 一种方法使它成为可能,但涉及一些重复,并且仅在您控制所引用的模式时才有效。

您需要像这样重新定义选择器 属性...

"selector": {
          "description": "This property did not function correctly in VSCode",
          "allOf": [
            {
              "$ref": "#/definitions/selector"
            },
            {
              "properties": {
                "operator": true,
                "value": true,
                "example": true,
                "alternative": true
              },
              "additionalProperties": false
            }
          ]
        }

属性 对象的值是模式值,布尔值是有效模式。你不需要(或不想)在这里处理他们的验证,只说这些是允许的,后面没有 additionalProperties.

您还需要从 selectordefinition 中删除 additionalProperties: false,因为这会阻止所有属性(我现在猜想这就是为什么您在其中一位编辑)。

它涉及一些重复,但这是我知道您可以为 draft-07 或更早版本执行此操作的唯一方法。正如我所说,由于新词的存在,对于 2019-09 或更高版本的草案来说不是问题。

additionalProperties 是有问题的,因为它依赖于 propertiespatternProperties。结果是 "additionalProperties": false 有效地阻止了模式组合。 @Relequestual 展示了一种替代方法,这里是另一种方法,稍微不那么冗长,但仍然需要重复 属性 个名称。

draft-06 及更高版本

{
  "allOf": [{ "$ref": "#/definitions/base" }],
  "properties": {
    "bar": { "type": "number" }
  },
  "propertyNames": { "enum": ["foo", "bar"] },

  "definitions": {
    "base": {
      "properties": {
        "foo": { "type": "string" }
      }
    }
  }
}