1: <?php
2:
3: declare(strict_types=1);
4:
5: /**
6: * This file is part of the Nexus MCP SDK package.
7: *
8: * (c) 2025 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
9: *
10: * For the full copyright and license information, please view
11: * the LICENSE file that was distributed with this source code.
12: */
13:
14: namespace Nexus\Mcp\Schema\Tool\ToolSchema;
15:
16: /**
17: * The `array` type is used for validating JSON indexed arrays.
18: *
19: * This schema follows JSON Schema Draft 2020-12.
20: *
21: * @extends ToolSchema<list<mixed>, array{
22: * type: 'array',
23: * description?: non-empty-string,
24: * title?: non-empty-string,
25: * minItems?: int<0, max>,
26: * maxItems?: int<0, max>,
27: * uniqueItems?: bool,
28: * prefixItems?: array<string, mixed>,
29: * items?: array<string, mixed>,
30: * default?: list<mixed>,
31: * }>
32: */
33: final class ArrayType extends ToolSchema
34: {
35: /**
36: * @var null|int<0, max>
37: */
38: private ?int $minItems = null;
39:
40: /**
41: * @var null|int<0, max>
42: */
43: private ?int $maxItems = null;
44:
45: private ?bool $uniqueItems = null;
46:
47: /**
48: * @var null|array<string, mixed>
49: */
50: private ?array $prefixItems = null;
51:
52: /**
53: * @var null|array<string, mixed>
54: */
55: private ?array $items = null;
56:
57: public function minItems(int $minItems): self
58: {
59: if ($minItems < 0) {
60: throw new \InvalidArgumentException('The minimum number of items must be a non-negative integer.');
61: }
62:
63: $this->minItems = $minItems;
64:
65: return $this;
66: }
67:
68: public function maxItems(int $maxItems): self
69: {
70: if ($maxItems < 0) {
71: throw new \InvalidArgumentException('The maximum number of items must be a non-negative integer.');
72: }
73:
74: $this->maxItems = $maxItems;
75:
76: return $this;
77: }
78:
79: public function uniqueItems(bool $uniqueItems): self
80: {
81: $this->uniqueItems = $uniqueItems;
82:
83: return $this;
84: }
85:
86: /**
87: * An array is valid against this keyword if items are valid against the corresponding schemas provided
88: * by the keyword value. The value of this keyword must be an array of valid json schemas, and each item
89: * must be valid against the schema defined at the same position (index).
90: *
91: * @template T
92: * @template U of array<string, mixed>
93: *
94: * @param ToolSchema<T, U> $prefixItems
95: */
96: public function prefixItems(ToolSchema $prefixItems): self
97: {
98: $this->prefixItems = $prefixItems->toArray();
99:
100: return $this;
101: }
102:
103: /**
104: * An array is valid against this keyword if all _unchecked_ items are valid against the schema
105: * defined by the keyword value. An item is considered _unchecked_ if `prefixItems` keyword
106: * contains an array of schemas and doesn't have a corresponding position (index).
107: *
108: * @template T
109: * @template U of array<string, mixed>
110: *
111: * @param ToolSchema<T, U> $items
112: */
113: public function items(ToolSchema $items): self
114: {
115: $this->items = $items->toArray();
116:
117: return $this;
118: }
119:
120: #[\Override]
121: public function toArray(): array
122: {
123: return array_filter([
124: 'type' => 'array',
125: 'description' => $this->description,
126: 'title' => $this->title,
127: 'minItems' => $this->minItems,
128: 'maxItems' => $this->maxItems,
129: 'uniqueItems' => $this->uniqueItems,
130: 'prefixItems' => $this->prefixItems,
131: 'items' => $this->items,
132: 'default' => $this->default,
133: ], static fn(mixed $value): bool => null !== $value);
134: }
135: }
136: