packages/sql-faker/src/Generation/Lexeme/SpacingConstraint.php
1<?php
2
3declare(strict_types=1);
4
5namespace SqlFaker\Generation\Lexeme;
6
7/**
8 * Allowed boundary spellings with every contributing rule retained for diagnostics.
9 */
10final class SpacingConstraint
11{
12 /**
13 * Allows adjacent lexemes with no separator.
14 */
15 public const JOIN = 1;
16 /**
17 * Allows a single space between lexemes.
18 */
19 public const SPACE = 2;
20 /**
21 * Allows either supported separator form.
22 */
23 public const EITHER = 3;
24
25 /**
26 * @param list<string> $rules
27 */
28 public function __construct(public readonly int $allowed = self::EITHER, public readonly array $rules = [])
29 {
30 }
31
32 /**
33 * Keeps only separators allowed by both constraints and retains both sources.
34 */
35 public function intersect(self $other): self
36 {
37 return new self($this->allowed & $other->allowed, array_values(array_unique([...$this->rules, ...$other->rules])));
38 }
39
40 /**
41 * Selects the default single space when permitted, a join otherwise, or null on contradiction.
42 */
43 public function separator(): ?string
44 {
45 if (($this->allowed & self::SPACE) !== 0) {
46 return ' ';
47 }
48 return ($this->allowed & self::JOIN) !== 0 ? '' : null;
49 }
50}
51