View source  
  <?php
namespace Drupal\ui_patterns\TypedData;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\TypedData\ListDataDefinition;
use Drupal\Core\TypedData\MapDataDefinition;
class PatternDataDefinition extends MapDataDefinition {
  
  const MACHINE_NAME = '/^(?!(%s)$)(?=[A-Za-z0-9_-]+$).*$/';
  
  protected $reserved = [
    'id',
    'type',
    'theme',
    'context',
    'use',
    'attributes',
  ];
  
  public function getPropertyDefinitions() {
    $this
      ->setMainPropertyName('id')
      ->setPropertyDefinition('id', $this
      ->getMachineNameDefinition()
      ->setRequired(TRUE))
      ->setPropertyDefinition('label', DataDefinition::create('string')
      ->setRequired(TRUE))
      ->setPropertyDefinition('base path', DataDefinition::create('string')
      ->setRequired(TRUE))
      ->setPropertyDefinition('file name', DataDefinition::create('string')
      ->setRequired(TRUE))
      ->setPropertyDefinition('provider', DataDefinition::create('string')
      ->setRequired(TRUE))
      ->setPropertyDefinition('fields', $this
      ->getFieldsDefinition())
      ->setPropertyDefinition('variants', $this
      ->getVariantsDefinition())
      ->setPropertyDefinition('theme hook', DataDefinition::create('string')
      ->setRequired(TRUE))
      ->setPropertyDefinition('description', DataDefinition::create('string'))
      ->setPropertyDefinition('use', DataDefinition::create('string'))
      ->setPropertyDefinition('tags', ListDataDefinition::create('string'))
      ->setPropertyDefinition('custom theme hook', DataDefinition::create('boolean'))
      ->setPropertyDefinition('template', DataDefinition::create('string'))
      ->setPropertyDefinition('libraries', DataDefinition::create('any'));
    return $this->propertyDefinitions;
  }
  
  protected function getMachineNameDefinition() {
    return DataDefinition::create('string')
      ->addConstraint('Regex', sprintf(self::MACHINE_NAME, implode('|', $this->reserved)));
  }
  
  protected function getFieldsDefinition() {
    return new ListDataDefinition([], MapDataDefinition::create()
      ->setPropertyDefinition('name', $this
      ->getMachineNameDefinition()
      ->setRequired(TRUE))
      ->setPropertyDefinition('label', DataDefinition::create('string')
      ->setRequired(TRUE))
      ->setPropertyDefinition('type', $this
      ->getMachineNameDefinition())
      ->setPropertyDefinition('description', DataDefinition::create('string'))
      ->setPropertyDefinition('preview', DataDefinition::create('any')));
  }
  
  protected function getVariantsDefinition() {
    return new ListDataDefinition([], MapDataDefinition::create()
      ->setPropertyDefinition('name', $this
      ->getMachineNameDefinition()
      ->setRequired(TRUE))
      ->setPropertyDefinition('label', DataDefinition::create('string')
      ->setRequired(TRUE))
      ->setPropertyDefinition('description', DataDefinition::create('string')));
  }
}