# Base types provided by Drupal core.

# Read https://www.drupal.org/node/1905070 for more details about configuration
# schema, types and type resolution.

# Undefined type used by the system to assign to elements at any level where
# configuration schema is not defined. Using explicitly has the same effect as
# not defining schema, so there is no point in doing that.
undefined:
  label: 'Undefined'
  class: '\Drupal\Core\Config\Schema\Undefined'

# Explicit type to use when no data typing is possible. Instead of using this
# type, we strongly suggest you use configuration structures that can be
# described with other structural elements of schema, and describe your schema
# with those elements.
ignore:
  label: 'Ignore'
  class: '\Drupal\Core\Config\Schema\Ignore'

# Basic scalar data types from typed data.
boolean:
  label: 'Boolean'
  class: '\Drupal\Core\TypedData\Plugin\DataType\BooleanData'
email:
  label: 'Email'
  class: '\Drupal\Core\TypedData\Plugin\DataType\Email'
  constraints:
    Email:
      message: "%value is not a valid email address."
integer:
  label: 'Integer'
  class: '\Drupal\Core\TypedData\Plugin\DataType\IntegerData'
timestamp:
  label: 'Timestamp'
  class: '\Drupal\Core\TypedData\Plugin\DataType\Timestamp'
float:
  label: 'Float'
  class: '\Drupal\Core\TypedData\Plugin\DataType\FloatData'
string:
  label: 'String'
  class: '\Drupal\Core\TypedData\Plugin\DataType\StringData'
uri:
  label: 'Uri'
  class: '\Drupal\Core\TypedData\Plugin\DataType\Uri'

# Container data types for lists with known and unknown keys.
mapping:
  label: Mapping
  class: '\Drupal\Core\Config\Schema\Mapping'
  definition_class: '\Drupal\Core\TypedData\MapDataDefinition'
  mapping: {}
  constraints:
    # By default, allow the explicitly listed mapping keys, and require their
    # presence unless `requiredKey: false` is specified.
    ValidKeys: '<infer>'
sequence:
  label: Sequence
  class: '\Drupal\Core\Config\Schema\Sequence'
  definition_class: '\Drupal\Core\Config\Schema\SequenceDataDefinition'

# Simple extended data types:

# Human readable string that must be plain text and editable with a text field.
label:
  type: string
  label: 'Optional label'
  translatable: true
  constraints:
    Regex:
      # Forbid any kind of control character.
      # @see https://stackoverflow.com/a/66587087
      pattern: '/([^\PC])/u'
      match: false
      message: 'Labels are not allowed to span multiple lines or contain control characters.'

required_label:
  type: label
  label: 'Label'
  constraints:
    NotBlank: {}

# String containing plural variants, separated by EXT.
plural_label:
  type: label
  label: 'Plural variants'
  constraints:
    Regex:
      # Normally, labels cannot contain invisible control characters. In this particular
      # case, an invisible character (ASCII 3, 0x03) is used to encode translation
      # information, so carve out an exception for that only.
      # @see \Drupal\views\Plugin\views\field\NumericField
      pattern: '/([^\PC\x03])/u'
      match: false
      message: 'Labels are not allowed to span multiple lines or contain control characters.'

# Internal Drupal path
path:
  type: string
  label: 'Path'

# Human readable string that can contain multiple lines of text or HTML.
text:
  type: string
  label: 'Text'
  translatable: true
  constraints:
    Regex:
      # Disallow all control characters except for tabs (ASCII 9, 0x09) as well
      # as carriage returns (ASCII 13, 0x0D) and line feeds (ASCII 10, 0x0A),
      # which are used for line endings:
      # - Windows: `\r\n`
      # - old macOS: `\r`
      # - *nix: `\n`
      # @see https://stackoverflow.com/a/66587087
      pattern: '/([^\PC\x09\x0a\x0d])/u'
      match: false
      message: 'Text is not allowed to contain control characters, only visible characters.'

# A UUID.
uuid:
  type: string
  label: 'UUID'
  constraints:
    Uuid: {}

# PHP Date format string that is translatable.
date_format:
  type: string
  label: 'Date format'
  translatable: true
  translation context: 'PHP date format'

# HTML color value.
color_hex:
  type: string
  label: 'Color'
  constraints:
    # TRICKY: this cannot reuse the Color::validateHex() logic because:
    # 1. Color::validateHex() would not allow NULL, but this constraint does.
    #    (Anything in config can be marked optional, so NULL must never trigger
    #    a validation error) Color::validateHex() does not allow this.
    # 2. The Regex constraint is something that an external tool (no matter
    #    whether that's something generating/validating Drupal config or a
    #    JSON:API/REST/GraphQL/… client) to also correctly validate this.
    Regex:
      # Regex copied from Color::validateHex()
      pattern: '/^[#]?([0-9a-fA-F]{3}){1,2}$/'
      message: "%value is not a valid hexadecimal color."

# Machine-readable identifier that can only contain certain characters.
machine_name:
  type: string
  label: 'Machine name'
  constraints:
    Regex:
      pattern: '/^[a-z0-9_]+$/'
      message: "The %value machine name is not valid."
    Length:
      # @see \Drupal\Core\Config\Entity\ConfigEntityStorage::MAX_ID_LENGTH
      max: 166

# A language identifier.
langcode:
  type: string
  label: 'Language code'
  constraints:
    NotNull: []
    Choice:
      callback: 'Drupal\Core\TypedData\Plugin\DataType\LanguageReference::getAllValidLangcodes'

# A number of bytes; either a plain number or with a size indication such as "MB".
# @see \Drupal\Component\Utility\Bytes
bytes:
  type: string
  label: 'Bytes'
  constraints:
    Callback: ['\Drupal\Component\Utility\Bytes', 'validateConstraint']

weight:
  type: integer
  label: 'Weight'
  constraints:
    Range:
      # @see PHP_INT_MIN (32-bit)
      min: -2147483648
      # @see PHP_INT_MAX (32-bit)
      max: 2147483647
    FullyValidatable: ~

# Complex extended data types:

# Root of a configuration object.

_core_config_info:
  type: mapping
  mapping:
    default_config_hash:
      type: string
      label: 'Default configuration hash'
      constraints:
        NotNull: []
        Regex: '/^[a-zA-Z0-9\-_]+$/'
        # The hash is a base64-encoded version of the config's SHA-256 hash. Given
        # the deterministic length of a SHA-256 hash, and the way base64 encoding
        # works, this is always going to be 43 characters long.
        Length: 43
  constraints:
    ValidKeys: ['default_config_hash']

config_object:
  type: mapping
  mapping:
    _core:
      # This only exists for merging configuration; it's not required.
      requiredKey: false
      type: _core_config_info
    langcode:
      requiredKey: false
      type: langcode
  constraints:
    # The `langcode` key:
    # - MUST be specified when there are translatable values
    # - MUST NOT be specified when there are no translatable values.
    # Translatable values are specified for this config schema type (a subtype of `type: config_object`) if the
    # `translatable` flag is present and set to `true` for *any* element in that config schema type.
    LangcodeRequiredIfTranslatableValues: ~

# Mail text with subject and body parts.
mail:
  type: mapping
  label: 'Mail'
  mapping:
    subject:
      type: required_label
      label: 'Subject'
    body:
      type: text
      label: 'Body'

# Filter with module and status.
filter:
  type: mapping
  label: 'Filter'
  mapping:
    id:
      type: string
      label: 'ID'
      constraints:
        PluginExists:
          manager: plugin.manager.filter
          interface: 'Drupal\filter\Plugin\FilterInterface'
    provider:
      type: string
      label: 'Provider'
    status:
      type: boolean
      label: 'Status'
    weight:
      type: weight
      label: 'Weight'
    settings:
      type: filter_settings.[%parent.id]

# System action configuration base.
action_configuration_default:
  type: sequence
  label: 'Action configuration'
  sequence:
    type: string

theme_settings:
  type: config_object
  mapping:
    favicon:
      type: mapping
      label: 'Shortcut icon settings'
      mapping:
        mimetype:
          type: string
          label: 'MIME type'
        path:
          type: string
          label: 'Path'
        url:
          type: string
          label: 'URL'
        use_default:
          type: boolean
          label: 'Use the default shortcut icon supplied by the theme'
    features:
      type: mapping
      label: 'Optional features'
      mapping:
        comment_user_picture:
          type: boolean
          label: 'User pictures in comments'
        comment_user_verification:
          type: boolean
          label: 'User verification status in comments'
        favicon:
          type: boolean
          label: 'Shortcut icon'
        logo:
          type: boolean
          label: 'Logo'
        name:
          type: boolean
          label: 'Site name'
        node_user_picture:
          type: boolean
          label: 'User pictures in posts'
        slogan:
          type: boolean
          label: 'Site slogan'
    logo:
      type: mapping
      label: 'Logo settings'
      mapping:
        path:
          type: string
          label: 'Logo path'
        url:
          type: uri
          nullable: true
          label: 'URL'
        use_default:
          type: boolean
          label: 'Use default'
    third_party_settings:
      # Third party settings are always optional: they're an optional extension
      # point.
      requiredKey: false
      type: sequence
      label: 'Third party settings'
      sequence:
        type: theme_settings.third_party.[%key]

# Array of routes with route_name and route_params keys.
route:
  type: mapping
  label: 'Route'
  mapping:
    route_name:
      type: string
      label: 'Route Name'
    route_params:
      type: sequence
      label: 'Route Params'
      sequence:
        type: string
        label: 'Param'

# Config dependencies.
config_dependencies_base:
  type: mapping
  mapping:
    config:
      # All dependency keys are optional: this might not depend on any other config.
      requiredKey: false
      type: sequence
      label: 'Configuration entity dependencies'
      sequence:
        type: string
        constraints:
          NotBlank: []
          ConfigExists: []
    content:
      # All dependency keys are optional: this might not depend on any content entities.
      requiredKey: false
      type: sequence
      label: 'Content entity dependencies'
      sequence:
        type: string
    module:
      # All dependency keys are optional: this might not depend on any modules.
      requiredKey: false
      type: sequence
      label: 'Module dependencies'
      sequence:
        type: string
        constraints:
          NotBlank: []
          ExtensionName: []
          ExtensionExists: module
    theme:
      # All dependency keys are optional: this might not depend on any themes.
      requiredKey: false
      type: sequence
      label: 'Theme dependencies'
      sequence:
        type: string
        constraints:
          NotBlank: []
          ExtensionName: []
          ExtensionExists: theme
  constraints:
    ValidKeys: '<infer>'

config_dependencies:
  type: config_dependencies_base
  label: 'Configuration dependencies'
  mapping:
    enforced:
      # All dependency keys are optional: this may have no dependencies at all.
      requiredKey: false
      type: config_dependencies_base
      label: 'Enforced configuration dependencies'
  constraints:
    ValidKeys: '<infer>'

config_entity:
  type: mapping
  mapping:
    uuid:
      type: uuid
      label: 'UUID'
    langcode:
      type: langcode
    status:
      type: boolean
      label: 'Status'
    dependencies:
      type: config_dependencies
      label: 'Dependencies'
    third_party_settings:
      # Third party settings are always optional: they're an optional extension
      # point.
      requiredKey: false
      type: sequence
      label: 'Third party settings'
      sequence:
        type: '[%parent.%parent.%type].third_party.[%key]'
    _core:
      # This only exists for merging configuration; it's not required.
      requiredKey: false
      type: _core_config_info

block.settings.*:
  type: block_settings

block_settings:
  type: mapping
  label: 'Block settings'
  mapping:
    id:
      type: string
      label: 'ID'
    label:
      type: label
      label: 'Description'
    label_display:
      type: string
      label: 'Display title'
    provider:
      type: string
      label: 'Provider'
    status:
      type: boolean
      label: 'Status'
    info:
      type: label
      label: 'Admin info'
    view_mode:
      type: string
      label: 'View mode'
    context_mapping:
      type: sequence
      label: 'Context assignments'
      sequence:
        type: string

condition.plugin:
  type: mapping
  label: 'Condition'
  mapping:
    id:
      type: string
      label: 'ID'
      constraints:
        PluginExists:
          manager: plugin.manager.condition
          interface: 'Drupal\Core\Condition\ConditionInterface'
    negate:
      type: boolean
      label: 'Negate'
    uuid:
      type: uuid
    context_mapping:
      type: sequence
      label: 'Context assignments'
      sequence:
        type: string

condition.plugin.entity_bundle:*:
  type: condition.plugin
  mapping:
    bundles:
      type: sequence
      sequence:
        type: string

display_variant.plugin:
  type: mapping
  label: 'Display variant'
  mapping:
    id:
      type: string
      label: 'ID'
    label:
      type: required_label
      label: 'Label'
    weight:
      type: weight
      label: 'Weight'
    uuid:
      type: uuid

layout_plugin.settings:
  type: mapping
  label: 'Layout settings'
  mapping:
    label:
      type: label
      label: 'Label'
    context_mapping:
      type: sequence
      label: 'Context assignments'
      sequence:
        type: string

# Specify defaults.
layout_plugin.settings.*:
  type: layout_plugin.settings

base_entity_reference_field_settings:
  type: mapping
  mapping:
    target_type:
      type: string
      label: 'Type of item to reference'

field_config_base:
  type: config_entity
  mapping:
    id:
      type: string
      label: 'ID'
    field_name:
      type: string
      label: 'Field name'
    entity_type:
      type: string
      label: 'Entity type'
    bundle:
      type: string
      label: 'Bundle'
      constraints:
        EntityBundleExists: '%parent.entity_type'
    label:
      type: required_label
      label: 'Label'
    description:
      type: text
      label: 'Help text'
    required:
      type: boolean
      label: 'Required field'
    translatable:
      type: boolean
      label: 'Translatable'
    default_value:
      type: sequence
      label: 'Default values'
      sequence:
        type: field.value.[%parent.%parent.field_type]
        label: 'Default value'
    default_value_callback:
      type: string
      label: 'Default value callback'
    settings:
      type: field.field_settings.[%parent.field_type]
    field_type:
      type: string
      label: 'Field type'
      constraints:
        PluginExists:
          manager: plugin.manager.field.field_type
          interface: '\Drupal\Core\Field\FieldItemInterface'

core.base_field_override.*.*.*:
  type: field_config_base
  label: 'Base field bundle override'

core.date_format.*:
  type: config_entity
  label: 'Date format'
  mapping:
    id:
      type: machine_name
      label: 'ID'
    label:
      type: required_label
      label: 'Label'
    locked:
      type: boolean
      label: 'Locked'
    pattern:
      type: core_date_format_pattern.[%parent.locked]
      label: 'PHP date format'
      constraints:
        NotBlank: []
        # A valid date format character must appear somewhere in the value.
        # See https://www.php.net/manual/en/datetime.format.php
        Regex:
          pattern: '/[aABcdDeFgGhHiIjlLmMnNoOpPrsStTuUvwWxXyYzZ]/'
          message: 'This is not a valid date format.'
  constraints:
    FullyValidatable: ~

# Unlocked date formats should use the translatable type.
core_date_format_pattern.0:
  type: date_format
  label: 'Date format'

# Locked date formats are just used to transport the value.
core_date_format_pattern.1:
  type: string
  label: 'Date format'

# Generic field settings schemas.

field.storage_settings.*:
  type: mapping
  label: 'Settings'
  # By default, a field type has no settings, so this can safely be considered
  # fully validatable. A `FOO` field type that has one or more settings is
  # required to create a `field.storage_settings.FOO` config schema type, and
  # cannot possibly forget to do that, because validation errors would be
  # triggered if it ever tried to save a setting, since this mapping allows no
  # key-value pairs at all.
  constraints:
    FullyValidatable: ~

field.field_settings.*:
  type: mapping
  label: 'Settings'
  # By default, a field type has no settings, so this can safely be considered
  # fully validatable. A `FOO` field type that has one or more settings is
  # required to create a `field.field_settings.FOO` config schema type, and
  # cannot possibly forget to do that, because validation errors would be
  # triggered if it ever tried to save a setting, since this mapping allows no
  # key-value pairs at all.
  constraints:
    FullyValidatable: ~

field.value.*:
  type: mapping
  label: 'Default value'

# Schema for the configuration of the String field type.
# This field type has no field instance settings, so no specific config schema type.
# @see `type: field.field_settings.*`
field.storage_settings.string:
  type: mapping
  label: 'String settings'
  mapping:
    max_length:
      type: integer
      label: 'Maximum length'
    case_sensitive:
      type: boolean
      label: 'Case sensitive'
    is_ascii:
      type: boolean
      label: 'Contains US ASCII characters only'

field.value.string:
  type: mapping
  label: 'Default value'
  mapping:
    value:
      type: label
      label: 'Value'

# Schema for the configuration of the  String (long) field type.

field.storage_settings.string_long:
  type: mapping
  label: 'String (long) settings'
  mapping:
    case_sensitive:
      type: boolean
      label: 'Case sensitive'

field.value.string_long:
  type: mapping
  label: 'Default value'
  mapping:
    value:
      type: text
      label: 'Value'

# Schema for the configuration of the Password field type.
# This field type has no field instance settings, so no specific config schema type.
# @see `type: field.field_settings.*`
field.storage_settings.password:
  type: field.storage_settings.string
  label: 'Password settings'

# Schema for the configuration of the URI field type.
# This field type has no field instance settings, so no specific config schema type.
# @see `type: field.field_settings.*`
field.storage_settings.uri:
  type: field.storage_settings.string
  label: 'URI settings'
  mapping:
    max_length:
      type: integer
      label: 'Maximum length'
    case_sensitive:
      type: boolean
      label: 'Case sensitive'

field.value.uri:
  type: mapping
  label: 'Default value'
  mapping:
    value:
      type: string
      label: 'Value'

# Schema for the configuration of the Created field type.
# This field type has no field storage settings, so no specific config schema type.
# @see `type: field.storage_settings.*`
# This field type has no field instance settings, so no specific config schema type.
# @see `type: field.field_settings.*`
field.value.created:
  type: mapping
  label: 'Default value'
  mapping:
    value:
      type: integer
      label: 'Value'

# Schema for the configuration of the Changed field type.
# This field type has no field storage settings, so no specific config schema type.
# @see `type: field.storage_settings.*`
# This field type has no field instance settings, so no specific config schema type.
# @see `type: field.field_settings.*`
field.value.changed:
  type: mapping
  label: 'Default value'
  mapping:
    value:
      type: integer
      label: 'Value'

# Schema for the configuration of the Entity reference field type.

field.storage_settings.entity_reference:
  type: mapping
  label: 'Entity reference field storage settings'
  mapping:
    target_type:
      type: string
      label: 'Type of item to reference'

field.field_settings.entity_reference:
  type: mapping
  label: 'Entity reference field settings'
  mapping:
    handler:
      type: string
      label: 'Reference method'
      constraints:
        PluginExists:
          manager: plugin.manager.entity_reference_selection
          interface: 'Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface'
          # @todo Remove this line and explicitly require valid entity reference
          # selection plugin IDs in https://drupal.org/i/3420198.
          allowFallback: true
    handler_settings:
      type: entity_reference_selection.[%parent.handler]
      label: 'Entity reference selection plugin settings'

field.value.entity_reference:
  type: mapping
  label: 'Default value'
  mapping:
    target_id:
      type: string
      label: 'Value'
    target_uuid:
      type: uuid

# Schema for the configuration of the Boolean field type.

field.field_settings.boolean:
  label: 'Boolean settings'
  type: mapping
  mapping:
    on_label:
      type: required_label
      label: 'On label'
    off_label:
      type: required_label
      label: 'Off label'

field.value.boolean:
  type: mapping
  mapping:
    value:
      type: integer
      label: 'Value'

# Schema for the configuration of the Email field type.
# This field type has no field storage settings, so no specific config schema type.
# @see `type: field.storage_settings.*`
field.field_settings.email:
  type: mapping
  label: 'Email settings'
  sequence:
    type: string
    label: 'Setting'

field.value.email:
  type: mapping
  label: 'Default value'
  mapping:
    value:
      type: email
      label: 'Value'

# Schema for the configuration of the Integer field type.

field.storage_settings.integer:
  type: mapping
  label: 'Integer settings'
  mapping:
    unsigned:
      type: boolean
      label: 'Unsigned'
    size:
      type: string
      label: 'Database storage size'

field.field_settings.integer:
  type: mapping
  label: 'Integer'
  mapping:
    min:
      type: integer
      label: 'Minimum'
    max:
      type: integer
      label: 'Maximum'
    prefix:
      type: label
      label: 'Prefix'
    suffix:
      type: label
      label: 'Suffix'

field.value.integer:
  type: mapping
  label: 'Default value'
  mapping:
    value:
      type: integer
      label: 'Value'

# Schema for the configuration of the Decimal field type.

field.storage_settings.decimal:
  type: mapping
  label: 'Decimal settings'
  mapping:
    precision:
      type: integer
      label: 'Precision'
    scale:
      type: integer
      label: 'Scale'

field.field_settings.decimal:
  type: mapping
  label: 'Decimal settings'
  mapping:
    min:
      type: float
      label: 'Minimum'
    max:
      type: float
      label: 'Maximum'
    prefix:
      type: label
      label: 'Prefix'
    suffix:
      type: label
      label: 'Suffix'

field.value.decimal:
  type: mapping
  label: 'Default value'
  mapping:
    value:
      type: float
      label: 'Value'

# Schema for the configuration of the Float field type.

field.storage_settings.float:
  type: mapping
  label: 'Float settings'

field.field_settings.float:
  type: mapping
  label: 'Float settings'
  mapping:
    min:
      type: float
      label: 'Minimum'
    max:
      type: float
      label: 'Maximum'
    prefix:
      type: label
      label: 'Prefix'
    suffix:
      type: label
      label: 'Suffix'

field.value.float:
  type: mapping
  label: 'Default value'
  mapping:
    value:
      type: float
      label: 'Value'

# Schema for the configuration of the Timestamp field type.

field.value.timestamp:
  type: mapping
  label: 'Timestamp value'
  mapping:
    value:
      type: timestamp
      label: 'Value'

# Text with a text format.
text_format:
  type: mapping
  label: 'Text with text format'
  # We declare the entire mapping of text and text format as translatable. This
  # causes the entire mapping to be saved to the language overrides of the
  # configuration. Storing only the (to be formatted) text could result in
  # security problems in case the text format of the source text is changed.
  translatable: true
  mapping:
    value:
      type: text
      label: 'Text'
      # Mark the actual text as translatable (in addition to the entire mapping
      # being marked as translatable) so that shipped configuration with
      # formatted text can participate in the string translation system.
      translatable: true
    format:
      type: string
      label: 'Text format'
      # The text format should not be translated as part of the string
      # translation system, so this is not marked as translatable.

# Base schema for all entity reference selection handler schemas.
entity_reference_selection:
  type: mapping
  label: 'Entity reference selection handler settings'
  mapping:
    target_type:
      type: string
      label: 'Type of item to reference'

# Schema for all entity reference selection handlers that are not providing a
# specific schema.
entity_reference_selection.*:
  type: entity_reference_selection

# Schema for the entity reference 'default' selection handler settings.
entity_reference_selection.default:
  type: entity_reference_selection
  label: 'Default selection handler settings'
  mapping:
    target_bundles:
      type: sequence
      label: 'types'
      nullable: true
      sequence:
        type: string
        label: 'Bundle'
    sort:
      type: mapping
      label: 'Sort settings'
      mapping:
        field:
          type: string
          label: 'Sort by'
        direction:
          type: string
          label: 'Sort direction'
    auto_create:
      type: boolean
      label: 'Create referenced entities if they don''t already exist'
    auto_create_bundle:
      type: string
      label: 'Bundle assigned to the auto-created entities.'

# Schema for all entity reference 'default:*' selection handlers that are not
# providing a specific schema.
entity_reference_selection.default:*:
  type: entity_reference_selection.default
