JSON 模式 - 即使 "if" 不正确,if then 语句也总是被评估

JSON Schema - if then statement is always evaluated even when "if" isn't true

我有一个 JSON 架构,在架构中 - 当 属性 type 等于 menu 时,那么 属性 default 应该是一个整数或一个名为“default”的字符串。问题是,即使 type 不是“菜单”。

(JSON 中有名为“type”和“default”的属性,不要与 JSON 架构类型和默认键混淆。

Schema 缩减为相关属性:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "array",
    "title": "HubSpot Module",
    "items": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "The type of field, see [field types](https://developers.hubspot.com/en/docs/cms/building-blocks/module-theme-fields#field-types) for documentation on all field types."
        },
        "default": {
          "type": ["string", "integer", "array", "boolean", "null", "number", "object"],
          "description": "Default value for the field.",
          "if": {
            "properties": {
              "type": {
                "const": "menu"
              }
            }
          },
          "then": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "string",
                "enum": [
                  "default"
                ]
              }
            ],
            "description": "The menu ID for the menu. The default value of null, defaults to the default menu under navigation.",
            "default": "null"
          },
          "else": {
            "anyOf": [
              {
                "type": ["string", "integer", "array", "boolean", "null", "number", "object"]
              }
            ]
          }
        }
      },
      "required": [
        "name",
        "label",
        "type"
      ]
    }
  }

当满足这些条件时它会起作用,例如

[
  {
    "label": "Primary menu field",
    "name": "primary_menu_field",
    "type": "menu",
    "default": 123
  }
]

[
  {
    "label": "Primary menu field",
    "name": "primary_menu_field",
    "type": "menu",
    "default": "default"
  }
]

这些都没有抛出警告。但是以下抛出警告:Incorrect type. Expected "integer".

[
  {
    "name": "boolean_field",
    "label": "Boolean field",
    "required": false,
    "locked": false,
    "type": "boolean",
    "inline_help_text": "",
    "help_text": "",
    "default": false 
  }
]

尽管 type 属性 没有被命名为“菜单”。将鼠标悬停在“默认”属性 VSCode 上确实给出了我对它的定义。

似乎 if 语句总是被评估为 true - 只有当 属性 type 的值为 menu 时才应该评估它,是有什么我想念的吗?

您的 if 没有按预期工作,因为它在错误的位置并且没有受到足够的约束。您在“默认”属性 模式中有 if,这意味着 if 模式将应用于“默认”属性 的值。所以,如果“默认”是 123,那么 if 模式,

{
  "properties": {
    "type": { "const": "menu" }
  }
}

将根据 123 进行评估。由于 123 是一个数字,properties 关键字将被忽略,架构将通过验证并应用 then 架构。这就是我所说的 if 受到约束的意思。使用 if 时,您需要检查丢失的数据或错误类型的数据。

{
  "type": "object",
  "properties": {
    "type": { "const": "menu" }
  },
  "required": ["type"]
}

现在,您将在根据此模式验证 123 时收到一条错误消息,并希望能找出您的 if/then 位置错误。 if 需要应用于对象,您需要将其向上移动到架构中的该级别。这将使您的 if 得到预期的评估。不要忘记更新 then,因为您移动了架构。我还需要在对象级别而不是 属性 级别进行定义。

{
  "$schema": "http://json-schema.org/draft-07/schema#",

  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "type": { "type": "string" }
    },
    "required": ["name", "label", "type"],

    "if": {
      "type": "object",
      "properties": {
        "type": { "const": "menu" }
      },
      "required": ["type"]
    },
    "then": {
      "properties": {
        "default": {
          "anyOf": [
            { "type": "integer" },
            { "const": "default" }
          ]
        }
      }
    }
  }
}

你的if/then/elsedefault属性下面,所以它在default下面找对象,而不是在你想要的地方上一层。

此外,如果 属性 实际上不存在,if 条件中的 properties 检查将始终为真,因此要确保它确实存在,您可以添加一个 "required": <propertyname> 旁边。

(正交地,您的 type 检查并没有真正做任何事情,因为您在列表中包含了所有有效类型。您最好将其省略以指示“这可以是任何类型”。)