Skip to content

Commit f7d9b72

Browse files
authored
Merge pull request #63 from slackhq/ih_support_unique_hackEnum
Support hackEnum and unique constraints together
2 parents d7a3578 + bd64a86 commit f7d9b72

File tree

4 files changed

+95
-5
lines changed

4 files changed

+95
-5
lines changed

src/Codegen/Constraints/ArrayBuilder.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Slack\Hack\JsonSchema\Codegen;
44

5+
use namespace HH\Lib\C;
56
use type Facebook\HackCodegen\{CodegenMethod, HackBuilder, HackBuilderValues};
67

78
type TArraySchema = shape(
@@ -264,12 +265,12 @@ private function setupSingleItemSchemaBuilder(): void {
264265
* Determine the type of hack array we will generate.
265266
*/
266267
private function determineHackArrayType(): void {
267-
if ($this->schema['uniqueItems'] ?? false) {
268-
$item_type = $this->singleItemSchemaBuilder?->getType();
269-
if ($item_type === 'string' || $item_type === 'int') {
268+
$items = $this->typed_schema['items'] ?? null;
269+
if (($this->schema['uniqueItems'] ?? false) && $this->isSchema($items)) {
270+
$schema = type_assert_type($items, TArraySchemaItemsSingleSchema::class);
271+
if (C\contains(keyset[TSchemaType::INTEGER_T, TSchemaType::STRING_T], $schema['type'] ?? null)) {
270272
$this->hackArrayType = HackArrayType::KEYSET;
271273
}
272274
}
273275
}
274-
275276
}

tests/ArraySchemaValidatorTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,16 @@ public function testHackEnumItems(): void {
230230
expect($validated)->toEqual(shape('hack_enum_items' => vec[TestStringEnum::ABC, TestStringEnum::DEF]));
231231
}
232232

233+
public function testUniqueHackEnum(): void {
234+
$input = vec['foo', 'bar', 'foo'];
235+
236+
$validator = new ArraySchemaValidator(dict['unique_hack_enum_items' => $input]);
237+
$validator->validate();
238+
239+
expect($validator->isValid())->toBeTrue();
240+
$validated = $validator->getValidatedInput();
241+
242+
expect($validated)->toEqual(shape('unique_hack_enum_items' => keyset[TestStringEnum::ABC, TestStringEnum::DEF]));
243+
}
244+
233245
}

tests/examples/array-schema.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,16 @@
5353
}
5454
},
5555
"hack_enum_items": {
56+
"type": "array",
57+
"items": {
58+
"type": "string",
59+
"hackEnum": "Slack\\Hack\\JsonSchema\\Tests\\TestStringEnum"
60+
}
61+
},
62+
"unique_hack_enum_items": {
5663
"type": "array",
5764
"uniqueItems": true,
65+
"coerce": true,
5866
"items": {
5967
"type": "string",
6068
"hackEnum": "Slack\\Hack\\JsonSchema\\Tests\\TestStringEnum"

tests/examples/codegen/ArraySchemaValidator.php

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* To re-generate this file run `make test`
66
*
77
*
8-
* @generated SignedSource<<87191fcc75856e69e35c2652ba5f9836>>
8+
* @generated SignedSource<<7f20c3eead69c411ea999a821ff7167a>>
99
*/
1010
namespace Slack\Hack\JsonSchema\Tests\Generated;
1111
use namespace Slack\Hack\JsonSchema;
@@ -25,6 +25,7 @@
2525
?'unique_numbers_coerce' => keyset<int>,
2626
?'unsupported_unique_items' => vec<TArraySchemaValidatorPropertiesUnsupportedUniqueItemsItems>,
2727
?'hack_enum_items' => vec<\Slack\Hack\JsonSchema\Tests\TestStringEnum>,
28+
?'unique_hack_enum_items' => keyset<\Slack\Hack\JsonSchema\Tests\TestStringEnum>,
2829
...
2930
);
3031

@@ -392,6 +393,63 @@ public static function check(
392393
}
393394
}
394395

396+
final class ArraySchemaValidatorPropertiesUniqueHackEnumItemsItems {
397+
398+
private static bool $coerce = false;
399+
400+
public static function check(
401+
mixed $input,
402+
string $pointer,
403+
): \Slack\Hack\JsonSchema\Tests\TestStringEnum {
404+
$typed = Constraints\StringConstraint::check($input, $pointer, self::$coerce);
405+
406+
$typed = Constraints\HackEnumConstraint::check(
407+
$typed,
408+
\Slack\Hack\JsonSchema\Tests\TestStringEnum::class,
409+
$pointer,
410+
);
411+
return $typed;
412+
}
413+
}
414+
415+
final class ArraySchemaValidatorPropertiesUniqueHackEnumItems {
416+
417+
private static bool $coerce = true;
418+
419+
public static function check(
420+
mixed $input,
421+
string $pointer,
422+
): keyset<\Slack\Hack\JsonSchema\Tests\TestStringEnum> {
423+
$typed = Constraints\ArrayConstraint::check($input, $pointer, self::$coerce);
424+
425+
$output = vec[];
426+
$errors = vec[];
427+
428+
foreach ($typed as $index => $value) {
429+
try {
430+
$output[] = ArraySchemaValidatorPropertiesUniqueHackEnumItemsItems::check(
431+
$value,
432+
JsonSchema\get_pointer($pointer, (string) $index),
433+
);
434+
} catch (JsonSchema\InvalidFieldException $e) {
435+
$errors = \HH\Lib\Vec\concat($errors, $e->errors);
436+
}
437+
}
438+
439+
if (\HH\Lib\C\count($errors)) {
440+
throw new JsonSchema\InvalidFieldException($pointer, $errors);
441+
}
442+
443+
$output = Constraints\ArrayUniqueItemsConstraint::check(
444+
$output,
445+
$pointer,
446+
self::$coerce,
447+
);
448+
449+
return $output;
450+
}
451+
}
452+
395453
final class ArraySchemaValidator
396454
extends JsonSchema\BaseValidator<TArraySchemaValidator> {
397455

@@ -500,6 +558,17 @@ public static function check(
500558
}
501559
}
502560

561+
if (\HH\Lib\C\contains_key($typed, 'unique_hack_enum_items')) {
562+
try {
563+
$output['unique_hack_enum_items'] = ArraySchemaValidatorPropertiesUniqueHackEnumItems::check(
564+
$typed['unique_hack_enum_items'],
565+
JsonSchema\get_pointer($pointer, 'unique_hack_enum_items'),
566+
);
567+
} catch (JsonSchema\InvalidFieldException $e) {
568+
$errors = \HH\Lib\Vec\concat($errors, $e->errors);
569+
}
570+
}
571+
503572
if (\HH\Lib\C\count($errors)) {
504573
throw new JsonSchema\InvalidFieldException($pointer, $errors);
505574
}

0 commit comments

Comments
 (0)