{
  "$schema": "http://json-schema.org/draft-07/schema",
  "$id": "https://somod.json-schema.sodaru.com/serverless-template/index.json",
  "title": "JSON Schema for Serverless Template in SOMOD",
  "definitions": {
    "somodAjvCompile": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::AjvCompile"
      ],
      "properties": {
        "SOMOD::AjvCompile": {
          "anyOf": [
            {
              "$ref": "http://json-schema.org/draft-07/schema"
            },
            {
              "$ref": "#/definitions/somodFunctions"
            }
          ]
        }
      }
    },
    "somodAnd": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::And"
      ],
      "properties": {
        "SOMOD::And": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "$ref": "#/definitions/somodFunctions"
              }
            ]
          },
          "minItems": 1
        }
      }
    },
    "somodEquals": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::Equals"
      ],
      "properties": {
        "SOMOD::Equals": {
          "type": "array",
          "items": {
            "anyOf": [
              true,
              {
                "$ref": "#/definitions/somodFunctions"
              }
            ]
          },
          "minItems": 2,
          "maxItems": 2
        }
      }
    },
    "somodFunctions": {
      "if": {
        "type": "object",
        "propertyNames": {
          "enum": [
            "SOMOD::AjvCompile",
            "SOMOD::And",
            "SOMOD::Or",
            "SOMOD::Equals",
            "SOMOD::If",
            "SOMOD::JsonParse",
            "SOMOD::JsonStringify",
            "SOMOD::Key",
            "SOMOD::Parameter"
          ]
        }
      },
      "then": {
        "oneOf": [
          {
            "$ref": "#/definitions/somodAjvCompile"
          },
          {
            "$ref": "#/definitions/somodAnd"
          },
          {
            "$ref": "#/definitions/somodOr"
          },
          {
            "$ref": "#/definitions/somodEquals"
          },
          {
            "$ref": "#/definitions/somodIf"
          },
          {
            "$ref": "#/definitions/somodJsonParse"
          },
          {
            "$ref": "#/definitions/somodJsonStringify"
          },
          {
            "$ref": "#/definitions/somodKey"
          },
          {
            "$ref": "#/definitions/somodParameter"
          }
        ]
      },
      "else": true
    },
    "somodIf": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::If"
      ],
      "properties": {
        "SOMOD::If": {
          "type": "array",
          "additionalItems": {
            "anyOf": [
              true,
              {
                "$ref": "#/definitions/somodFunctions"
              }
            ]
          },
          "items": [
            {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "$ref": "#/definitions/somodFunctions"
                }
              ]
            }
          ],
          "minItems": 2,
          "maxItems": 3
        }
      }
    },
    "somodJsonParse": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::JsonParse"
      ],
      "properties": {
        "SOMOD::JsonParse": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "$ref": "#/definitions/somodFunctions"
            }
          ]
        }
      }
    },
    "somodJsonStringify": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::JsonStringify"
      ],
      "properties": {
        "SOMOD::JsonStringify": {
          "anyOf": [
            true,
            {
              "$ref": "#/definitions/somodFunctions"
            }
          ]
        }
      }
    },
    "somodKey": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::Key"
      ],
      "properties": {
        "SOMOD::Key": {
          "type": "array",
          "additionalItems": false,
          "items": [
            {
              "anyOf": [
                {
                  "type": "object"
                },
                {
                  "type": "array"
                },
                {
                  "$ref": "#/definitions/somodFunctions"
                }
              ]
            },
            {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "number"
                },
                {
                  "$ref": "#/definitions/somodFunctions"
                }
              ]
            }
          ],
          "minItems": 2,
          "maxItems": 2
        }
      }
    },
    "somodOr": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::Or"
      ],
      "properties": {
        "SOMOD::Or": {
          "type": "array",
          "items": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "$ref": "#/definitions/somodFunctions"
              }
            ]
          },
          "minItems": 1
        }
      }
    },
    "somodParameter": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::Parameter"
      ],
      "properties": {
        "SOMOD::Parameter": {
          "type": "string",
          "description": "Must refer the parameter available for this module"
        }
      }
    },
    "arrayLike": {
      "oneOf": [
        {
          "$ref": "#/definitions/samCidr"
        },
        {
          "$ref": "#/definitions/samGetAZs"
        },
        {
          "$ref": "#/definitions/samSplit"
        },
        {
          "$ref": "#/definitions/samIf"
        },
        {
          "$ref": "#/definitions/samFindInMap"
        },
        {
          "$ref": "#/definitions/samRef"
        },
        {
          "$ref": "#/definitions/somodRef"
        },
        {
          "$ref": "#/definitions/somodParameter"
        },
        {
          "$ref": "#/definitions/somodIf"
        },
        {
          "$ref": "#/definitions/somodJsonParse"
        },
        {
          "$ref": "#/definitions/somodKey"
        }
      ]
    },
    "booleanLike": {
      "oneOf": [
        {
          "$ref": "#/definitions/samBoolean"
        },
        {
          "$ref": "#/definitions/samAnd"
        },
        {
          "$ref": "#/definitions/samOr"
        },
        {
          "$ref": "#/definitions/samEquals"
        },
        {
          "$ref": "#/definitions/samNot"
        },
        {
          "$ref": "#/definitions/samIf"
        },
        {
          "$ref": "#/definitions/samFindInMap"
        },
        {
          "$ref": "#/definitions/samRef"
        },
        {
          "$ref": "#/definitions/somodRef"
        },
        {
          "$ref": "#/definitions/somodParameter"
        },
        {
          "$ref": "#/definitions/somodAnd"
        },
        {
          "$ref": "#/definitions/somodOr"
        },
        {
          "$ref": "#/definitions/somodEquals"
        },
        {
          "$ref": "#/definitions/somodIf"
        },
        {
          "$ref": "#/definitions/somodKey"
        }
      ]
    },
    "numberLike": {
      "oneOf": [
        {
          "$ref": "#/definitions/samNumber"
        },
        {
          "$ref": "#/definitions/samSelect"
        },
        {
          "$ref": "#/definitions/samIf"
        },
        {
          "$ref": "#/definitions/samFindInMap"
        },
        {
          "$ref": "#/definitions/samRef"
        },
        {
          "$ref": "#/definitions/somodRef"
        },
        {
          "$ref": "#/definitions/somodParameter"
        },
        {
          "$ref": "#/definitions/somodIf"
        },
        {
          "$ref": "#/definitions/somodKey"
        }
      ]
    },
    "samAnd": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::And": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/booleanLike"
          },
          "minItems": 1,
          "maxItems": 10
        }
      }
    },
    "samBase64": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::Base64": {
          "$ref": "#/definitions/stringLike"
        }
      }
    },
    "samBoolean": {
      "type": "boolean"
    },
    "samCidr": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::Cidr": {
          "type": "array",
          "items": [
            {
              "$ref": "#/definitions/stringLike",
              "description": "ipBlock"
            },
            {
              "$ref": "#/definitions/numberLike",
              "description": "count"
            },
            {
              "$ref": "#/definitions/numberLike",
              "description": "cidrBits"
            }
          ],
          "minItems": 3,
          "maxItems": 3,
          "additionalItems": false
        }
      }
    },
    "samEquals": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::Equals": {
          "type": "array",
          "items": [
            {
              "anyOf": [
                {
                  "$ref": "#/definitions/stringLike"
                },
                {
                  "$ref": "#/definitions/numberLike"
                },
                {
                  "$ref": "#/definitions/booleanLike"
                },
                {
                  "$ref": "#/definitions/arrayLike"
                }
              ]
            },
            {
              "anyOf": [
                {
                  "$ref": "#/definitions/stringLike"
                },
                {
                  "$ref": "#/definitions/numberLike"
                },
                {
                  "$ref": "#/definitions/booleanLike"
                },
                {
                  "$ref": "#/definitions/arrayLike"
                }
              ]
            }
          ],
          "maxItems": 2,
          "minItems": 2,
          "additionalItems": false
        }
      }
    },
    "samFindInMap": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::FindInMap": {
          "type": "array",
          "items": [
            {
              "$ref": "#/definitions/samString"
            },
            {
              "$ref": "#/definitions/stringLike"
            },
            {
              "$ref": "#/definitions/stringLike"
            }
          ],
          "minItems": 3,
          "maxItems": 3,
          "additionalItems": false
        }
      }
    },
    "samGetAZs": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::GetAZs": {
          "anyOf": [
            {
              "$ref": "#/definitions/samString"
            },
            {
              "$ref": "#/definitions/somodRef"
            },
            {
              "$ref": "#/definitions/somodFunctions"
            }
          ]
        }
      }
    },
    "samIf": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::If": {
          "type": "array",
          "items": [
            {
              "$ref": "#/definitions/samString"
            },
            {
              "anyOf": [
                {
                  "$ref": "#/definitions/stringLike"
                },
                {
                  "$ref": "#/definitions/numberLike"
                },
                {
                  "$ref": "#/definitions/booleanLike"
                },
                {
                  "$ref": "#/definitions/arrayLike"
                }
              ]
            },
            {
              "anyOf": [
                {
                  "$ref": "#/definitions/stringLike"
                },
                {
                  "$ref": "#/definitions/numberLike"
                },
                {
                  "$ref": "#/definitions/booleanLike"
                },
                {
                  "$ref": "#/definitions/arrayLike"
                }
              ]
            }
          ],
          "maxItems": 3,
          "minItems": 3,
          "additionalItems": false
        }
      }
    },
    "samJoin": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::Join": {
          "type": "array",
          "items": [
            {
              "$ref": "#/definitions/samString"
            },
            {
              "anyOf": [
                {
                  "type": "array",
                  "items": {
                    "anyOf": [
                      {
                        "$ref": "#/definitions/stringLike"
                      },
                      {
                        "$ref": "#/definitions/numberLike"
                      }
                    ]
                  },
                  "minItems": 1
                },
                {
                  "$ref": "#/definitions/samGetAZs"
                },
                {
                  "$ref": "#/definitions/samIf"
                },
                {
                  "$ref": "#/definitions/samSplit"
                },
                {
                  "$ref": "#/definitions/samSelect"
                },
                {
                  "$ref": "#/definitions/samRef"
                },
                {
                  "$ref": "#/definitions/somodRef"
                },
                {
                  "$ref": "#/definitions/somodFunctions"
                }
              ]
            }
          ],
          "minItems": 2,
          "maxItems": 2,
          "additionalItems": false
        }
      }
    },
    "samNot": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::Not": {
          "type": "array",
          "items": [
            {
              "$ref": "#/definitions/booleanLike"
            }
          ],
          "maxItems": 1,
          "minItems": 1,
          "additionalItems": false
        }
      }
    },
    "samNumber": {
      "type": "number"
    },
    "samOr": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::Or": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/booleanLike"
          },
          "minItems": 1,
          "maxItems": 10
        }
      }
    },
    "samRef": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Ref": {
          "enum": [
            "AWS::AccountId",
            "AWS::NotificationARNs",
            "AWS::NoValue",
            "AWS::Partition",
            "AWS::Region",
            "AWS::StackId",
            "AWS::StackName",
            "AWS::URLSuffix"
          ]
        }
      }
    },
    "samSelect": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::Select": {
          "type": "array",
          "items": [
            {
              "anyOf": [
                {
                  "$ref": "#/definitions/samNumber"
                },
                {
                  "$ref": "#/definitions/somodFunctions"
                },
                {
                  "$ref": "#/definitions/samFindInMap"
                }
              ]
            },
            {
              "anyOf": [
                {
                  "$ref": "#/definitions/samFindInMap"
                },
                {
                  "$ref": "#/definitions/samGetAZs"
                },
                {
                  "$ref": "#/definitions/samIf"
                },
                {
                  "$ref": "#/definitions/samSplit"
                },
                {
                  "$ref": "#/definitions/samRef"
                },
                {
                  "$ref": "#/definitions/somodRef"
                },
                {
                  "$ref": "#/definitions/somodFunctions"
                }
              ]
            }
          ],
          "minItems": 2,
          "maxItems": 2,
          "additionalItems": false
        }
      }
    },
    "samSplit": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::Split": {
          "type": "array",
          "items": [
            {
              "$ref": "#/definitions/samString"
            },
            {
              "anyOf": [
                {
                  "$ref": "#/definitions/samString"
                },
                {
                  "$ref": "#/definitions/samBase64"
                },
                {
                  "$ref": "#/definitions/samFindInMap"
                },
                {
                  "$ref": "#/definitions/samGetAZs"
                },
                {
                  "$ref": "#/definitions/samIf"
                },
                {
                  "$ref": "#/definitions/samJoin"
                },
                {
                  "$ref": "#/definitions/samSelect"
                },
                {
                  "$ref": "#/definitions/samSub"
                },
                {
                  "$ref": "#/definitions/samRef"
                },
                {
                  "$ref": "#/definitions/somodRef"
                },
                {
                  "$ref": "#/definitions/somodFunctions"
                },
                {
                  "$ref": "#/definitions/somodModuleName"
                }
              ]
            }
          ],
          "minItems": 2,
          "maxItems": 2,
          "additionalItems": false
        }
      }
    },
    "samString": {
      "type": "string"
    },
    "samSub": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Fn::Sub": {
          "oneOf": [
            {
              "type": "string",
              "maxLength": 1024
            },
            {
              "type": "array",
              "items": [
                {
                  "$ref": "#/definitions/samString"
                },
                {
                  "type": "object",
                  "additionalProperties": false,
                  "patternProperties": {
                    "^[a-zA-Z0-9]+$": {
                      "anyOf": [
                        {
                          "$ref": "#/definitions/samString"
                        },
                        {
                          "$ref": "#/definitions/samBase64"
                        },
                        {
                          "$ref": "#/definitions/samFindInMap"
                        },
                        {
                          "$ref": "#/definitions/samGetAZs"
                        },
                        {
                          "$ref": "#/definitions/samIf"
                        },
                        {
                          "$ref": "#/definitions/samJoin"
                        },
                        {
                          "$ref": "#/definitions/samSelect"
                        },
                        {
                          "$ref": "#/definitions/samRef"
                        },
                        {
                          "$ref": "#/definitions/somodRef"
                        },
                        {
                          "$ref": "#/definitions/somodFunctions"
                        }
                      ]
                    }
                  }
                }
              ],
              "minItems": 2,
              "maxItems": 2,
              "additionalItems": false
            }
          ]
        }
      }
    },
    "stringLike": {
      "oneOf": [
        {
          "$ref": "#/definitions/samString"
        },
        {
          "$ref": "#/definitions/samBase64"
        },
        {
          "$ref": "#/definitions/samIf"
        },
        {
          "$ref": "#/definitions/samFindInMap"
        },
        {
          "$ref": "#/definitions/samJoin"
        },
        {
          "$ref": "#/definitions/samSelect"
        },
        {
          "$ref": "#/definitions/samSub"
        },
        {
          "$ref": "#/definitions/samRef"
        },
        {
          "$ref": "#/definitions/somodRef"
        },
        {
          "$ref": "#/definitions/somodParameter"
        },
        {
          "$ref": "#/definitions/somodModuleName"
        },
        {
          "$ref": "#/definitions/somodAjvCompile"
        },
        {
          "$ref": "#/definitions/somodIf"
        },
        {
          "$ref": "#/definitions/somodJsonStringify"
        },
        {
          "$ref": "#/definitions/somodKey"
        }
      ]
    },
    "somodAccess": {
      "type": "object",
      "properties": {
        "SOMOD::Access": {
          "enum": [
            "module",
            "scope",
            "public"
          ]
        }
      }
    },
    "somodCreateIf": {
      "type": "object",
      "properties": {
        "SOMOD::CreateIf": {
          "$ref": "#/definitions/booleanLike"
        }
      }
    },
    "somodDependsOn": {
      "type": "object",
      "properties": {
        "SOMOD::DependsOn": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "resource"
            ],
            "properties": {
              "module": {
                "$ref": "#/definitions/somodModuleNamePattern"
              },
              "resource": {
                "$ref": "#/definitions/somodResourceLogicalIdPattern"
              }
            }
          },
          "minItems": 1,
          "maxItems": 20
        }
      }
    },
    "somodExtend": {
      "type": "object",
      "properties": {
        "SOMOD::Extend": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "module",
            "resource"
          ],
          "properties": {
            "module": {
              "$ref": "#/definitions/somodModuleNamePattern"
            },
            "resource": {
              "$ref": "#/definitions/somodResourceLogicalIdPattern"
            },
            "rules": {
              "type": "object",
              "additionalProperties": {
                "enum": [
                  "REPLACE",
                  "COMBINE",
                  "APPEND",
                  "PREPEND"
                ]
              }
            }
          }
        }
      }
    },
    "somodModuleName": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::ModuleName"
      ],
      "properties": {
        "SOMOD::ModuleName": {
          "const": true
        }
      }
    },
    "somodModuleNamePattern": {
      "type": "string",
      "pattern": "^(@[a-z0-9-]+\\/)?[a-z0-9-]+$",
      "maxLength": 128
    },
    "somodOutput": {
      "type": "object",
      "properties": {
        "SOMOD::Output": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "default": {
              "type": "boolean"
            },
            "attributes": {
              "type": "array",
              "items": {
                "type": "string",
                "pattern": "^[a-zA-Z0-9]+$"
              }
            }
          }
        }
      }
    },
    "somodRef": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::Ref"
      ],
      "properties": {
        "SOMOD::Ref": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "resource"
          ],
          "properties": {
            "resource": {
              "$ref": "#/definitions/somodResourceLogicalIdPattern"
            },
            "module": {
              "$ref": "#/definitions/somodModuleNamePattern"
            },
            "attribute": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9]+$"
            }
          }
        }
      }
    },
    "somodResourceLogicalIdPattern": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9]{1,64}$"
    },
    "somodResourceName": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "SOMOD::ResourceName"
      ],
      "properties": {
        "SOMOD::ResourceName": {
          "type": "string",
          "pattern": "^[a-zA-Z]+[a-zA-Z0-9]*$",
          "maxLength": 64
        }
      }
    },
    "allResource": {
      "allOf": [
        {
          "type": "object",
          "required": [
            "Type",
            "Properties"
          ],
          "properties": {
            "Type": {
              "type": "string"
            },
            "Properties": {
              "type": "object"
            }
          }
        },
        {
          "$ref": "#/definitions/somodExtend"
        },
        {
          "$ref": "#/definitions/somodAccess"
        },
        {
          "$ref": "#/definitions/somodDependsOn"
        },
        {
          "$ref": "#/definitions/somodOutput"
        },
        {
          "$ref": "#/definitions/somodCreateIf"
        },
        {
          "if": {
            "type": "object",
            "required": [
              "SOMOD::Extend"
            ]
          },
          "then": {
            "type": "object",
            "propertyNames": {
              "not": {
                "enum": [
                  "SOMOD::Access",
                  "SOMOD::DependsOn",
                  "SOMOD::Output",
                  "SOMOD::CreateIf"
                ]
              },
              "errorMessage": "Extended Resource can not have Access, DependsOn, Output or CreateIf keywords"
            }
          },
          "errorMessage": {
            "if": "Extended Resource can not have Access, DependsOn, Output or CreateIf keywords"
          }
        }
      ]
    },
    "customResource": {
      "type": "object",
      "required": [
        "Type",
        "Properties"
      ],
      "anyOf": [
        {
          "type": "object",
          "required": [
            "SOMOD::Extend"
          ]
        },
        {
          "type": "object",
          "properties": {
            "Properties": {
              "type": "object",
              "required": [
                "ServiceToken"
              ]
            }
          }
        }
      ],
      "errorMessage": {
        "anyOf": "When not extended, Properties must have ServiceToken"
      },
      "properties": {
        "Type": {
          "type": "string",
          "pattern": "^Custom::[A-Z][a-zA-Z0-9]{0,63}$"
        },
        "Properties": {
          "type": "object",
          "properties": {
            "ServiceToken": {
              "$ref": "#/definitions/somodRef"
            }
          }
        }
      }
    },
    "functionTypes": {
      "anyOf": [
        {
          "enum": [
            "S3",
            "SNS",
            "Kinesis",
            "DynamoDB",
            "SQS",
            "Api",
            "Schedule",
            "EventBridgeRule",
            "CloudWatchLogs",
            "IoTRule",
            "AlexaSkill",
            "Cognito",
            "HttpApi",
            "MSK",
            "MQ",
            "SelfManagedKafka",
            "CFNCustomResource"
          ]
        },
        {
          "type": "string",
          "minLength": 1,
          "maxLength": 32,
          "pattern": "^[a-zA-Z0-9]*$"
        }
      ]
    },
    "functionApiEvent": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "Type",
        "Properties"
      ],
      "properties": {
        "Type": {
          "const": "Api"
        },
        "Properties": {
          "type": "object",
          "required": [
            "Method",
            "Path",
            "RestApiId"
          ],
          "properties": {
            "Method": {
              "anyOf": [
                {
                  "enum": [
                    "GET",
                    "POST",
                    "PUT",
                    "DELETE",
                    "ANY"
                  ]
                },
                {
                  "type": "string",
                  "pattern": "^[A-Z]+$"
                }
              ]
            },
            "Path": {
              "type": "string"
            },
            "RestApiId": {
              "$ref": "#/definitions/somodRef"
            }
          }
        }
      }
    },
    "functionHttpApiEvent": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "Type",
        "Properties"
      ],
      "properties": {
        "Type": {
          "const": "HttpApi"
        },
        "Properties": {
          "type": "object",
          "required": [
            "Method",
            "Path",
            "ApiId"
          ],
          "properties": {
            "Method": {
              "anyOf": [
                {
                  "enum": [
                    "GET",
                    "POST",
                    "PUT",
                    "DELETE",
                    "ANY"
                  ]
                },
                {
                  "type": "string",
                  "pattern": "^[A-Z]+$"
                }
              ]
            },
            "Path": {
              "type": "string"
            },
            "ApiId": {
              "$ref": "#/definitions/somodRef"
            }
          }
        }
      }
    },
    "functionEvent": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "Type",
        "Properties"
      ],
      "properties": {
        "Type": {
          "$ref": "#/definitions/functionTypes"
        },
        "Properties": {
          "type": "object"
        }
      }
    },
    "functionEventSource": {
      "allOf": [
        {
          "$ref": "#/definitions/functionEvent"
        },
        {
          "if": {
            "type": "object",
            "properties": {
              "Type": {
                "const": "HttpApi"
              }
            }
          },
          "then": {
            "$ref": "#/definitions/functionHttpApiEvent"
          }
        },
        {
          "if": {
            "type": "object",
            "properties": {
              "Type": {
                "const": "Api"
              }
            }
          },
          "then": {
            "$ref": "#/definitions/functionApiEvent"
          }
        }
      ]
    },
    "functionResource": {
      "title": "JSON Schema for Function Resource in Serverless Template of SOMOD",
      "type": "object",
      "required": [
        "Type",
        "Properties"
      ],
      "anyOf": [
        {
          "type": "object",
          "required": [
            "SOMOD::Extend"
          ]
        },
        {
          "type": "object",
          "properties": {
            "Properties": {
              "type": "object",
              "oneOf": [
                {
                  "required": [
                    "CodeUri"
                  ]
                },
                {
                  "required": [
                    "InlineCode"
                  ]
                }
              ],
              "properties": {
                "CodeUri": {
                  "type": "object",
                  "properties": {
                    "SOMOD::Function": {
                      "type": "object",
                      "required": [
                        "type",
                        "name"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      ],
      "errorMessage": {
        "anyOf": "When not extended, Properties must have either CodeUri or InlineCode"
      },
      "properties": {
        "Type": {
          "const": "AWS::Serverless::Function"
        },
        "Properties": {
          "type": "object",
          "properties": {
            "CodeUri": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "SOMOD::Function"
              ],
              "properties": {
                "SOMOD::Function": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "type": {
                      "$ref": "#/definitions/functionTypes"
                    },
                    "name": {
                      "type": "string",
                      "description": "The name of the function, this is the file name of es module under 'serverless/functions' directory (without file extension)",
                      "pattern": "^[a-zA-Z]+[a-zA-Z0-9]*$"
                    },
                    "customResources": {
                      "type": "object",
                      "description": "Define the Schema for the custom resources handled by this function. Schema is indexed by Custom Resource Type with `Custom::` removed. Schema no need to define `ServiceToken` Property",
                      "additionalProperties": false,
                      "maxProperties": 25,
                      "patternProperties": {
                        "^[A-Z][a-zA-Z0-9]{0,63}$": {
                          "$ref": "http://json-schema.org/draft-07/schema"
                        }
                      }
                    },
                    "middlewares": {
                      "type": "array",
                      "description": "Middlewares to be added to this function. Middlewares are applied in the order specified in this Property",
                      "minItems": 1,
                      "maxItems": 16,
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "resource"
                        ],
                        "properties": {
                          "resource": {
                            "$ref": "#/definitions/somodResourceLogicalIdPattern"
                          },
                          "module": {
                            "$ref": "#/definitions/somodModuleNamePattern"
                          }
                        }
                      }
                    }
                  }
                }
              }
            },
            "InlineCode": {
              "type": "string"
            },
            "Layers": {
              "type": "array",
              "description": "Layers attached to the funtion, If a layer are refered using SOMOD::Ref, the npm packages in the layer are excluded from the function bundle",
              "items": {
                "$ref": "#/definitions/stringLike"
              },
              "maxItems": 5,
              "uniqueItems": true
            },
            "Events": {
              "type": "object",
              "additionalProperties": false,
              "patternProperties": {
                "^[a-zA-Z0-9]+$": {
                  "$ref": "#/definitions/functionEventSource"
                }
              }
            }
          }
        }
      }
    },
    "functionLayerResource": {
      "type": "object",
      "required": [
        "Type",
        "Properties"
      ],
      "anyOf": [
        {
          "type": "object",
          "required": [
            "SOMOD::Extend"
          ]
        },
        {
          "type": "object",
          "properties": {
            "Properties": {
              "type": "object",
              "required": [
                "RetentionPolicy",
                "ContentUri"
              ],
              "properties": {
                "ContentUri": {
                  "type": "object",
                  "properties": {
                    "SOMOD::FunctionLayer": {
                      "type": "object",
                      "required": [
                        "name"
                      ],
                      "anyOf": [
                        {
                          "type": "object",
                          "required": [
                            "libraries"
                          ]
                        },
                        {
                          "type": "object",
                          "required": [
                            "content"
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      ],
      "errorMessage": {
        "anyOf": "When not extended, Properties must have RetentionPolicy and ContentUri"
      },
      "properties": {
        "Type": {
          "const": "AWS::Serverless::LayerVersion"
        },
        "Properties": {
          "type": "object",
          "properties": {
            "RetentionPolicy": {
              "const": "Delete"
            },
            "ContentUri": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "SOMOD::FunctionLayer"
              ],
              "properties": {
                "SOMOD::FunctionLayer": {
                  "type": "object",
                  "additionalProperties": false,
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "The name of the function layer",
                      "pattern": "^[a-zA-Z]+[a-zA-Z0-9]*$"
                    },
                    "libraries": {
                      "type": "array",
                      "description": "All dependent libraries to be installed in the layer",
                      "items": {
                        "type": "string",
                        "pattern": "^(@[a-z0-9\\-]+\\/){0,1}[a-z0-9\\-]+$"
                      },
                      "minItems": 1,
                      "maxItems": 32
                    },
                    "content": {
                      "type": "object",
                      "description": "The Layer Content, map of file-path to file-content",
                      "additionalProperties": false,
                      "patternProperties": {
                        ".*": {
                          "$ref": "#/definitions/stringLike"
                        }
                      },
                      "minProperties": 1,
                      "maxProperties": 32
                    },
                    "allowedTypes": {
                      "type": "array",
                      "description": "Type of the funtion to which this layer can be applied to. If not specified or left empty, the layer is allowed for all type of functions",
                      "items": {
                        "$ref": "#/definitions/functionTypes"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "functionMiddlewareResource": {
      "type": "object",
      "required": [
        "Type",
        "Properties"
      ],
      "anyOf": [
        {
          "type": "object",
          "required": [
            "SOMOD::Extend"
          ]
        },
        {
          "type": "object",
          "properties": {
            "Properties": {
              "type": "object",
              "required": [
                "CodeUri"
              ],
              "properties": {
                "CodeUri": {
                  "type": "object",
                  "properties": {
                    "SOMOD::FunctionMiddleware": {
                      "type": "object",
                      "required": [
                        "name"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      ],
      "errorMessage": {
        "anyOf": "When not extended, Properties must have CodeUri"
      },
      "properties": {
        "Type": {
          "const": "SOMOD::Serverless::FunctionMiddleware"
        },
        "Properties": {
          "type": "object",
          "properties": {
            "CodeUri": {
              "type": "object",
              "required": [
                "SOMOD::FunctionMiddleware"
              ],
              "additionalProperties": false,
              "properties": {
                "SOMOD::FunctionMiddleware": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "The name of the function middleware, this is the file name of es module under 'serverless/functions/middlewares' directory (without file extension)",
                      "pattern": "^[a-zA-Z]+[a-zA-Z0-9]*$"
                    },
                    "allowedTypes": {
                      "type": "array",
                      "description": "Type of the funtion to which this middleware can be applied to. If not specified or left empty, the middleware is allowed for all type of functions",
                      "items": {
                        "$ref": "#/definitions/functionTypes"
                      }
                    }
                  }
                }
              }
            },
            "Environment": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "Variables": {
                  "type": "object",
                  "additionalProperties": {
                    "$ref": "#/definitions/stringLike"
                  },
                  "propertyNames": {
                    "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
                  }
                }
              }
            },
            "Layers": {
              "type": "array",
              "description": "Functions Layers to be added to applied functions, If a layer are refered using SOMOD::Ref, the npm packages in the layer are excluded from the function bundle",
              "items": {
                "$ref": "#/definitions/stringLike"
              },
              "maxItems": 5,
              "uniqueItems": true
            }
          }
        }
      }
    }
  },
  "type": "object",
  "required": [
    "Resources"
  ],
  "properties": {
    "Resources": {
      "type": "object",
      "additionalProperties": {
        "allOf": [
          {
            "$ref": "#/definitions/allResource"
          },
          {
            "if": {
              "type": "object",
              "properties": {
                "Type": {
                  "enum": [
                    "AWS::Serverless::Function",
                    "AWS::Serverless::LayerVersion",
                    "SOMOD::Serverless::FunctionMiddleware"
                  ]
                }
              }
            },
            "then": {
              "oneOf": [
                {
                  "$ref": "#/definitions/functionResource"
                },
                {
                  "$ref": "#/definitions/functionLayerResource"
                },
                {
                  "$ref": "#/definitions/functionMiddlewareResource"
                }
              ]
            }
          },
          {
            "if": {
              "type": "object",
              "properties": {
                "Type": {
                  "type": "string",
                  "pattern": "^Custom::[A-Z][a-zA-Z0-9]{0,63}$"
                }
              }
            },
            "then": {
              "$ref": "#/definitions/customResource"
            }
          }
        ]
      },
      "propertyNames": {
        "type": "string",
        "pattern": "^[a-zA-Z0-9]{1,64}$"
      }
    },
    "Outputs": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/definitions/stringLike"
      },
      "propertyNames": {
        "$ref": "#/definitions/somodParameter/properties/SOMOD::Parameter"
      }
    }
  },
  "additionalProperties": false
}