diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 76daa54f..47bf45fb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,7 +26,7 @@ jobs:
run: composer install --no-interaction --prefer-dist --optimize-autoloader
- name: PHPCS checks
- run: ./vendor/bin/phpcs ${{ github.workspace }}/src
+ run: ./vendor/bin/phpcs ${{ github.workspace }}/src/WordPress
test-unit:
runs-on: ${{ matrix.os }}
diff --git a/composer.json b/composer.json
index 9eeb687e..729d401f 100644
--- a/composer.json
+++ b/composer.json
@@ -14,7 +14,8 @@
"nette/php-generator": "*",
"jane-php/json-schema": "*",
"bamarni/composer-bin-plugin": "*",
- "wp-coding-standards/wpcs": "3.0"
+ "wp-coding-standards/wpcs": "3.0",
+ "phpcompatibility/php-compatibility": "^9.3"
},
"config": {
"optimize-autoloader": true,
diff --git a/composer.lock b/composer.lock
index 46abc4a7..3b34e33b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "71709bd85d8f5389e7b741c8f505994c",
+ "content-hash": "3fe66d0e097d4dbd4858fa622220f097",
"packages": [
{
"name": "pimple/pimple",
@@ -1858,6 +1858,68 @@
},
"time": "2022-01-11T14:28:07+00:00"
},
+ {
+ "name": "phpcompatibility/php-compatibility",
+ "version": "9.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
+ "reference": "9fb324479acf6f39452e0655d2429cc0d3914243"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243",
+ "reference": "9fb324479acf6f39452e0655d2429cc0d3914243",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "squizlabs/php_codesniffer": "^2.3 || ^3.0.2"
+ },
+ "conflict": {
+ "squizlabs/php_codesniffer": "2.6.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0"
+ },
+ "suggest": {
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.",
+ "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
+ },
+ "type": "phpcodesniffer-standard",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "LGPL-3.0-or-later"
+ ],
+ "authors": [
+ {
+ "name": "Wim Godden",
+ "homepage": "https://github.com/wimg",
+ "role": "lead"
+ },
+ {
+ "name": "Juliette Reinders Folmer",
+ "homepage": "https://github.com/jrfnl",
+ "role": "lead"
+ },
+ {
+ "name": "Contributors",
+ "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors"
+ }
+ ],
+ "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.",
+ "homepage": "http://techblog.wimgodden.be/tag/codesniffer/",
+ "keywords": [
+ "compatibility",
+ "phpcs",
+ "standards"
+ ],
+ "support": {
+ "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues",
+ "source": "https://github.com/PHPCompatibility/PHPCompatibility"
+ },
+ "time": "2019-12-27T09:44:58+00:00"
+ },
{
"name": "phpcsstandards/phpcsextra",
"version": "1.2.1",
diff --git a/phpcs.xml b/phpcs.xml
index 5645e28d..d5acadf5 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -3,6 +3,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/WordPress/AsyncHttp/Client.php b/src/WordPress/AsyncHttp/Client.php
index a5e68f60..0d7484ab 100644
--- a/src/WordPress/AsyncHttp/Client.php
+++ b/src/WordPress/AsyncHttp/Client.php
@@ -94,7 +94,7 @@ class Client {
protected $queue_needs_processing = false;
public function __construct() {
- $this->requests = new Map();
+ $this->requests = new Map();
$this->onProgress = function () {
};
}
@@ -163,13 +163,13 @@ public function get_stream( $request ) {
}
/**
- * @param \WordPress\AsyncHttp\Request $request
- */
- protected function enqueue_request( $request ) {
- $stream = StreamWrapper::create_resource(
+ * @param \WordPress\AsyncHttp\Request $request
+ */
+ protected function enqueue_request( $request ) {
+ $stream = StreamWrapper::create_resource(
new StreamData( $request, $this )
);
- $this->requests[ $request ] = new RequestInfo( $stream );
+ $this->requests[ $request ] = new RequestInfo( $stream );
$this->queue_needs_processing = true;
return $stream;
@@ -182,18 +182,18 @@ public function process_queue() {
$this->queue_needs_processing = false;
$active_requests = count( $this->get_streamed_requests() );
- $backfill = $this->concurrency - $active_requests;
+ $backfill = $this->concurrency - $active_requests;
if ( $backfill <= 0 ) {
return;
}
- $enqueued = array_slice( $this->get_enqueued_request(), 0, $backfill );
+ $enqueued = array_slice( $this->get_enqueued_request(), 0, $backfill );
list( $streams, $response_headers ) = streams_send_http_requests( $enqueued );
foreach ( $streams as $k => $stream ) {
- $request = $enqueued[ $k ];
- $total = $response_headers[ $k ]['headers']['content-length'];
- $this->requests[ $request ]->state = RequestInfo::STATE_STREAMING;
+ $request = $enqueued[ $k ];
+ $total = $response_headers[ $k ]['headers']['content-length'];
+ $this->requests[ $request ]->state = RequestInfo::STATE_STREAMING;
$this->requests[ $request ]->stream = stream_monitor_progress(
$stream,
function ( $downloaded ) use ( $request, $total ) {
@@ -205,7 +205,7 @@ function ( $downloaded ) use ( $request, $total ) {
}
protected function get_enqueued_request() {
- $enqueued_requests = [];
+ $enqueued_requests = array();
foreach ( $this->requests as $request => $info ) {
if ( $info->state === RequestInfo::STATE_ENQUEUED ) {
$enqueued_requests[] = $request;
@@ -216,7 +216,7 @@ protected function get_enqueued_request() {
}
protected function get_streamed_requests() {
- $active_requests = [];
+ $active_requests = array();
foreach ( $this->requests as $request => $info ) {
if ( $info->state !== RequestInfo::STATE_ENQUEUED ) {
$active_requests[] = $request;
@@ -245,12 +245,15 @@ public function read_bytes( $request, $length ) {
}
$request_info = $this->requests[ $request ];
- $stream = $request_info->stream;
+ $stream = $request_info->stream;
$active_requests = $this->get_streamed_requests();
- $active_streams = array_map( function ( $request ) {
- return $this->requests[ $request ]->stream;
- }, $active_requests );
+ $active_streams = array_map(
+ function ( $request ) {
+ return $this->requests[ $request ]->stream;
+ },
+ $active_requests
+ );
if ( ! count( $active_streams ) ) {
return false;
@@ -264,7 +267,7 @@ public function read_bytes( $request, $length ) {
}
if ( strlen( $request_info->buffer ) >= $length ) {
- $buffered = substr( $request_info->buffer, 0, $length );
+ $buffered = substr( $request_info->buffer, 0, $length );
$request_info->buffer = substr( $request_info->buffer, $length );
return $buffered;
@@ -274,9 +277,12 @@ public function read_bytes( $request, $length ) {
return $request_info->buffer;
}
- $active_streams = array_filter( $active_streams, function ( $stream ) {
- return ! feof( $stream );
- } );
+ $active_streams = array_filter(
+ $active_streams,
+ function ( $stream ) {
+ return ! feof( $stream );
+ }
+ );
if ( ! count( $active_streams ) ) {
continue;
}
diff --git a/src/WordPress/AsyncHttp/Request.php b/src/WordPress/AsyncHttp/Request.php
index a7999386..5f681b7c 100644
--- a/src/WordPress/AsyncHttp/Request.php
+++ b/src/WordPress/AsyncHttp/Request.php
@@ -12,5 +12,4 @@ class Request {
public function __construct( string $url ) {
$this->url = $url;
}
-
}
diff --git a/src/WordPress/AsyncHttp/RequestInfo.php b/src/WordPress/AsyncHttp/RequestInfo.php
index b2ddc71c..6cae6c81 100644
--- a/src/WordPress/AsyncHttp/RequestInfo.php
+++ b/src/WordPress/AsyncHttp/RequestInfo.php
@@ -17,8 +17,7 @@ public function __construct( $stream ) {
$this->stream = $stream;
}
- public function isFinished() {
+ public function is_finished() {
return $this->state === self::STATE_FINISHED;
}
-
}
diff --git a/src/WordPress/AsyncHttp/StreamData.php b/src/WordPress/AsyncHttp/StreamData.php
index 7bd5546e..0d36f117 100644
--- a/src/WordPress/AsyncHttp/StreamData.php
+++ b/src/WordPress/AsyncHttp/StreamData.php
@@ -12,7 +12,6 @@ class StreamData extends VanillaStreamWrapperData {
public function __construct( Request $request, Client $group ) {
parent::__construct( null );
$this->request = $request;
- $this->client = $group;
+ $this->client = $group;
}
-
}
diff --git a/src/WordPress/AsyncHttp/StreamWrapper.php b/src/WordPress/AsyncHttp/StreamWrapper.php
index f661a4ba..f48f3f23 100644
--- a/src/WordPress/AsyncHttp/StreamWrapper.php
+++ b/src/WordPress/AsyncHttp/StreamWrapper.php
@@ -31,9 +31,9 @@ public function stream_open( $path, $mode, $options, &$opened_path ) {
}
/**
- * @param int $cast_as
- */
- public function stream_cast( $cast_as ) {
+ * @param int $cast_as
+ */
+ public function stream_cast( $cast_as ) {
$this->initialize();
return parent::stream_cast( $cast_as );
@@ -103,7 +103,6 @@ public function stream_seek( $offset, $whence ) {
* Let's refuse to call fclose() in that scenario.
*/
protected function has_valid_stream() {
- return get_resource_type( $this->stream ) !== "Unknown";
+ return get_resource_type( $this->stream ) !== 'Unknown';
}
-
}
diff --git a/src/WordPress/AsyncHttp/async_http_streams.php b/src/WordPress/AsyncHttp/async_http_streams.php
index 0b9e9d84..16a1f58d 100644
--- a/src/WordPress/AsyncHttp/async_http_streams.php
+++ b/src/WordPress/AsyncHttp/async_http_streams.php
@@ -20,7 +20,7 @@
* @see stream_http_open_nonblocking
*/
function streams_http_open_nonblocking( $urls ) {
- $streams = [];
+ $streams = array();
foreach ( $urls as $k => $url ) {
$streams[ $k ] = stream_http_open_nonblocking( $url );
}
@@ -44,9 +44,9 @@ function streams_http_open_nonblocking( $urls ) {
* @throws Exception If unable to open the stream.
*/
function stream_http_open_nonblocking( $url ) {
- $parts = parse_url( $url );
+ $parts = parse_url( $url );
$scheme = $parts['scheme'];
- if ( ! in_array( $scheme, [ 'http', 'https' ] ) ) {
+ if ( ! in_array( $scheme, array( 'http', 'https' ) ) ) {
throw new InvalidArgumentException( 'Invalid scheme – only http:// and https:// URLs are supported' );
}
@@ -55,13 +55,13 @@ function stream_http_open_nonblocking( $url ) {
// Create stream context
$context = stream_context_create(
- [
- 'socket' => [
+ array(
+ 'socket' => array(
'isSsl' => $scheme === 'https',
'originalUrl' => $url,
'socketUrl' => 'tcp://' . $host . ':' . $port,
- ],
- ]
+ ),
+ )
);
$stream = stream_socket_client(
@@ -92,24 +92,23 @@ function stream_http_open_nonblocking( $url ) {
* @throws Exception If there is an error enabling crypto or if stream_select times out.
*/
function streams_http_requests_send( $streams ) {
- $read = $except = null;
+ $read = $except = null;
$remaining_streams = $streams;
while ( count( $remaining_streams ) ) {
$write = $remaining_streams;
sleep( 2 );
+ // phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged
$ready = @stream_select( $read, $write, $except, 5, 5000000 );
if ( $ready === false ) {
- throw new Exception( "Error: " . error_get_last()['message'] );
+ throw new Exception( 'Error: ' . error_get_last()['message'] );
} elseif ( $ready <= 0 ) {
- var_dump( $ready );
- die();
- throw new Exception( "stream_select timed out" );
+ throw new Exception( 'stream_select timed out' );
}
foreach ( $write as $k => $stream ) {
$enabled_crypto = stream_socket_enable_crypto( $stream, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT );
if ( false === $enabled_crypto ) {
- throw new Exception( "Failed to enable crypto: " . error_get_last()['message'] );
+ throw new Exception( 'Failed to enable crypto: ' . error_get_last()['message'] );
} elseif ( 0 === $enabled_crypto ) {
// Wait for the handshake to complete
} else {
@@ -128,8 +127,8 @@ function streams_http_requests_send( $streams ) {
* Waits for response bytes to be available in the given streams.
*
* @param array $streams The array of streams to wait for.
- * @param int $length The number of bytes to read from each stream.
- * @param int $timeout_microseconds The timeout in microseconds for the stream_select function.
+ * @param int $length The number of bytes to read from each stream.
+ * @param int $timeout_microseconds The timeout in microseconds for the stream_select function.
*
* @return array|false An array of chunks read from the streams, or false if no streams are available.
* @throws Exception If an error occurs during the stream_select operation or if the operation times out.
@@ -139,16 +138,17 @@ function streams_http_response_await_bytes( $streams, $length, $timeout_microsec
if ( count( $read ) === 0 ) {
return false;
}
- $write = [];
+ $write = array();
$except = null;
+ // phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged
$ready = @stream_select( $read, $write, $except, 0, $timeout_microseconds );
if ( $ready === false ) {
- throw new Exception( "Could not retrieve response bytes: " . error_get_last()['message'] );
+ throw new Exception( 'Could not retrieve response bytes: ' . error_get_last()['message'] );
} elseif ( $ready <= 0 ) {
- throw new Exception( "stream_select timed out" );
+ throw new Exception( 'stream_select timed out' );
}
- $chunks = [];
+ $chunks = array();
foreach ( $read as $k => $stream ) {
$chunks[ $k ] = fread( $stream, $length );
}
@@ -163,29 +163,28 @@ function streams_http_response_await_bytes( $streams, $length, $timeout_microsec
*
* @return array An array containing the parsed status and headers.
*/
-
function parse_http_headers( string $headers ) {
- $lines = explode( "\r\n", $headers );
- $status = array_shift( $lines );
- $status = explode( ' ', $status );
- $status = [
+ $lines = explode( "\r\n", $headers );
+ $status = array_shift( $lines );
+ $status = explode( ' ', $status );
+ $status = array(
'protocol' => $status[0],
'code' => $status[1],
'message' => $status[2],
- ];
- $headers = [];
+ );
+ $headers = array();
foreach ( $lines as $line ) {
- if ( strpos($line, ': ') === false ) {
+ if ( strpos( $line, ': ' ) === false ) {
continue;
}
- $line = explode( ': ', $line );
+ $line = explode( ': ', $line );
$headers[ strtolower( $line[0] ) ] = $line[1];
}
- return [
+ return array(
'status' => $status,
'headers' => $headers,
- ];
+ );
}
/**
@@ -195,11 +194,10 @@ function parse_http_headers( string $headers ) {
*
* @return string The prepared HTTP request string.
*/
-
function stream_http_prepare_request_bytes( $url ) {
- $parts = parse_url( $url );
- $host = $parts['host'];
- $path = $parts['path'] . ( isset( $parts['query'] ) ? '?' . $parts['query'] : '' );
+ $parts = parse_url( $url );
+ $host = $parts['host'];
+ $path = $parts['path'] . ( isset( $parts['query'] ) ? '?' . $parts['query'] : '' );
$request = << $stream ) {
$headers[ $k ] = '';
}
@@ -234,7 +232,7 @@ function streams_http_response_await_headers( $streams ) {
}
foreach ( $bytes as $k => $byte ) {
$headers[ $k ] .= $byte;
- if ( substr_compare($headers[ $k ], "\r\n\r\n", -strlen("\r\n\r\n")) === 0 ) {
+ if ( substr_compare( $headers[ $k ], "\r\n\r\n", - strlen( "\r\n\r\n" ) ) === 0 ) {
unset( $remaining_streams[ $k ] );
}
}
@@ -262,7 +260,7 @@ function stream_monitor_progress( $stream, $onProgress ) {
$stream,
function ( $data ) use ( $onProgress ) {
static $streamedBytes = 0;
- $streamedBytes += strlen( $data );
+ $streamedBytes += strlen( $data );
$onProgress( $streamedBytes );
}
)
@@ -278,23 +276,23 @@ function ( $data ) use ( $onProgress ) {
* @throws Exception If any of the requests fail with a non-successful HTTP code.
*/
function streams_send_http_requests( array $requests ) {
- $urls = [];
+ $urls = array();
foreach ( $requests as $k => $request ) {
$urls[ $k ] = $request->url;
}
- $redirects = $urls;
- $final_streams = [];
- $response_headers = [];
+ $redirects = $urls;
+ $final_streams = array();
+ $response_headers = array();
do {
$streams = streams_http_open_nonblocking( $redirects );
streams_http_requests_send( $streams );
- $redirects = [];
- $headers = streams_http_response_await_headers( $streams );
+ $redirects = array();
+ $headers = streams_http_response_await_headers( $streams );
foreach ( array_keys( $headers ) as $k ) {
$code = $headers[ $k ]['status']['code'];
if ( $code > 399 || $code < 200 ) {
- throw new Exception( "Failed to download file " . $requests[ $k ]->url . ": Server responded with HTTP code " . $code );
+ throw new Exception( 'Failed to download file ' . $requests[ $k ]->url . ': Server responded with HTTP code ' . $code );
}
if ( isset( $headers[ $k ]['headers']['location'] ) ) {
$redirects[ $k ] = $headers[ $k ]['headers']['location'];
@@ -302,10 +300,10 @@ function streams_send_http_requests( array $requests ) {
continue;
}
- $final_streams[ $k ] = $streams[ $k ];
+ $final_streams[ $k ] = $streams[ $k ];
$response_headers[ $k ] = $headers[ $k ];
}
} while ( count( $redirects ) );
- return [ $final_streams, $response_headers ];
+ return array( $final_streams, $response_headers );
}
diff --git a/src/WordPress/Blueprints/BlueprintException.php b/src/WordPress/Blueprints/BlueprintException.php
index a53c7dfc..3fd991cf 100644
--- a/src/WordPress/Blueprints/BlueprintException.php
+++ b/src/WordPress/Blueprints/BlueprintException.php
@@ -4,7 +4,7 @@
use Exception;
-class BlueprintException extends Exception
-{
+class BlueprintException extends Exception {
+
}
diff --git a/src/WordPress/Blueprints/BlueprintMapper.php b/src/WordPress/Blueprints/BlueprintMapper.php
index 32d62944..c66c89fe 100644
--- a/src/WordPress/Blueprints/BlueprintMapper.php
+++ b/src/WordPress/Blueprints/BlueprintMapper.php
@@ -24,7 +24,7 @@ public function __construct() {
ResourceDefinitionInterface::class => array( $this, 'resource_factory' ),
StepDefinitionInterface::class => array( $this, 'step_factory' ),
);
- $this->mapper = new JsonMapper( $custom_factories );
+ $this->mapper = new JsonMapper( $custom_factories );
}
/**
diff --git a/src/WordPress/Blueprints/BlueprintParser.php b/src/WordPress/Blueprints/BlueprintParser.php
index 728dcef6..28374406 100644
--- a/src/WordPress/Blueprints/BlueprintParser.php
+++ b/src/WordPress/Blueprints/BlueprintParser.php
@@ -56,9 +56,9 @@ public function parse( $raw_blueprint ) {
}
/**
- * @param \stdClass $data
- */
- public function fromObject( $data ) {
+ * @param \stdClass $data
+ */
+ public function fromObject( $data ) {
$result = $this->validator->validate( $data );
if ( ! $result->isValid() ) {
print_r( ( new ErrorFormatter() )->format( $result->error() ) );
@@ -68,9 +68,9 @@ public function fromObject( $data ) {
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
- */
- public function fromBlueprint( $blueprint ) {
+ * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
+ */
+ public function fromBlueprint( $blueprint ) {
$result = $this->validator->validate( $blueprint );
if ( ! $result->isValid() ) {
print_r( ( new ErrorFormatter() )->format( $result->error() ) );
diff --git a/src/WordPress/Blueprints/BlueprintValidator.php b/src/WordPress/Blueprints/BlueprintValidator.php
index a4fcc8fe..094b08d2 100644
--- a/src/WordPress/Blueprints/BlueprintValidator.php
+++ b/src/WordPress/Blueprints/BlueprintValidator.php
@@ -63,6 +63,4 @@ protected function removeNulls( $value ) {
return $value;
}
-
}
-
diff --git a/src/WordPress/Blueprints/Cache/FileCache.php b/src/WordPress/Blueprints/Cache/FileCache.php
index 534c6e58..5ba67132 100644
--- a/src/WordPress/Blueprints/Cache/FileCache.php
+++ b/src/WordPress/Blueprints/Cache/FileCache.php
@@ -32,15 +32,15 @@ public function __construct( $cacheDirectory = null ) {
try {
$this->filesystem->mkdir( $this->cacheDirectory );
} catch ( IOExceptionInterface $exception ) {
- echo "An error occurred while creating your cache directory at " . $exception->getPath();
+ echo 'An error occurred while creating your cache directory at ' . $exception->getPath();
}
}
}
/**
- * @return mixed
- */
- public function get( $key, $default = null ) {
+ * @return mixed
+ */
+ public function get( $key, $default = null ) {
$filepath = $this->getFilePathForKey( $key );
if ( ! file_exists( $filepath ) ) {
return $default;
@@ -53,7 +53,7 @@ public function get( $key, $default = null ) {
public function set( $key, $value, $ttl = null ): bool {
$filepath = $this->getFilePathForKey( $key );
- $data = serialize( $value );
+ $data = serialize( $value );
return file_put_contents( $filepath, $data ) !== false;
}
@@ -77,7 +77,7 @@ public function clear(): bool {
}
public function getMultiple( $keys, $default = null ): iterable {
- $result = [];
+ $result = array();
foreach ( $keys as $key ) {
$result[ $key ] = $this->get( $key, $default );
}
@@ -113,4 +113,3 @@ private function getFilePathForKey( $key ) {
return $this->cacheDirectory . DIRECTORY_SEPARATOR . sha1( $key );
}
}
-
diff --git a/src/WordPress/Blueprints/Compile/BlueprintCompiler.php b/src/WordPress/Blueprints/Compile/BlueprintCompiler.php
index 7934ed49..449028c8 100644
--- a/src/WordPress/Blueprints/Compile/BlueprintCompiler.php
+++ b/src/WordPress/Blueprints/Compile/BlueprintCompiler.php
@@ -23,19 +23,19 @@ public function __construct(
$stepRunnerFactory,
ResourceResolverInterface $resourceResolver
) {
- $this->resourceResolver = $resourceResolver;
+ $this->resourceResolver = $resourceResolver;
$this->stepRunnerFactory = $stepRunnerFactory;
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
- */
- public function compile( $blueprint ): CompiledBlueprint {
+ * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
+ */
+ public function compile( $blueprint ): CompiledBlueprint {
$blueprint->steps = array_merge( $this->expandShorthandsIntoSteps( $blueprint ), $blueprint->steps );
$progressTracker = new Tracker();
- $stepsStage = $progressTracker->stage( 0.6 );
- $resourcesStage = $progressTracker->stage( 0.4 );
+ $stepsStage = $progressTracker->stage( 0.6 );
+ $resourcesStage = $progressTracker->stage( 0.4 );
return new CompiledBlueprint(
$this->compileSteps( $blueprint, $stepsStage ),
@@ -46,14 +46,14 @@ public function compile( $blueprint ): CompiledBlueprint {
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
- */
- protected function expandShorthandsIntoSteps( $blueprint ) {
+ * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
+ */
+ protected function expandShorthandsIntoSteps( $blueprint ) {
// @TODO: This duplicates the logic in BlueprintComposer.
- // It cannot be easily reused because of the dichotomy between the
- // Step and Step model classes. Let's alter the code generation
- // to only generate a single model class for each schema object.
- $additional_steps = [];
+ // It cannot be easily reused because of the dichotomy between the
+ // Step and Step model classes. Let's alter the code generation
+ // to only generate a single model class for each schema object.
+ $additional_steps = array();
if ( $blueprint->WordPressVersion ) {
$additional_steps[] = ( new DownloadWordPressStep() )
->setWordPressZip(
@@ -65,7 +65,7 @@ protected function expandShorthandsIntoSteps( $blueprint ) {
( new UrlResource() )
->setUrl( 'https://downloads.wordpress.org/plugin/sqlite-database-integration.zip' )
);
-// @TODO: stream_select times out here:
+ // @TODO: stream_select times out here:
$additional_steps[] = ( new WriteFileStep() )
->setPath( 'wp-cli.phar' )
->setData( ( new UrlResource() )->setUrl( 'https://playground.wordpress.net/wp-cli.phar' ) );
@@ -73,15 +73,15 @@ protected function expandShorthandsIntoSteps( $blueprint ) {
->setOptions( new WordPressInstallationOptions() );
}
if ( $blueprint->constants ) {
- $step = new DefineWpConfigConstsStep();
- $step->consts = $blueprint->constants;
+ $step = new DefineWpConfigConstsStep();
+ $step->consts = $blueprint->constants;
$additional_steps[] = $step;
}
if ( $blueprint->plugins ) {
foreach ( $blueprint->plugins as $plugin ) {
- $step = new InstallPluginStep();
+ $step = new InstallPluginStep();
$step->pluginZipFile = $plugin;
- $additional_steps[] = $step;
+ $additional_steps[] = $step;
}
}
if ( $blueprint->siteOptions ) {
@@ -94,10 +94,10 @@ protected function expandShorthandsIntoSteps( $blueprint ) {
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
- * @param \WordPress\Blueprints\Progress\Tracker $progress
- */
- protected function compileSteps( $blueprint, $progress ) {
+ * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
+ * @param \WordPress\Blueprints\Progress\Tracker $progress
+ */
+ protected function compileSteps( $blueprint, $progress ) {
$stepRunnerFactory = $this->stepRunnerFactory;
// Compile, ensure all the runners may be created and configured
$totalProgressWeight = 0;
@@ -105,9 +105,9 @@ protected function compileSteps( $blueprint, $progress ) {
$totalProgressWeight += $step->progress->weight ?? 1;
}
- $compiledSteps = [];
+ $compiledSteps = array();
foreach ( $blueprint->steps as $step ) {
- $runner = $stepRunnerFactory( $step->step );
+ $runner = $stepRunnerFactory( $step->step );
$stepProgressTracker = $progress->stage(
( $step->progress->weight ?? 1 ) / $totalProgressWeight,
$step->progress->caption ?? $runner->getDefaultCaption( $step )
@@ -125,15 +125,15 @@ protected function compileSteps( $blueprint, $progress ) {
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
- * @param \WordPress\Blueprints\Progress\Tracker $progress
- */
- protected function compileResources( $blueprint, $progress ) {
- $resources = [];
+ * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
+ * @param \WordPress\Blueprints\Progress\Tracker $progress
+ */
+ protected function compileResources( $blueprint, $progress ) {
+ $resources = array();
$this->findResources( $blueprint, $resources );
$totalProgressWeight = count( $resources );
- $compiledResources = [];
+ $compiledResources = array();
foreach ( $resources as $path => list( $declaration, $resource ) ) {
/** @var $resource ResourceDefinitionInterface */
$compiledResources[ $path ] = new CompiledResource(
@@ -152,21 +152,21 @@ protected function compileResources( $blueprint, $progress ) {
// Find all the resources in the blueprint
protected function findResources( $blueprintFragment, &$resources, $path = '', $parseUrls = false ) {
if ( $parseUrls && is_string( $blueprintFragment ) ) {
- $resources[ $path ] = [
+ $resources[ $path ] = array(
$blueprintFragment,
$this->resourceResolver->parseUrl( $blueprintFragment ),
- ];
+ );
} elseif ( $blueprintFragment instanceof ResourceDefinitionInterface ) {
- $resources[ $path ] = [
+ $resources[ $path ] = array(
$blueprintFragment,
$blueprintFragment,
- ];
+ );
} elseif ( is_object( $blueprintFragment ) ) {
// Check if the @var annotation mentions a ResourceDefinitionInterface
foreach ( get_object_vars( $blueprintFragment ) as $key => $value ) {
$reflection = new \ReflectionProperty( $blueprintFragment, $key );
- $reflection->setAccessible(true);
- $docComment = $reflection->getDocComment();
+ $reflection->setAccessible( true );
+ $docComment = $reflection->getDocComment();
$parseNestedUrls = false;
if ( preg_match( '/@var\s+([^\s]+)/', $docComment, $matches ) ) {
$className = $matches[1];
@@ -187,5 +187,4 @@ protected function findResources( $blueprintFragment, &$resources, $path = '', $
return $blueprintFragment;
}
}
-
}
diff --git a/src/WordPress/Blueprints/Compile/CompiledBlueprint.php b/src/WordPress/Blueprints/Compile/CompiledBlueprint.php
index a33ea060..ea1c0c29 100644
--- a/src/WordPress/Blueprints/Compile/CompiledBlueprint.php
+++ b/src/WordPress/Blueprints/Compile/CompiledBlueprint.php
@@ -17,11 +17,9 @@ class CompiledBlueprint {
* @param $stepsProgressStage
*/
public function __construct( $compiledSteps, $compiledResources, $progressTracker, $stepsProgressStage ) {
- $this->compiledSteps = $compiledSteps;
- $this->compiledResources = $compiledResources;
- $this->progressTracker = $progressTracker;
+ $this->compiledSteps = $compiledSteps;
+ $this->compiledResources = $compiledResources;
+ $this->progressTracker = $progressTracker;
$this->stepsProgressStage = $stepsProgressStage;
}
-
-
}
diff --git a/src/WordPress/Blueprints/Compile/CompiledResource.php b/src/WordPress/Blueprints/Compile/CompiledResource.php
index d911a444..169fdc91 100644
--- a/src/WordPress/Blueprints/Compile/CompiledResource.php
+++ b/src/WordPress/Blueprints/Compile/CompiledResource.php
@@ -16,9 +16,8 @@ public function __construct(
ResourceDefinitionInterface $resource,
Tracker $progressTracker
) {
- $this->declaration = $declaration;
- $this->resource = $resource;
+ $this->declaration = $declaration;
+ $this->resource = $resource;
$this->progressTracker = $progressTracker;
}
-
}
diff --git a/src/WordPress/Blueprints/Compile/CompiledStep.php b/src/WordPress/Blueprints/Compile/CompiledStep.php
index 2256e910..c99acc84 100644
--- a/src/WordPress/Blueprints/Compile/CompiledStep.php
+++ b/src/WordPress/Blueprints/Compile/CompiledStep.php
@@ -17,9 +17,8 @@ public function __construct(
StepRunnerInterface $runner,
Tracker $progressTracker
) {
- $this->step = $step;
- $this->runner = $runner;
+ $this->step = $step;
+ $this->runner = $runner;
$this->progressTracker = $progressTracker;
}
-
}
diff --git a/src/WordPress/Blueprints/Compile/StepFailure.php b/src/WordPress/Blueprints/Compile/StepFailure.php
index affa5601..ce074af5 100644
--- a/src/WordPress/Blueprints/Compile/StepFailure.php
+++ b/src/WordPress/Blueprints/Compile/StepFailure.php
@@ -8,14 +8,14 @@
class StepFailure extends BlueprintException implements StepResultInterface {
/**
- * @var \WordPress\Blueprints\Model\DataClass\StepDefinitionInterface
- */
- public $step;
- public function __construct(
+ * @var \WordPress\Blueprints\Model\DataClass\StepDefinitionInterface
+ */
+ public $step;
+ public function __construct(
StepDefinitionInterface $step,
\Exception $cause
) {
$this->step = $step;
- parent::__construct( "Error when executing step $step->step", 0, $cause );
+ parent::__construct( "Error when executing step $step->step", 0, $cause );
}
}
diff --git a/src/WordPress/Blueprints/Compile/StepSuccess.php b/src/WordPress/Blueprints/Compile/StepSuccess.php
index 2eddbf48..a5de5f7a 100644
--- a/src/WordPress/Blueprints/Compile/StepSuccess.php
+++ b/src/WordPress/Blueprints/Compile/StepSuccess.php
@@ -9,7 +9,7 @@ class StepSuccess implements StepResultInterface {
public $result;
public function __construct( StepDefinitionInterface $step, $result ) {
- $this->step = $step;
+ $this->step = $step;
$this->result = $result;
}
}
diff --git a/src/WordPress/Blueprints/ContainerBuilder.php b/src/WordPress/Blueprints/ContainerBuilder.php
index e4d7d6d3..db962ee3 100644
--- a/src/WordPress/Blueprints/ContainerBuilder.php
+++ b/src/WordPress/Blueprints/ContainerBuilder.php
@@ -64,10 +64,10 @@
class ContainerBuilder {
- const ENVIRONMENT_NATIVE = 'native';
+ const ENVIRONMENT_NATIVE = 'native';
const ENVIRONMENT_PLAYGROUND = 'playground';
- const ENVIRONMENT_WP_NOW = 'wp-now';
- const ENVIRONMENTS = array(
+ const ENVIRONMENT_WP_NOW = 'wp-now';
+ const ENVIRONMENTS = array(
self::ENVIRONMENT_NATIVE,
self::ENVIRONMENT_PLAYGROUND,
self::ENVIRONMENT_WP_NOW,
@@ -81,20 +81,20 @@ public function __construct() {
/**
- * @param string $environment
- * @param \WordPress\Blueprints\Runtime\RuntimeInterface $runtime
- */
- public function build( $environment, $runtime ) {
- $container = $this->container;
+ * @param string $environment
+ * @param \WordPress\Blueprints\Runtime\RuntimeInterface $runtime
+ */
+ public function build( $environment, $runtime ) {
+ $container = $this->container;
$container['runtime'] = function () use ( $runtime ) {
return $runtime;
};
if ( $environment === static::ENVIRONMENT_NATIVE ) {
- $container['downloads_cache'] = function ( $c ) {
+ $container['downloads_cache'] = function ( $c ) {
return new FileCache();
};
- $container['http_client'] = function ( $c ) {
+ $container['http_client'] = function ( $c ) {
return new Client();
};
$container[ 'resource.resolver.' . UrlResource::DISCRIMINATOR ] = function ( $c ) {
@@ -141,7 +141,7 @@ function () use ( $c ) {
$container['blueprint.json_schema_path'] = function () {
return __DIR__ . '/schema.json';
};
- $container['blueprint.json_schema'] = function ( $c ) {
+ $container['blueprint.json_schema'] = function ( $c ) {
return json_decode( file_get_contents( $c['blueprint.json_schema_path'] ) );
};
@@ -150,10 +150,10 @@ function () use ( $c ) {
$c['blueprint.json_schema_path']
);
};
- $container['blueprint.mapper'] = function ( $c ) {
+ $container['blueprint.mapper'] = function ( $c ) {
return new BlueprintMapper();
};
- $container['blueprint.parser'] = function ( $c ) {
+ $container['blueprint.parser'] = function ( $c ) {
return new BlueprintParser(
$c['blueprint.validator'],
$c['blueprint.mapper']
@@ -163,71 +163,71 @@ function () use ( $c ) {
$container[ 'step.runner.' . InstallSqliteIntegrationStep::DISCRIMINATOR ] = function () {
return new InstallSqliteIntegrationStepRunner();
};
- $container[ 'step.runner.' . DownloadWordPressStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . DownloadWordPressStep::DISCRIMINATOR ] = function () {
return new DownloadWordPressStepRunner();
};
- $container[ 'step.runner.' . UnzipStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . UnzipStep::DISCRIMINATOR ] = function () {
return new UnzipStepRunner();
};
- $container[ 'step.runner.' . WriteFileStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . WriteFileStep::DISCRIMINATOR ] = function () {
return new WriteFileStepRunner();
};
- $container[ 'step.runner.' . RunPHPStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . RunPHPStep::DISCRIMINATOR ] = function () {
return new RunPHPStepRunner();
};
- $container[ 'step.runner.' . DefineWpConfigConstsStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . DefineWpConfigConstsStep::DISCRIMINATOR ] = function () {
return new DefineWpConfigConstsStepRunner();
};
- $container[ 'step.runner.' . EnableMultisiteStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . EnableMultisiteStep::DISCRIMINATOR ] = function () {
return new EnableMultisiteStepRunner();
};
- $container[ 'step.runner.' . DefineSiteUrlStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . DefineSiteUrlStep::DISCRIMINATOR ] = function () {
return new DefineSiteUrlStepRunner();
};
- $container[ 'step.runner.' . MkdirStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . MkdirStep::DISCRIMINATOR ] = function () {
return new MkdirStepRunner();
};
- $container[ 'step.runner.' . RmStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . RmStep::DISCRIMINATOR ] = function () {
return new RmStepRunner();
};
- $container[ 'step.runner.' . MvStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . MvStep::DISCRIMINATOR ] = function () {
return new MvStepRunner();
};
- $container[ 'step.runner.' . CpStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . CpStep::DISCRIMINATOR ] = function () {
return new CpStepRunner();
};
- $container[ 'step.runner.' . WPCLIStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . WPCLIStep::DISCRIMINATOR ] = function () {
return new WPCLIStepRunner();
};
- $container[ 'step.runner.' . SetSiteOptionsStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . SetSiteOptionsStep::DISCRIMINATOR ] = function () {
return new SetSiteOptionsStepRunner();
};
- $container[ 'step.runner.' . ActivatePluginStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . ActivatePluginStep::DISCRIMINATOR ] = function () {
return new ActivatePluginStepRunner();
};
- $container[ 'step.runner.' . ActivateThemeStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . ActivateThemeStep::DISCRIMINATOR ] = function () {
return new ActivateThemeStepRunner();
};
- $container[ 'step.runner.' . InstallPluginStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . InstallPluginStep::DISCRIMINATOR ] = function () {
return new InstallPluginStepRunner();
};
- $container[ 'step.runner.' . InstallThemeStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . InstallThemeStep::DISCRIMINATOR ] = function () {
return new InstallThemeStepRunner();
};
- $container[ 'step.runner.' . ImportFileStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . ImportFileStep::DISCRIMINATOR ] = function () {
return new ImportFileStepRunner();
};
- $container[ 'step.runner.' . RunWordPressInstallerStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . RunWordPressInstallerStep::DISCRIMINATOR ] = function () {
return new RunWordPressInstallerStepRunner();
};
- $container[ 'step.runner.' . RunSQLStep::DISCRIMINATOR ] = function () {
+ $container[ 'step.runner.' . RunSQLStep::DISCRIMINATOR ] = function () {
return new RunSQLStepRunner();
};
$container[ 'resource.resolver.' . FilesystemResource::DISCRIMINATOR ] = function () {
return new FilesystemResourceResolver();
};
- $container[ 'resource.resolver.' . InlineResource::DISCRIMINATOR ] = function () {
+ $container[ 'resource.resolver.' . InlineResource::DISCRIMINATOR ] = function () {
return new InlineResourceResolver();
};
@@ -256,11 +256,11 @@ function ( $c ) {
$container['step.runner_factory'] = function ( $c ) {
return function ( $slug ) use ( $c ) {
- if ( ! isset( $c["step.runner.$slug"] ) ) {
+ if ( ! isset( $c[ "step.runner.$slug" ] ) ) {
throw new InvalidArgumentException( "No runner registered for step {$slug}" );
}
- return $c["step.runner.$slug"];
+ return $c[ "step.runner.$slug" ];
};
};
diff --git a/src/WordPress/Blueprints/Engine.php b/src/WordPress/Blueprints/Engine.php
index 8168ae8c..9dca3a87 100644
--- a/src/WordPress/Blueprints/Engine.php
+++ b/src/WordPress/Blueprints/Engine.php
@@ -28,9 +28,9 @@ public function __construct(
BlueprintCompiler $compiler,
BlueprintRunner $runner
) {
- $this->runner = $runner;
+ $this->runner = $runner;
$this->compiler = $compiler;
- $this->parser = $parser;
+ $this->parser = $parser;
}
public function parseAndCompile( $raw_blueprint ) {
@@ -40,9 +40,9 @@ public function parseAndCompile( $raw_blueprint ) {
}
/**
- * @param \WordPress\Blueprints\Compile\CompiledBlueprint $compiled_blueprint
- */
- public function run( $compiled_blueprint ) {
+ * @param \WordPress\Blueprints\Compile\CompiledBlueprint $compiled_blueprint
+ */
+ public function run( $compiled_blueprint ) {
return $this->runner->run( $compiled_blueprint );
}
}
diff --git a/src/WordPress/Blueprints/Model/BlueprintBuilder.php b/src/WordPress/Blueprints/Model/BlueprintBuilder.php
index 52773260..0a3abc53 100644
--- a/src/WordPress/Blueprints/Model/BlueprintBuilder.php
+++ b/src/WordPress/Blueprints/Model/BlueprintBuilder.php
@@ -48,18 +48,18 @@ public function withWordPressVersion( $v ) {
}
/**
- * @param mixed[] $options
- */
- public function withSiteOptions( $options ) {
+ * @param mixed[] $options
+ */
+ public function withSiteOptions( $options ) {
$this->blueprint->setSiteOptions( $options );
return $this;
}
/**
- * @param mixed[] $constants
- */
- public function withWpConfigConstants( $constants ) {
+ * @param mixed[] $constants
+ */
+ public function withWpConfigConstants( $constants ) {
$this->blueprint->setConstants( $constants );
return $this;
@@ -184,9 +184,9 @@ private function prependStep( StepDefinitionInterface $builder ) {
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\StepDefinitionInterface $builder
- */
- public function addStep( $builder ) {
+ * @param \WordPress\Blueprints\Model\DataClass\StepDefinitionInterface $builder
+ */
+ public function addStep( $builder ) {
array_push( $this->blueprint->steps, $builder );
return $this;
diff --git a/src/WordPress/Blueprints/Model/BlueprintSerializer.php b/src/WordPress/Blueprints/Model/BlueprintSerializer.php
index 93e02386..2c6a2a9c 100644
--- a/src/WordPress/Blueprints/Model/BlueprintSerializer.php
+++ b/src/WordPress/Blueprints/Model/BlueprintSerializer.php
@@ -8,10 +8,9 @@
class BlueprintSerializer {
/**
- * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
- */
- public function toJson( $blueprint ) {
+ * @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
+ */
+ public function toJson( $blueprint ) {
return json_encode( $blueprint );
}
-
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/ActivatePluginStep.php b/src/WordPress/Blueprints/Model/DataClass/ActivatePluginStep.php
index 030c9693..c36a1542 100644
--- a/src/WordPress/Blueprints/Model/DataClass/ActivatePluginStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/ActivatePluginStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class ActivatePluginStep implements StepDefinitionInterface
-{
+class ActivatePluginStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'activatePlugin';
/** @var Progress */
@@ -17,46 +17,43 @@ class ActivatePluginStep implements StepDefinitionInterface
/**
* Plugin slug, like 'gutenberg' or 'hello-dolly'.
+ *
* @var string
*/
public $slug;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param string $slug
- */
- public function setSlug($slug)
- {
+ * @param string $slug
+ */
+ public function setSlug( $slug ) {
$this->slug = $slug;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/ActivateThemeStep.php b/src/WordPress/Blueprints/Model/DataClass/ActivateThemeStep.php
index bb31bdf1..1d019cca 100644
--- a/src/WordPress/Blueprints/Model/DataClass/ActivateThemeStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/ActivateThemeStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class ActivateThemeStep implements StepDefinitionInterface
-{
+class ActivateThemeStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'activateTheme';
/** @var Progress */
@@ -17,46 +17,43 @@ class ActivateThemeStep implements StepDefinitionInterface
/**
* Theme slug, like 'twentytwentythree'.
+ *
* @var string
*/
public $slug;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param string $slug
- */
- public function setSlug($slug)
- {
+ * @param string $slug
+ */
+ public function setSlug( $slug ) {
$this->slug = $slug;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/Blueprint.php b/src/WordPress/Blueprints/Model/DataClass/Blueprint.php
index b43d0d00..99d6e4b1 100644
--- a/src/WordPress/Blueprints/Model/DataClass/Blueprint.php
+++ b/src/WordPress/Blueprints/Model/DataClass/Blueprint.php
@@ -5,18 +5,21 @@
class Blueprint {
/**
* Optional description. It doesn't do anything but is exposed as a courtesy to developers who may want to document which blueprint file does what.
+ *
* @var string
*/
public $description = '';
/**
* Version of WordPress to use. Also accepts URL to a WordPress zip file.
+ *
* @var string
*/
public $WordPressVersion;
/**
* Slot for runtime–specific options, schema must be provided by the runtime.
+ *
* @var \ArrayObject
*/
public $runtime;
@@ -26,33 +29,37 @@ class Blueprint {
/**
* PHP Constants to define on every request
+ *
* @var \ArrayObject
*/
- public $constants = [];
+ public $constants = array();
/**
* WordPress plugins to install and activate
+ *
* @var string[]|ResourceDefinitionInterface[]
*/
- public $plugins = [];
+ public $plugins = array();
/**
* WordPress site options to define
+ *
* @var \ArrayObject
*/
- public $siteOptions = [];
+ public $siteOptions = array();
/**
* The steps to run after every other operation in this Blueprint was executed.
+ *
* @var StepDefinitionInterface[]
*/
- public $steps = [];
+ public $steps = array();
/**
- * @param string $description
- */
- public function setDescription( $description ) {
+ * @param string $description
+ */
+ public function setDescription( $description ) {
$this->description = $description;
return $this;
@@ -60,9 +67,9 @@ public function setDescription( $description ) {
/**
- * @param string $WordPressVersion
- */
- public function setWordPressVersion( $WordPressVersion ) {
+ * @param string $WordPressVersion
+ */
+ public function setWordPressVersion( $WordPressVersion ) {
$this->WordPressVersion = $WordPressVersion;
return $this;
@@ -77,9 +84,9 @@ public function setRuntime( $runtime ) {
/**
- * @param \WordPress\Blueprints\Model\DataClass\BlueprintOnBoot $onBoot
- */
- public function setOnBoot( $onBoot ) {
+ * @param \WordPress\Blueprints\Model\DataClass\BlueprintOnBoot $onBoot
+ */
+ public function setOnBoot( $onBoot ) {
$this->onBoot = $onBoot;
return $this;
@@ -94,9 +101,9 @@ public function setConstants( $constants ) {
/**
- * @param mixed[] $plugins
- */
- public function setPlugins( $plugins ) {
+ * @param mixed[] $plugins
+ */
+ public function setPlugins( $plugins ) {
$this->plugins = $plugins;
return $this;
@@ -111,9 +118,9 @@ public function setSiteOptions( $siteOptions ) {
/**
- * @param mixed[] $steps
- */
- public function setSteps( $steps ) {
+ * @param mixed[] $steps
+ */
+ public function setSteps( $steps ) {
$this->steps = $steps;
return $this;
diff --git a/src/WordPress/Blueprints/Model/DataClass/BlueprintOnBoot.php b/src/WordPress/Blueprints/Model/DataClass/BlueprintOnBoot.php
index 554b7184..c91c17f6 100644
--- a/src/WordPress/Blueprints/Model/DataClass/BlueprintOnBoot.php
+++ b/src/WordPress/Blueprints/Model/DataClass/BlueprintOnBoot.php
@@ -2,10 +2,11 @@
namespace WordPress\Blueprints\Model\DataClass;
-class BlueprintOnBoot
-{
+class BlueprintOnBoot {
+
/**
* The URL to navigate to after the blueprint has been run.
+ *
* @var string
*/
public $openUrl;
@@ -15,20 +16,18 @@ class BlueprintOnBoot
/**
- * @param string $openUrl
- */
- public function setOpenUrl($openUrl)
- {
+ * @param string $openUrl
+ */
+ public function setOpenUrl( $openUrl ) {
$this->openUrl = $openUrl;
return $this;
}
/**
- * @param bool $login
- */
- public function setLogin($login)
- {
+ * @param bool $login
+ */
+ public function setLogin( $login ) {
$this->login = $login;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/CorePluginResource.php b/src/WordPress/Blueprints/Model/DataClass/CorePluginResource.php
index 472bcef1..0c18d971 100644
--- a/src/WordPress/Blueprints/Model/DataClass/CorePluginResource.php
+++ b/src/WordPress/Blueprints/Model/DataClass/CorePluginResource.php
@@ -2,38 +2,38 @@
namespace WordPress\Blueprints\Model\DataClass;
-class CorePluginResource implements ResourceDefinitionInterface
-{
+class CorePluginResource implements ResourceDefinitionInterface {
+
const DISCRIMINATOR = 'wordpress.org/plugins';
/**
* Identifies the file resource as a WordPress Core plugin
+ *
* @var string
*/
public $resource = 'wordpress.org/plugins';
/**
* The slug of the WordPress Core plugin
+ *
* @var string
*/
public $slug;
/**
- * @param string $resource
- */
- public function setResource($resource)
- {
+ * @param string $resource
+ */
+ public function setResource( $resource ) {
$this->resource = $resource;
return $this;
}
/**
- * @param string $slug
- */
- public function setSlug($slug)
- {
+ * @param string $slug
+ */
+ public function setSlug( $slug ) {
$this->slug = $slug;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/CoreThemeResource.php b/src/WordPress/Blueprints/Model/DataClass/CoreThemeResource.php
index 2296d87d..20785f19 100644
--- a/src/WordPress/Blueprints/Model/DataClass/CoreThemeResource.php
+++ b/src/WordPress/Blueprints/Model/DataClass/CoreThemeResource.php
@@ -2,38 +2,38 @@
namespace WordPress\Blueprints\Model\DataClass;
-class CoreThemeResource implements ResourceDefinitionInterface
-{
+class CoreThemeResource implements ResourceDefinitionInterface {
+
const DISCRIMINATOR = 'wordpress.org/themes';
/**
* Identifies the file resource as a WordPress Core theme
+ *
* @var string
*/
public $resource = 'wordpress.org/themes';
/**
* The slug of the WordPress Core theme
+ *
* @var string
*/
public $slug;
/**
- * @param string $resource
- */
- public function setResource($resource)
- {
+ * @param string $resource
+ */
+ public function setResource( $resource ) {
$this->resource = $resource;
return $this;
}
/**
- * @param string $slug
- */
- public function setSlug($slug)
- {
+ * @param string $slug
+ */
+ public function setSlug( $slug ) {
$this->slug = $slug;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/CpStep.php b/src/WordPress/Blueprints/Model/DataClass/CpStep.php
index c5d22c1e..5b4c16c7 100644
--- a/src/WordPress/Blueprints/Model/DataClass/CpStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/CpStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class CpStep implements StepDefinitionInterface
-{
+class CpStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'cp';
/** @var Progress */
@@ -17,62 +17,59 @@ class CpStep implements StepDefinitionInterface
/**
* Source path
+ *
* @var string
*/
public $fromPath;
/**
* Target path
+ *
* @var string
*/
public $toPath;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param string $fromPath
- */
- public function setFromPath($fromPath)
- {
+ * @param string $fromPath
+ */
+ public function setFromPath( $fromPath ) {
$this->fromPath = $fromPath;
return $this;
}
/**
- * @param string $toPath
- */
- public function setToPath($toPath)
- {
+ * @param string $toPath
+ */
+ public function setToPath( $toPath ) {
$this->toPath = $toPath;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/DefineSiteUrlStep.php b/src/WordPress/Blueprints/Model/DataClass/DefineSiteUrlStep.php
index b21cf0e8..07433cee 100644
--- a/src/WordPress/Blueprints/Model/DataClass/DefineSiteUrlStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/DefineSiteUrlStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class DefineSiteUrlStep implements StepDefinitionInterface
-{
+class DefineSiteUrlStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'defineSiteUrl';
/** @var Progress */
@@ -17,46 +17,43 @@ class DefineSiteUrlStep implements StepDefinitionInterface
/**
* The URL
+ *
* @var string
*/
public $siteUrl;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param string $siteUrl
- */
- public function setSiteUrl($siteUrl)
- {
+ * @param string $siteUrl
+ */
+ public function setSiteUrl( $siteUrl ) {
$this->siteUrl = $siteUrl;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/DefineWpConfigConstsStep.php b/src/WordPress/Blueprints/Model/DataClass/DefineWpConfigConstsStep.php
index 19a0bbc6..ae227048 100644
--- a/src/WordPress/Blueprints/Model/DataClass/DefineWpConfigConstsStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/DefineWpConfigConstsStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class DefineWpConfigConstsStep implements StepDefinitionInterface
-{
+class DefineWpConfigConstsStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'defineWpConfigConsts';
/** @var Progress */
@@ -17,46 +17,43 @@ class DefineWpConfigConstsStep implements StepDefinitionInterface
/**
* The constants to define
+ *
* @var \ArrayObject
*/
public $consts;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param iterable $consts
- */
- public function setConsts($consts)
- {
+ * @param iterable $consts
+ */
+ public function setConsts( $consts ) {
$this->consts = $consts;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/DownloadWordPressStep.php b/src/WordPress/Blueprints/Model/DataClass/DownloadWordPressStep.php
index 1db432bf..d60a6eba 100644
--- a/src/WordPress/Blueprints/Model/DataClass/DownloadWordPressStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/DownloadWordPressStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class DownloadWordPressStep implements StepDefinitionInterface
-{
+class DownloadWordPressStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'downloadWordPress';
/** @var Progress */
@@ -20,37 +20,33 @@ class DownloadWordPressStep implements StepDefinitionInterface
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
- public function setWordPressZip($wordPressZip)
- {
+ public function setWordPressZip( $wordPressZip ) {
$this->wordPressZip = $wordPressZip;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/EnableMultisiteStep.php b/src/WordPress/Blueprints/Model/DataClass/EnableMultisiteStep.php
index 8dda6c98..8c381b9c 100644
--- a/src/WordPress/Blueprints/Model/DataClass/EnableMultisiteStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/EnableMultisiteStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class EnableMultisiteStep implements StepDefinitionInterface
-{
+class EnableMultisiteStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'enableMultisite';
/** @var Progress */
@@ -17,30 +17,27 @@ class EnableMultisiteStep implements StepDefinitionInterface
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/EvalPHPCallbackStep.php b/src/WordPress/Blueprints/Model/DataClass/EvalPHPCallbackStep.php
index b2d480b5..1e5eb6a7 100644
--- a/src/WordPress/Blueprints/Model/DataClass/EvalPHPCallbackStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/EvalPHPCallbackStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class EvalPHPCallbackStep implements StepDefinitionInterface
-{
+class EvalPHPCallbackStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'evalPHPCallback';
/** @var Progress */
@@ -14,49 +14,47 @@ class EvalPHPCallbackStep implements StepDefinitionInterface
/**
* The step identifier.
+ *
* @var string
*/
public $step = 'evalPHPCallback';
/**
* The PHP function.
+ *
* @var mixed
*/
public $callback;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
- public function setCallback($callback)
- {
+ public function setCallback( $callback ) {
$this->callback = $callback;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/FileInfo.php b/src/WordPress/Blueprints/Model/DataClass/FileInfo.php
index 534f76a9..fc1ab214 100644
--- a/src/WordPress/Blueprints/Model/DataClass/FileInfo.php
+++ b/src/WordPress/Blueprints/Model/DataClass/FileInfo.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class FileInfo
-{
+class FileInfo {
+
/** @var string */
public $key;
@@ -18,40 +18,36 @@ class FileInfo
/**
- * @param string $key
- */
- public function setKey($key)
- {
+ * @param string $key
+ */
+ public function setKey( $key ) {
$this->key = $key;
return $this;
}
/**
- * @param string $name
- */
- public function setName($name)
- {
+ * @param string $name
+ */
+ public function setName( $name ) {
$this->name = $name;
return $this;
}
/**
- * @param string $type
- */
- public function setType($type)
- {
+ * @param string $type
+ */
+ public function setType( $type ) {
$this->type = $type;
return $this;
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\FileInfoData $data
- */
- public function setData($data)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\FileInfoData $data
+ */
+ public function setData( $data ) {
$this->data = $data;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/FileInfoData.php b/src/WordPress/Blueprints/Model/DataClass/FileInfoData.php
index 39ff5129..72ef3ce2 100644
--- a/src/WordPress/Blueprints/Model/DataClass/FileInfoData.php
+++ b/src/WordPress/Blueprints/Model/DataClass/FileInfoData.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class FileInfoData
-{
+class FileInfoData {
+
/** @var float */
public $BYTES_PER_ELEMENT;
@@ -21,50 +21,45 @@ class FileInfoData
/**
- * @param float $BYTES_PER_ELEMENT
- */
- public function setBYTES_PER_ELEMENT($BYTES_PER_ELEMENT)
- {
+ * @param float $BYTES_PER_ELEMENT
+ */
+ public function setBYTES_PER_ELEMENT( $BYTES_PER_ELEMENT ) {
$this->BYTES_PER_ELEMENT = $BYTES_PER_ELEMENT;
return $this;
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\FileInfoDataBuffer $buffer
- */
- public function setBuffer($buffer)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\FileInfoDataBuffer $buffer
+ */
+ public function setBuffer( $buffer ) {
$this->buffer = $buffer;
return $this;
}
/**
- * @param float $byteLength
- */
- public function setByteLength($byteLength)
- {
+ * @param float $byteLength
+ */
+ public function setByteLength( $byteLength ) {
$this->byteLength = $byteLength;
return $this;
}
/**
- * @param float $byteOffset
- */
- public function setByteOffset($byteOffset)
- {
+ * @param float $byteOffset
+ */
+ public function setByteOffset( $byteOffset ) {
$this->byteOffset = $byteOffset;
return $this;
}
/**
- * @param float $length
- */
- public function setLength($length)
- {
+ * @param float $length
+ */
+ public function setLength( $length ) {
$this->length = $length;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/FileInfoDataBuffer.php b/src/WordPress/Blueprints/Model/DataClass/FileInfoDataBuffer.php
index 535ef8b4..a1d03063 100644
--- a/src/WordPress/Blueprints/Model/DataClass/FileInfoDataBuffer.php
+++ b/src/WordPress/Blueprints/Model/DataClass/FileInfoDataBuffer.php
@@ -2,17 +2,16 @@
namespace WordPress\Blueprints\Model\DataClass;
-class FileInfoDataBuffer
-{
+class FileInfoDataBuffer {
+
/** @var float */
public $byteLength;
/**
- * @param float $byteLength
- */
- public function setByteLength($byteLength)
- {
+ * @param float $byteLength
+ */
+ public function setByteLength( $byteLength ) {
$this->byteLength = $byteLength;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/FilesystemResource.php b/src/WordPress/Blueprints/Model/DataClass/FilesystemResource.php
index caffb091..9637f215 100644
--- a/src/WordPress/Blueprints/Model/DataClass/FilesystemResource.php
+++ b/src/WordPress/Blueprints/Model/DataClass/FilesystemResource.php
@@ -2,38 +2,38 @@
namespace WordPress\Blueprints\Model\DataClass;
-class FilesystemResource implements ResourceDefinitionInterface
-{
+class FilesystemResource implements ResourceDefinitionInterface {
+
const DISCRIMINATOR = 'filesystem';
/**
* Identifies the file resource as Virtual File System (VFS)
+ *
* @var string
*/
public $resource = 'filesystem';
/**
* The path to the file in the VFS
+ *
* @var string
*/
public $path;
/**
- * @param string $resource
- */
- public function setResource($resource)
- {
+ * @param string $resource
+ */
+ public function setResource( $resource ) {
$this->resource = $resource;
return $this;
}
/**
- * @param string $path
- */
- public function setPath($path)
- {
+ * @param string $path
+ */
+ public function setPath( $path ) {
$this->path = $path;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/ImportFileStep.php b/src/WordPress/Blueprints/Model/DataClass/ImportFileStep.php
index 568a04ad..caa11d88 100644
--- a/src/WordPress/Blueprints/Model/DataClass/ImportFileStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/ImportFileStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class ImportFileStep implements StepDefinitionInterface
-{
+class ImportFileStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'importFile';
/** @var Progress */
@@ -20,37 +20,33 @@ class ImportFileStep implements StepDefinitionInterface
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
- public function setFile($file)
- {
+ public function setFile( $file ) {
$this->file = $file;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/InlineResource.php b/src/WordPress/Blueprints/Model/DataClass/InlineResource.php
index 4e30c0ad..8e2ec36e 100644
--- a/src/WordPress/Blueprints/Model/DataClass/InlineResource.php
+++ b/src/WordPress/Blueprints/Model/DataClass/InlineResource.php
@@ -2,38 +2,38 @@
namespace WordPress\Blueprints\Model\DataClass;
-class InlineResource implements ResourceDefinitionInterface
-{
+class InlineResource implements ResourceDefinitionInterface {
+
const DISCRIMINATOR = 'inline';
/**
* Identifies the file resource as an inline string
+ *
* @var string
*/
public $resource = 'inline';
/**
* The contents of the file
+ *
* @var string
*/
public $contents;
/**
- * @param string $resource
- */
- public function setResource($resource)
- {
+ * @param string $resource
+ */
+ public function setResource( $resource ) {
$this->resource = $resource;
return $this;
}
/**
- * @param string $contents
- */
- public function setContents($contents)
- {
+ * @param string $contents
+ */
+ public function setContents( $contents ) {
$this->contents = $contents;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/InstallPluginStep.php b/src/WordPress/Blueprints/Model/DataClass/InstallPluginStep.php
index 54375712..1da3cb0c 100644
--- a/src/WordPress/Blueprints/Model/DataClass/InstallPluginStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/InstallPluginStep.php
@@ -13,6 +13,7 @@ class InstallPluginStep implements StepDefinitionInterface {
/**
* The step identifier.
+ *
* @var string
*/
public $step = 'installPlugin';
@@ -22,15 +23,16 @@ class InstallPluginStep implements StepDefinitionInterface {
/**
* Whether to activate the plugin after installing it.
+ *
* @var bool
*/
public $activate = true;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress( $progress ) {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
@@ -38,9 +40,9 @@ public function setProgress( $progress ) {
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError( $continueOnError ) {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
@@ -48,9 +50,9 @@ public function setContinueOnError( $continueOnError ) {
/**
- * @param string $step
- */
- public function setStep( $step ) {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
@@ -65,9 +67,9 @@ public function setPluginZipFile( $pluginZipFile ) {
/**
- * @param bool $activate
- */
- public function setActivate( $activate ) {
+ * @param bool $activate
+ */
+ public function setActivate( $activate ) {
$this->activate = $activate;
return $this;
diff --git a/src/WordPress/Blueprints/Model/DataClass/InstallSqliteIntegrationStep.php b/src/WordPress/Blueprints/Model/DataClass/InstallSqliteIntegrationStep.php
index 63e868e4..d13f5bb2 100644
--- a/src/WordPress/Blueprints/Model/DataClass/InstallSqliteIntegrationStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/InstallSqliteIntegrationStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class InstallSqliteIntegrationStep implements StepDefinitionInterface
-{
+class InstallSqliteIntegrationStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'installSqliteIntegration';
/** @var Progress */
@@ -20,37 +20,33 @@ class InstallSqliteIntegrationStep implements StepDefinitionInterface
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
- public function setSqlitePluginZip($sqlitePluginZip)
- {
+ public function setSqlitePluginZip( $sqlitePluginZip ) {
$this->sqlitePluginZip = $sqlitePluginZip;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/InstallThemeStep.php b/src/WordPress/Blueprints/Model/DataClass/InstallThemeStep.php
index 5bd52b88..05bf1a69 100644
--- a/src/WordPress/Blueprints/Model/DataClass/InstallThemeStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/InstallThemeStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class InstallThemeStep implements StepDefinitionInterface
-{
+class InstallThemeStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'installTheme';
/** @var Progress */
@@ -14,6 +14,7 @@ class InstallThemeStep implements StepDefinitionInterface
/**
* The step identifier.
+ *
* @var string
*/
public $step = 'installTheme';
@@ -23,53 +24,49 @@ class InstallThemeStep implements StepDefinitionInterface
/**
* Whether to activate the theme after installing it.
+ *
* @var bool
*/
public $activate = true;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
- public function setThemeZipFile($themeZipFile)
- {
+ public function setThemeZipFile( $themeZipFile ) {
$this->themeZipFile = $themeZipFile;
return $this;
}
/**
- * @param bool $activate
- */
- public function setActivate($activate)
- {
+ * @param bool $activate
+ */
+ public function setActivate( $activate ) {
$this->activate = $activate;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/MkdirStep.php b/src/WordPress/Blueprints/Model/DataClass/MkdirStep.php
index 291151c9..efcb6e51 100644
--- a/src/WordPress/Blueprints/Model/DataClass/MkdirStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/MkdirStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class MkdirStep implements StepDefinitionInterface
-{
+class MkdirStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'mkdir';
/** @var Progress */
@@ -17,46 +17,43 @@ class MkdirStep implements StepDefinitionInterface
/**
* The path of the directory you want to create
+ *
* @var string
*/
public $path;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param string $path
- */
- public function setPath($path)
- {
+ * @param string $path
+ */
+ public function setPath( $path ) {
$this->path = $path;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/ModelInfo.php b/src/WordPress/Blueprints/Model/DataClass/ModelInfo.php
index ae54db72..322a60a3 100644
--- a/src/WordPress/Blueprints/Model/DataClass/ModelInfo.php
+++ b/src/WordPress/Blueprints/Model/DataClass/ModelInfo.php
@@ -2,23 +2,21 @@
namespace WordPress\Blueprints\Model\DataClass;
-class ModelInfo
-{
- public static function getResourceDefinitionInterfaceImplementations(): array
- {
- return [
+class ModelInfo {
+
+ public static function getResourceDefinitionInterfaceImplementations(): array {
+ return array(
FilesystemResource::class,
InlineResource::class,
CoreThemeResource::class,
CorePluginResource::class,
- UrlResource::class
- ];
+ UrlResource::class,
+ );
}
- public static function getStepDefinitionInterfaceImplementations(): array
- {
- return [
+ public static function getStepDefinitionInterfaceImplementations(): array {
+ return array(
ActivatePluginStep::class,
ActivateThemeStep::class,
CpStep::class,
@@ -40,7 +38,7 @@ public static function getStepDefinitionInterfaceImplementations(): array
DownloadWordPressStep::class,
InstallSqliteIntegrationStep::class,
WriteFileStep::class,
- WPCLIStep::class
- ];
+ WPCLIStep::class,
+ );
}
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/MvStep.php b/src/WordPress/Blueprints/Model/DataClass/MvStep.php
index 10c35d5b..c596ab1a 100644
--- a/src/WordPress/Blueprints/Model/DataClass/MvStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/MvStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class MvStep implements StepDefinitionInterface
-{
+class MvStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'mv';
/** @var Progress */
@@ -17,62 +17,59 @@ class MvStep implements StepDefinitionInterface
/**
* Source path
+ *
* @var string
*/
public $fromPath;
/**
* Target path
+ *
* @var string
*/
public $toPath;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param string $fromPath
- */
- public function setFromPath($fromPath)
- {
+ * @param string $fromPath
+ */
+ public function setFromPath( $fromPath ) {
$this->fromPath = $fromPath;
return $this;
}
/**
- * @param string $toPath
- */
- public function setToPath($toPath)
- {
+ * @param string $toPath
+ */
+ public function setToPath( $toPath ) {
$this->toPath = $toPath;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/Progress.php b/src/WordPress/Blueprints/Model/DataClass/Progress.php
index 973bc481..06261350 100644
--- a/src/WordPress/Blueprints/Model/DataClass/Progress.php
+++ b/src/WordPress/Blueprints/Model/DataClass/Progress.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class Progress
-{
+class Progress {
+
/** @var float */
public $weight;
@@ -12,20 +12,18 @@ class Progress
/**
- * @param float $weight
- */
- public function setWeight($weight)
- {
+ * @param float $weight
+ */
+ public function setWeight( $weight ) {
$this->weight = $weight;
return $this;
}
/**
- * @param string $caption
- */
- public function setCaption($caption)
- {
+ * @param string $caption
+ */
+ public function setCaption( $caption ) {
$this->caption = $caption;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/ResourceDefinitionInterface.php b/src/WordPress/Blueprints/Model/DataClass/ResourceDefinitionInterface.php
index 8bee1256..b156c3fc 100644
--- a/src/WordPress/Blueprints/Model/DataClass/ResourceDefinitionInterface.php
+++ b/src/WordPress/Blueprints/Model/DataClass/ResourceDefinitionInterface.php
@@ -2,6 +2,6 @@
namespace WordPress\Blueprints\Model\DataClass;
-interface ResourceDefinitionInterface
-{
+interface ResourceDefinitionInterface {
+
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/RmStep.php b/src/WordPress/Blueprints/Model/DataClass/RmStep.php
index af6d3853..831afae6 100644
--- a/src/WordPress/Blueprints/Model/DataClass/RmStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/RmStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class RmStep implements StepDefinitionInterface
-{
+class RmStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'rm';
/** @var Progress */
@@ -17,46 +17,43 @@ class RmStep implements StepDefinitionInterface
/**
* The path to remove
+ *
* @var string
*/
public $path;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param string $path
- */
- public function setPath($path)
- {
+ * @param string $path
+ */
+ public function setPath( $path ) {
$this->path = $path;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/RunPHPStep.php b/src/WordPress/Blueprints/Model/DataClass/RunPHPStep.php
index 3c763d38..63e5f9e0 100644
--- a/src/WordPress/Blueprints/Model/DataClass/RunPHPStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/RunPHPStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class RunPHPStep implements StepDefinitionInterface
-{
+class RunPHPStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'runPHP';
/** @var Progress */
@@ -14,52 +14,50 @@ class RunPHPStep implements StepDefinitionInterface
/**
* The step identifier.
+ *
* @var string
*/
public $step = 'runPHP';
/**
* The PHP code to run.
+ *
* @var string
*/
public $code;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param string $code
- */
- public function setCode($code)
- {
+ * @param string $code
+ */
+ public function setCode( $code ) {
$this->code = $code;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/RunSQLStep.php b/src/WordPress/Blueprints/Model/DataClass/RunSQLStep.php
index ebaf9c68..8872ba3f 100644
--- a/src/WordPress/Blueprints/Model/DataClass/RunSQLStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/RunSQLStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class RunSQLStep implements StepDefinitionInterface
-{
+class RunSQLStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'runSql';
/** @var Progress */
@@ -14,6 +14,7 @@ class RunSQLStep implements StepDefinitionInterface
/**
* The step identifier.
+ *
* @var string
*/
public $step = 'runSql';
@@ -23,37 +24,33 @@ class RunSQLStep implements StepDefinitionInterface
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
- public function setSql($sql)
- {
+ public function setSql( $sql ) {
$this->sql = $sql;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/RunWordPressInstallerStep.php b/src/WordPress/Blueprints/Model/DataClass/RunWordPressInstallerStep.php
index b4a38a06..15744739 100644
--- a/src/WordPress/Blueprints/Model/DataClass/RunWordPressInstallerStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/RunWordPressInstallerStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class RunWordPressInstallerStep implements StepDefinitionInterface
-{
+class RunWordPressInstallerStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'runWpInstallationWizard';
/** @var Progress */
@@ -20,40 +20,36 @@ class RunWordPressInstallerStep implements StepDefinitionInterface
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\WordPressInstallationOptions $options
- */
- public function setOptions($options)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\WordPressInstallationOptions $options
+ */
+ public function setOptions( $options ) {
$this->options = $options;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/SetSiteOptionsStep.php b/src/WordPress/Blueprints/Model/DataClass/SetSiteOptionsStep.php
index 3b9e7327..4ee1bd19 100644
--- a/src/WordPress/Blueprints/Model/DataClass/SetSiteOptionsStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/SetSiteOptionsStep.php
@@ -13,21 +13,23 @@ class SetSiteOptionsStep implements StepDefinitionInterface {
/**
* The name of the step. Must be "setSiteOptions".
+ *
* @var string
*/
public $step = 'setSiteOptions';
/**
* The options to set on the site.
+ *
* @var \ArrayObject
*/
public $options;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress( $progress ) {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
@@ -35,9 +37,9 @@ public function setProgress( $progress ) {
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError( $continueOnError ) {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
@@ -45,9 +47,9 @@ public function setContinueOnError( $continueOnError ) {
/**
- * @param string $step
- */
- public function setStep( $step ) {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
diff --git a/src/WordPress/Blueprints/Model/DataClass/StepDefinitionInterface.php b/src/WordPress/Blueprints/Model/DataClass/StepDefinitionInterface.php
index 84a42524..451abfd2 100644
--- a/src/WordPress/Blueprints/Model/DataClass/StepDefinitionInterface.php
+++ b/src/WordPress/Blueprints/Model/DataClass/StepDefinitionInterface.php
@@ -2,6 +2,6 @@
namespace WordPress\Blueprints\Model\DataClass;
-interface StepDefinitionInterface
-{
+interface StepDefinitionInterface {
+
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/UnzipStep.php b/src/WordPress/Blueprints/Model/DataClass/UnzipStep.php
index 5333e315..06ab8124 100644
--- a/src/WordPress/Blueprints/Model/DataClass/UnzipStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/UnzipStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class UnzipStep implements StepDefinitionInterface
-{
+class UnzipStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'unzip';
/** @var Progress */
@@ -20,53 +20,49 @@ class UnzipStep implements StepDefinitionInterface
/**
* The path to extract the zip file to
+ *
* @var string
*/
public $extractToPath;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
- public function setZipFile($zipFile)
- {
+ public function setZipFile( $zipFile ) {
$this->zipFile = $zipFile;
return $this;
}
/**
- * @param string $extractToPath
- */
- public function setExtractToPath($extractToPath)
- {
+ * @param string $extractToPath
+ */
+ public function setExtractToPath( $extractToPath ) {
$this->extractToPath = $extractToPath;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/UrlResource.php b/src/WordPress/Blueprints/Model/DataClass/UrlResource.php
index 8d25d706..fa3b2d18 100644
--- a/src/WordPress/Blueprints/Model/DataClass/UrlResource.php
+++ b/src/WordPress/Blueprints/Model/DataClass/UrlResource.php
@@ -2,54 +2,54 @@
namespace WordPress\Blueprints\Model\DataClass;
-class UrlResource implements ResourceDefinitionInterface
-{
+class UrlResource implements ResourceDefinitionInterface {
+
const DISCRIMINATOR = 'url';
/**
* Identifies the file resource as a URL
+ *
* @var string
*/
public $resource = 'url';
/**
* The URL of the file
+ *
* @var string
*/
public $url;
/**
* Optional caption for displaying a progress message
+ *
* @var string
*/
public $caption;
/**
- * @param string $resource
- */
- public function setResource($resource)
- {
+ * @param string $resource
+ */
+ public function setResource( $resource ) {
$this->resource = $resource;
return $this;
}
/**
- * @param string $url
- */
- public function setUrl($url)
- {
+ * @param string $url
+ */
+ public function setUrl( $url ) {
$this->url = $url;
return $this;
}
/**
- * @param string $caption
- */
- public function setCaption($caption)
- {
+ * @param string $caption
+ */
+ public function setCaption( $caption ) {
$this->caption = $caption;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/WPCLIStep.php b/src/WordPress/Blueprints/Model/DataClass/WPCLIStep.php
index ea7b3060..ed034b66 100644
--- a/src/WordPress/Blueprints/Model/DataClass/WPCLIStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/WPCLIStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class WPCLIStep implements StepDefinitionInterface
-{
+class WPCLIStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'wp-cli';
/** @var Progress */
@@ -14,52 +14,50 @@ class WPCLIStep implements StepDefinitionInterface
/**
* The step identifier.
+ *
* @var string
*/
public $step = 'wp-cli';
/**
* The WP CLI command to run.
+ *
* @var string[]
*/
public $command;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param mixed[] $command
- */
- public function setCommand($command)
- {
+ * @param mixed[] $command
+ */
+ public function setCommand( $command ) {
$this->command = $command;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/WordPressInstallationOptions.php b/src/WordPress/Blueprints/Model/DataClass/WordPressInstallationOptions.php
index 3446a085..214038c7 100644
--- a/src/WordPress/Blueprints/Model/DataClass/WordPressInstallationOptions.php
+++ b/src/WordPress/Blueprints/Model/DataClass/WordPressInstallationOptions.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class WordPressInstallationOptions
-{
+class WordPressInstallationOptions {
+
/** @var string */
public $adminUsername;
@@ -12,20 +12,18 @@ class WordPressInstallationOptions
/**
- * @param string $adminUsername
- */
- public function setAdminUsername($adminUsername)
- {
+ * @param string $adminUsername
+ */
+ public function setAdminUsername( $adminUsername ) {
$this->adminUsername = $adminUsername;
return $this;
}
/**
- * @param string $adminPassword
- */
- public function setAdminPassword($adminPassword)
- {
+ * @param string $adminPassword
+ */
+ public function setAdminPassword( $adminPassword ) {
$this->adminPassword = $adminPassword;
return $this;
}
diff --git a/src/WordPress/Blueprints/Model/DataClass/WriteFileStep.php b/src/WordPress/Blueprints/Model/DataClass/WriteFileStep.php
index 784e1845..d2fd90de 100644
--- a/src/WordPress/Blueprints/Model/DataClass/WriteFileStep.php
+++ b/src/WordPress/Blueprints/Model/DataClass/WriteFileStep.php
@@ -2,8 +2,8 @@
namespace WordPress\Blueprints\Model\DataClass;
-class WriteFileStep implements StepDefinitionInterface
-{
+class WriteFileStep implements StepDefinitionInterface {
+
const DISCRIMINATOR = 'writeFile';
/** @var Progress */
@@ -17,59 +17,56 @@ class WriteFileStep implements StepDefinitionInterface
/**
* The path of the file to write to
+ *
* @var string
*/
public $path;
/**
* The data to write
+ *
* @var string|ResourceDefinitionInterface
*/
public $data;
/**
- * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
- */
- public function setProgress($progress)
- {
+ * @param \WordPress\Blueprints\Model\DataClass\Progress $progress
+ */
+ public function setProgress( $progress ) {
$this->progress = $progress;
return $this;
}
/**
- * @param bool $continueOnError
- */
- public function setContinueOnError($continueOnError)
- {
+ * @param bool $continueOnError
+ */
+ public function setContinueOnError( $continueOnError ) {
$this->continueOnError = $continueOnError;
return $this;
}
/**
- * @param string $step
- */
- public function setStep($step)
- {
+ * @param string $step
+ */
+ public function setStep( $step ) {
$this->step = $step;
return $this;
}
/**
- * @param string $path
- */
- public function setPath($path)
- {
+ * @param string $path
+ */
+ public function setPath( $path ) {
$this->path = $path;
return $this;
}
- public function setData($data)
- {
+ public function setData( $data ) {
$this->data = $data;
return $this;
}
diff --git a/src/WordPress/Blueprints/Progress/ProgressCaptionEvent.php b/src/WordPress/Blueprints/Progress/ProgressCaptionEvent.php
index 5fbe1836..c23a726b 100644
--- a/src/WordPress/Blueprints/Progress/ProgressCaptionEvent.php
+++ b/src/WordPress/Blueprints/Progress/ProgressCaptionEvent.php
@@ -4,11 +4,10 @@
class ProgressCaptionEvent extends \Symfony\Contracts\EventDispatcher\Event {
/**
- * @var string
- */
- public $caption;
- public function __construct(string $caption)
- {
- $this->caption = $caption;
- }
+ * @var string
+ */
+ public $caption;
+ public function __construct( string $caption ) {
+ $this->caption = $caption;
+ }
}
diff --git a/src/WordPress/Blueprints/Progress/ProgressEvent.php b/src/WordPress/Blueprints/Progress/ProgressEvent.php
index 80b4fb85..ab04a23d 100644
--- a/src/WordPress/Blueprints/Progress/ProgressEvent.php
+++ b/src/WordPress/Blueprints/Progress/ProgressEvent.php
@@ -26,7 +26,7 @@ public function __construct(
float $progress,
string $caption
) {
- $this->caption = $caption;
+ $this->caption = $caption;
$this->progress = $progress;
}
}
diff --git a/src/WordPress/Blueprints/Progress/Tracker.php b/src/WordPress/Blueprints/Progress/Tracker.php
index 123b57b8..b1d6afb2 100644
--- a/src/WordPress/Blueprints/Progress/Tracker.php
+++ b/src/WordPress/Blueprints/Progress/Tracker.php
@@ -39,19 +39,19 @@
* stage2.finish();
*/
class Tracker {
- private $selfWeight = 1;
- private $selfDone = false;
+ private $selfWeight = 1;
+ private $selfDone = false;
private $selfProgress = 0;
- private $selfCaption = '';
+ private $selfCaption = '';
private $weight;
- private $subTrackers = [];
+ private $subTrackers = array();
public $events;
- public function __construct( $options = [] ) {
- $this->weight = $options['weight'] ?? 1;
+ public function __construct( $options = array() ) {
+ $this->weight = $options['weight'] ?? 1;
$this->selfCaption = $options['caption'] ?? '';
- $this->events = new EventDispatcher();
+ $this->events = new EventDispatcher();
}
/**
@@ -100,28 +100,36 @@ public function stage( $weight = null, $caption = '' ) {
}
$this->selfWeight -= $weight;
- $subTracker = new Tracker( [
- 'caption' => $caption,
- 'weight' => $weight,
- ] );
+ $subTracker = new Tracker(
+ array(
+ 'caption' => $caption,
+ 'weight' => $weight,
+ )
+ );
$this->subTrackers[] = $subTracker;
- $subTracker->events->addListener( ProgressEvent::class, function () {
- $this->notifyProgress();
- } );
- $subTracker->events->addListener( DoneEvent::class, function () {
- if ( $this->isDone() ) {
- $this->notifyDone();
+ $subTracker->events->addListener(
+ ProgressEvent::class,
+ function () {
+ $this->notifyProgress();
+ }
+ );
+ $subTracker->events->addListener(
+ DoneEvent::class,
+ function () {
+ if ( $this->isDone() ) {
+ $this->notifyDone();
+ }
}
- } );
+ );
return $subTracker;
}
/**
- * @param float $value
- * @param string|null $caption
- */
- public function set( $value, $caption = null ) {
+ * @param float $value
+ * @param string|null $caption
+ */
+ public function set( $value, $caption = null ) {
if ( $value < $this->selfProgress ) {
throw new \InvalidArgumentException( "Progress cannot go backwards (tried updating to $value when it already was $this->selfProgress)" );
}
@@ -145,7 +153,7 @@ public function setCaption( $caption ) {
}
public function finish() {
- $this->selfDone = true;
+ $this->selfDone = true;
$this->selfProgress = 100;
$this->notifyProgress();
$this->notifyDone();
@@ -170,9 +178,13 @@ public function getProgress() {
if ( $this->selfDone ) {
return 100;
}
- $sum = array_reduce( $this->subTrackers, function ( $sum, $tracker ) {
- return $sum + $tracker->getProgress() * $tracker->getWeight();
- }, $this->selfProgress * $this->selfWeight );
+ $sum = array_reduce(
+ $this->subTrackers,
+ function ( $sum, $tracker ) {
+ return $sum + $tracker->getProgress() * $tracker->getWeight();
+ },
+ $this->selfProgress * $this->selfWeight
+ );
return round( $sum * 10000 ) / 10000;
}
@@ -193,5 +205,4 @@ private function notifyProgress() {
private function notifyDone() {
$this->events->dispatch( new DoneEvent() );
}
-
}
diff --git a/src/WordPress/Blueprints/Resources/Resolver/FilesystemResourceResolver.php b/src/WordPress/Blueprints/Resources/Resolver/FilesystemResourceResolver.php
index 0611758d..a0b059bc 100644
--- a/src/WordPress/Blueprints/Resources/Resolver/FilesystemResourceResolver.php
+++ b/src/WordPress/Blueprints/Resources/Resolver/FilesystemResourceResolver.php
@@ -9,32 +9,32 @@
class FilesystemResourceResolver implements ResourceResolverInterface {
/**
- * @param string $url
- */
- public function parseUrl( $url ) {
- if ( strncmp($url, 'file://', strlen('file://')) !== 0 ) {
+ * @param string $url
+ */
+ public function parseUrl( $url ) {
+ if ( strncmp( $url, 'file://', strlen( 'file://' ) ) !== 0 ) {
return null;
}
return ( new FilesystemResource() )->setPath( $url );
}
- static public function getResourceClass(): string {
+ public static function getResourceClass(): string {
return FilesystemResource::class;
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
- */
- public function supports( $resource ): bool {
+ * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
+ */
+ public function supports( $resource ): bool {
return $resource instanceof FilesystemResource;
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
- * @param \WordPress\Blueprints\Progress\Tracker $progress_tracker
- */
- public function stream( $resource, $progress_tracker ) {
+ * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
+ * @param \WordPress\Blueprints\Progress\Tracker $progress_tracker
+ */
+ public function stream( $resource, $progress_tracker ) {
if ( ! $this->supports( $resource ) ) {
throw new \InvalidArgumentException( 'Resource ' . get_class( $resource ) . ' unsupported' );
}
@@ -44,5 +44,4 @@ public function stream( $resource, $progress_tracker ) {
/** @var $resource FilesystemResource */
return fopen( $resource->path, 'r' );
}
-
}
diff --git a/src/WordPress/Blueprints/Resources/Resolver/InlineResourceResolver.php b/src/WordPress/Blueprints/Resources/Resolver/InlineResourceResolver.php
index 4d961240..f8d4774a 100644
--- a/src/WordPress/Blueprints/Resources/Resolver/InlineResourceResolver.php
+++ b/src/WordPress/Blueprints/Resources/Resolver/InlineResourceResolver.php
@@ -10,9 +10,9 @@
class InlineResourceResolver implements ResourceResolverInterface {
/**
- * @param string $url
- */
- public function parseUrl( $url ) {
+ * @param string $url
+ */
+ public function parseUrl( $url ) {
// If url starts with "protocol://" then we assume it's not inline raw data
if ( 0 !== preg_match( '#^[a-z_+]+://#', $url ) ) {
return null;
@@ -21,33 +21,32 @@ public function parseUrl( $url ) {
return ( new InlineResource() )->setContents( $url );
}
- static public function getResourceClass(): string {
+ public static function getResourceClass(): string {
return InlineResource::class;
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
- */
- public function supports( $resource ): bool {
+ * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
+ */
+ public function supports( $resource ): bool {
return $resource instanceof InlineResource;
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
- * @param \WordPress\Blueprints\Progress\Tracker $progress_tracker
- */
- public function stream( $resource, $progress_tracker ) {
+ * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
+ * @param \WordPress\Blueprints\Progress\Tracker $progress_tracker
+ */
+ public function stream( $resource, $progress_tracker ) {
if ( ! $this->supports( $resource ) ) {
throw new \InvalidArgumentException( 'Resource ' . get_class( $resource ) . ' unsupported' );
}
$progress_tracker->finish();
/** @var $resource InlineResource */
- $fp = fopen( "php://temp", 'r+' );
+ $fp = fopen( 'php://temp', 'r+' );
fwrite( $fp, $resource->contents );
rewind( $fp );
return $fp;
}
-
}
diff --git a/src/WordPress/Blueprints/Resources/Resolver/ResourceResolverCollection.php b/src/WordPress/Blueprints/Resources/Resolver/ResourceResolverCollection.php
index 67584450..31a449ca 100644
--- a/src/WordPress/Blueprints/Resources/Resolver/ResourceResolverCollection.php
+++ b/src/WordPress/Blueprints/Resources/Resolver/ResourceResolverCollection.php
@@ -23,9 +23,9 @@ public static function getResourceClass(): string {
}
/**
- * @param string $url
- */
- public function parseUrl( $url ) {
+ * @param string $url
+ */
+ public function parseUrl( $url ) {
foreach ( $this->resource_resolvers as $resolver ) {
/** @var ResourceResolverInterface $resolver */
$resource = $resolver->parseUrl( $url );
@@ -38,9 +38,9 @@ public function parseUrl( $url ) {
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
- */
- public function supports( $resource ): bool {
+ * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
+ */
+ public function supports( $resource ): bool {
foreach ( $this->resource_resolvers as $resolver ) {
/** @var ResourceResolverInterface $resolver */
if ( $resolver->supports( $resource ) ) {
@@ -52,10 +52,10 @@ public function supports( $resource ): bool {
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
- * @param \WordPress\Blueprints\Progress\Tracker $progressTracker
- */
- public function stream( $resource, $progressTracker ) {
+ * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
+ * @param \WordPress\Blueprints\Progress\Tracker $progressTracker
+ */
+ public function stream( $resource, $progressTracker ) {
foreach ( $this->resource_resolvers as $resolver ) {
/** @var ResourceResolverInterface $resolver */
if ( $resolver->supports( $resource ) ) {
diff --git a/src/WordPress/Blueprints/Resources/Resolver/ResourceResolverInterface.php b/src/WordPress/Blueprints/Resources/Resolver/ResourceResolverInterface.php
index 7f7b8beb..345b52d7 100644
--- a/src/WordPress/Blueprints/Resources/Resolver/ResourceResolverInterface.php
+++ b/src/WordPress/Blueprints/Resources/Resolver/ResourceResolverInterface.php
@@ -7,20 +7,20 @@
interface ResourceResolverInterface {
/**
- * @param string $url
- */
- public function parseUrl( $url );
+ * @param string $url
+ */
+ public function parseUrl( $url );
/**
- * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
- */
- public function supports( $resource ): bool;
+ * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
+ */
+ public function supports( $resource ): bool;
- static public function getResourceClass(): string;
+ public static function getResourceClass(): string;
/**
- * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
- * @param \WordPress\Blueprints\Progress\Tracker $progress_tracker
- */
- public function stream( $resource, $progress_tracker );
+ * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
+ * @param \WordPress\Blueprints\Progress\Tracker $progress_tracker
+ */
+ public function stream( $resource, $progress_tracker );
}
diff --git a/src/WordPress/Blueprints/Resources/Resolver/UrlResourceResolver.php b/src/WordPress/Blueprints/Resources/Resolver/UrlResourceResolver.php
index 22edb3e7..d70da6b4 100644
--- a/src/WordPress/Blueprints/Resources/Resolver/UrlResourceResolver.php
+++ b/src/WordPress/Blueprints/Resources/Resolver/UrlResourceResolver.php
@@ -18,10 +18,10 @@ public function __construct( DataSourceInterface $data_source ) {
}
/**
- * @param string $url
- */
- public function parseUrl( $url ) {
- if ( strncmp($url, 'http://', strlen('http://')) !== 0 && strncmp($url, 'https://', strlen('https://')) !== 0 ) {
+ * @param string $url
+ */
+ public function parseUrl( $url ) {
+ if ( strncmp( $url, 'http://', strlen( 'http://' ) ) !== 0 && strncmp( $url, 'https://', strlen( 'https://' ) ) !== 0 ) {
return null;
}
@@ -34,17 +34,17 @@ public static function getResourceClass(): string {
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
- */
- public function supports( $resource ): bool {
+ * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
+ */
+ public function supports( $resource ): bool {
return $resource instanceof UrlResource;
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
- * @param \WordPress\Blueprints\Progress\Tracker $progress_tracker
- */
- public function stream( $resource, $progress_tracker ) {
+ * @param \WordPress\Blueprints\Model\DataClass\ResourceDefinitionInterface $resource
+ * @param \WordPress\Blueprints\Progress\Tracker $progress_tracker
+ */
+ public function stream( $resource, $progress_tracker ) {
if ( ! $this->supports( $resource ) ) {
throw new InvalidArgumentException( 'Resource ' . get_class( $resource ) . ' unsupported' );
}
diff --git a/src/WordPress/Blueprints/Resources/ResourceManager.php b/src/WordPress/Blueprints/Resources/ResourceManager.php
index 2ceba893..f713bb77 100644
--- a/src/WordPress/Blueprints/Resources/ResourceManager.php
+++ b/src/WordPress/Blueprints/Resources/ResourceManager.php
@@ -17,14 +17,14 @@ public function __construct(
ResourceResolverCollection $resource_resolvers
) {
$this->resource_resolvers = $resource_resolvers;
- $this->fs = new Filesystem();
- $this->map = new Map();
+ $this->fs = new Filesystem();
+ $this->map = new Map();
}
/**
- * @param mixed[] $compiledResources
- */
- public function enqueue( $compiledResources ) {
+ * @param mixed[] $compiledResources
+ */
+ public function enqueue( $compiledResources ) {
foreach ( $compiledResources as $compiled ) {
/** @var CompiledResource $compiled */
@@ -40,7 +40,7 @@ public function getStream( $key ) {
}
public function bufferToTemporaryFile( $resource, $callback, $suffix = null ) {
- $fp = $this->getStream( $resource );
+ $fp = $this->getStream( $resource );
$path = $this->fs->tempnam( sys_get_temp_dir(), 'resource', $suffix );
$this->fs->dumpFile( $path, $fp );
diff --git a/src/WordPress/Blueprints/Runner/Blueprint/BlueprintRunner.php b/src/WordPress/Blueprints/Runner/Blueprint/BlueprintRunner.php
index 8b83878e..85f3fe20 100644
--- a/src/WordPress/Blueprints/Runner/Blueprint/BlueprintRunner.php
+++ b/src/WordPress/Blueprints/Runner/Blueprint/BlueprintRunner.php
@@ -20,16 +20,16 @@ public function __construct(
$resourceManagerFactory
) {
$this->resourceManagerFactory = $resourceManagerFactory;
- $this->runtime = $runtime;
- $this->events = new EventDispatcher();
+ $this->runtime = $runtime;
+ $this->events = new EventDispatcher();
}
/**
- * @param \WordPress\Blueprints\Compile\CompiledBlueprint $blueprint
- */
- public function run( $blueprint ) {
+ * @param \WordPress\Blueprints\Compile\CompiledBlueprint $blueprint
+ */
+ public function run( $blueprint ) {
$resourceManagerFactory = $this->resourceManagerFactory;
- $resourceManager = $resourceManagerFactory();
+ $resourceManager = $resourceManagerFactory();
$resourceManager->enqueue(
$blueprint->compiledResources
);
@@ -38,7 +38,7 @@ public function run( $blueprint ) {
$compiledStep->runner->setResourceManager( $resourceManager );
}
// Run, store results
- $results = [];
+ $results = array();
foreach ( $blueprint->compiledSteps as $k => $compiledStep ) {
/** @var CompiledStep $compiledStep */
try {
@@ -64,5 +64,4 @@ public function run( $blueprint ) {
return $results;
}
-
}
diff --git a/src/WordPress/Blueprints/Runner/Step/ActivatePlugin/wp_activate_plugin.php b/src/WordPress/Blueprints/Runner/Step/ActivatePlugin/wp_activate_plugin.php
index d42f258d..9e517359 100644
--- a/src/WordPress/Blueprints/Runner/Step/ActivatePlugin/wp_activate_plugin.php
+++ b/src/WordPress/Blueprints/Runner/Step/ActivatePlugin/wp_activate_plugin.php
@@ -1,14 +1,14 @@
'Administrator') )[0] );
+set_current_user( get_users( array( 'role' => 'Administrator' ) )[0] );
-$pluginPath = getenv('PLUGIN_PATH');
-if (!is_dir($pluginPath)) {
- activate_plugin($pluginPath);
+$pluginPath = getenv( 'PLUGIN_PATH' );
+if ( ! is_dir( $pluginPath ) ) {
+ activate_plugin( $pluginPath );
die();
}
@@ -21,4 +21,4 @@
}
// If we got here, the plugin was not found.
-exit(1);
+exit( 1 );
diff --git a/src/WordPress/Blueprints/Runner/Step/ActivatePluginStepRunner.php b/src/WordPress/Blueprints/Runner/Step/ActivatePluginStepRunner.php
index 7889b7eb..783c0fe0 100644
--- a/src/WordPress/Blueprints/Runner/Step/ActivatePluginStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/ActivatePluginStepRunner.php
@@ -9,33 +9,33 @@
class ActivatePluginStepRunner extends BaseStepRunner {
/**
- * @param \WordPress\Blueprints\Model\DataClass\ActivatePluginStep $input
- * @param \WordPress\Blueprints\Progress\Tracker $tracker
- */
- function run( $input, $tracker ) {
- ($nullsafeVariable1 = $tracker) ? $nullsafeVariable1->setCaption($input->progress->caption ?? "Activating plugin " . $input->slug) : null;
+ * @param \WordPress\Blueprints\Model\DataClass\ActivatePluginStep $input
+ * @param \WordPress\Blueprints\Progress\Tracker $tracker
+ */
+ function run( $input, $tracker ) {
+ ( $nullsafeVariable1 = $tracker ) ? $nullsafeVariable1->setCaption( $input->progress->caption ?? 'Activating plugin ' . $input->slug ) : null;
// @TODO: Compare performance to the wp_activate_plugin.php script.
- // On the first sight it seems to be significantly faster.
+ // On the first sight it seems to be significantly faster.
return $this->getRuntime()->runShellCommand(
- [
+ array(
'php',
'wp-cli.phar',
'plugin',
'activate',
$input->slug,
- ]
+ )
);
-// return $this->getRuntime()->evalPhpInSubProcess(
-// file_get_contents( __DIR__ . '/ActivatePlugin/wp_activate_plugin.php' ),
-// [
-// 'PLUGIN_PATH' => $input->pluginPath,
-// ]
-// );
+ // return $this->getRuntime()->evalPhpInSubProcess(
+ // file_get_contents( __DIR__ . '/ActivatePlugin/wp_activate_plugin.php' ),
+ // [
+ // 'PLUGIN_PATH' => $input->pluginPath,
+ // ]
+ // );
}
public function getDefaultCaption( $input ) {
- return "Activating plugin";
+ return 'Activating plugin';
}
}
diff --git a/src/WordPress/Blueprints/Runner/Step/ActivateTheme/wp_activate_theme.php b/src/WordPress/Blueprints/Runner/Step/ActivateTheme/wp_activate_theme.php
index a653c2d0..4fa3982d 100644
--- a/src/WordPress/Blueprints/Runner/Step/ActivateTheme/wp_activate_theme.php
+++ b/src/WordPress/Blueprints/Runner/Step/ActivateTheme/wp_activate_theme.php
@@ -1,7 +1,7 @@
'Administrator') )[0] );
-switch_theme( getenv('THEME_FOLDER_NAME') );
+set_current_user( get_users( array( 'role' => 'Administrator' ) )[0] );
+switch_theme( getenv( 'THEME_FOLDER_NAME' ) );
diff --git a/src/WordPress/Blueprints/Runner/Step/ActivateThemeStepRunner.php b/src/WordPress/Blueprints/Runner/Step/ActivateThemeStepRunner.php
index 03f67944..455f441b 100644
--- a/src/WordPress/Blueprints/Runner/Step/ActivateThemeStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/ActivateThemeStepRunner.php
@@ -11,40 +11,40 @@
class ActivateThemeStepRunner extends BaseStepRunner {
- static public function getStepClass(): string {
+ public static function getStepClass(): string {
return ActivateThemeStep::class;
}
/**
- * @param ActivateThemeStep $input
- * @return string|null
- */
- public function getDefaultCaption( $input ) {
- return "Activating theme " . $input->slug;
+ * @param ActivateThemeStep $input
+ * @return string|null
+ */
+ public function getDefaultCaption( $input ) {
+ return 'Activating theme ' . $input->slug;
}
/**
- * @param \WordPress\Blueprints\Model\DataClass\ActivateThemeStep $input
- * @param \WordPress\Blueprints\Progress\Tracker $tracker
- */
- public function run( $input, $tracker ) {
+ * @param \WordPress\Blueprints\Model\DataClass\ActivateThemeStep $input
+ * @param \WordPress\Blueprints\Progress\Tracker $tracker
+ */
+ public function run( $input, $tracker ) {
// @TODO: Compare performance to the wp_activate_theme.php script.
- // On the first sight it seems to be significantly faster.
+ // On the first sight it seems to be significantly faster.
return $this->getRuntime()->runShellCommand(
- [
+ array(
'php',
'wp-cli.phar',
'theme',
'activate',
$input->slug,
- ]
+ )
);
-// return $this->getRuntime()->evalPhpInSubProcess(
-// file_get_contents( __DIR__ . '/ActivatePlugin/wp_activate_theme.php' ),
-// [
-// 'THEME_FOLDER_NAME' => $this->input->themeFolderName,
-// ]
-// );
+ // return $this->getRuntime()->evalPhpInSubProcess(
+ // file_get_contents( __DIR__ . '/ActivatePlugin/wp_activate_theme.php' ),
+ // [
+ // 'THEME_FOLDER_NAME' => $this->input->themeFolderName,
+ // ]
+ // );
}
}
diff --git a/src/WordPress/Blueprints/Runner/Step/BaseStepRunner.php b/src/WordPress/Blueprints/Runner/Step/BaseStepRunner.php
index 8a81093c..77052467 100644
--- a/src/WordPress/Blueprints/Runner/Step/BaseStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/BaseStepRunner.php
@@ -11,9 +11,9 @@ abstract class BaseStepRunner implements StepRunnerInterface {
protected $runtime;
/**
- * @param \WordPress\Blueprints\Resources\ResourceManager $map
- */
- public function setResourceManager( $map ) {
+ * @param \WordPress\Blueprints\Resources\ResourceManager $map
+ */
+ public function setResourceManager( $map ) {
$this->resourceManager = $map;
}
@@ -22,9 +22,9 @@ protected function getResource( $declaration ) {
}
/**
- * @param \WordPress\Blueprints\Runtime\RuntimeInterface $runtime
- */
- public function setRuntime( $runtime ) {
+ * @param \WordPress\Blueprints\Runtime\RuntimeInterface $runtime
+ */
+ public function setRuntime( $runtime ) {
$this->runtime = $runtime;
}
diff --git a/src/WordPress/Blueprints/Runner/Step/DefineSiteUrlStepRunner.php b/src/WordPress/Blueprints/Runner/Step/DefineSiteUrlStepRunner.php
index 803c3573..df7dc24f 100644
--- a/src/WordPress/Blueprints/Runner/Step/DefineSiteUrlStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/DefineSiteUrlStepRunner.php
@@ -8,23 +8,29 @@
class DefineSiteUrlStepRunner extends BaseStepRunner {
/**
- * @param \WordPress\Blueprints\Model\DataClass\DefineSiteUrlStep $input
- */
- function run( $input ) {
+ * @param \WordPress\Blueprints\Model\DataClass\DefineSiteUrlStep $input
+ */
+ function run( $input ) {
// @TODO: Don't manually construct the step object like this.
- // There may be more required fields in the future.
- // Instead, either remove this step, move the const-setting
- // logic to another class with crisply defined dependencies,
- // or provide a method similar to:
- // $executionContext->createStepRunner( DefineWpConfigConstsStepRunner::class )
+ // There may be more required fields in the future.
+ // Instead, either remove this step, move the const-setting
+ // logic to another class with crisply defined dependencies,
+ // or provide a method similar to:
+ // $executionContext->createStepRunner( DefineWpConfigConstsStepRunner::class )
$defineConstsHandler = new DefineWpConfigConstsStepRunner();
$defineConstsHandler->setRuntime( $this->getRuntime() );
- $defineConstsHandler->run( ( new DefineWpConfigConstsStep() )
- ->setConsts( [ 'WP_HOME' => $input->siteUrl, 'WP_SITEURL' => $input->siteUrl ] )
+ $defineConstsHandler->run(
+ ( new DefineWpConfigConstsStep() )
+ ->setConsts(
+ array(
+ 'WP_HOME' => $input->siteUrl,
+ 'WP_SITEURL' => $input->siteUrl,
+ )
+ )
);
}
public function getDefaultCaption( $input ) {
- return "Defining site URL";
+ return 'Defining site URL';
}
}
diff --git a/src/WordPress/Blueprints/Runner/Step/DefineWpConfigConsts/functions.php b/src/WordPress/Blueprints/Runner/Step/DefineWpConfigConsts/functions.php
index 9a83ae1c..740e51be 100644
--- a/src/WordPress/Blueprints/Runner/Step/DefineWpConfigConsts/functions.php
+++ b/src/WordPress/Blueprints/Runner/Step/DefineWpConfigConsts/functions.php
@@ -68,24 +68,24 @@
*
* @return string
*/
-function rewrite_wp_config_to_define_constants( $content, $constants = [] ) {
+function rewrite_wp_config_to_define_constants( $content, $constants = array() ) {
$tokens = array_reverse( token_get_all( $content ) );
- $output = [];
- $defined_expressions = [];
+ $output = array();
+ $defined_expressions = array();
// Look through all the tokens and find the define calls
do {
- $buffer = [];
- $name_buffer = [];
- $value_buffer = [];
- $third_arg_buffer = [];
+ $buffer = array();
+ $name_buffer = array();
+ $value_buffer = array();
+ $third_arg_buffer = array();
// Capture everything until the define call into output.
// Capturing the define call into a buffer.
// Example:
- // 2 ? 'WP_DEBUG' : 'FOO', true);
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // define(count([1,2]) > 2 ? 'WP_DEBUG' : 'FOO', true);
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
$open_parenthesis = 0;
while ( $token = array_pop( $tokens ) ) {
$buffer[] = $token;
- if ( $token === "(" || $token === "[" || $token === "{" ) {
- ++ $open_parenthesis;
- } elseif ( $token === ")" || $token === "]" || $token === "}" ) {
- -- $open_parenthesis;
- } elseif ( $token === "," && $open_parenthesis === 0 ) {
+ if ( $token === '(' || $token === '[' || $token === '{' ) {
+ ++$open_parenthesis;
+ } elseif ( $token === ')' || $token === ']' || $token === '}' ) {
+ --$open_parenthesis;
+ } elseif ( $token === ',' && $open_parenthesis === 0 ) {
break;
}
@@ -167,20 +167,20 @@ function rewrite_wp_config_to_define_constants( $content, $constants = [] ) {
}
// Capture everything until the closing parenthesis
- // define("WP_DEBUG", true);
- // ^^^^^^
+ // define("WP_DEBUG", true);
+ // ^^^^^^
$open_parenthesis = 0;
$is_second_argument = true;
while ( $token = array_pop( $tokens ) ) {
$buffer[] = $token;
- if ( $token === ")" && $open_parenthesis === 0 ) {
+ if ( $token === ')' && $open_parenthesis === 0 ) {
// Final parenthesis of the define call.
break;
- } elseif ( $token === "(" || $token === "[" || $token === "{" ) {
- ++ $open_parenthesis;
- } elseif ( $token === ")" || $token === "]" || $token === "}" ) {
- -- $open_parenthesis;
- } elseif ( $token === "," && $open_parenthesis === 0 ) {
+ } elseif ( $token === '(' || $token === '[' || $token === '{' ) {
+ ++$open_parenthesis;
+ } elseif ( $token === ')' || $token === ']' || $token === '}' ) {
+ --$open_parenthesis;
+ } elseif ( $token === ',' && $open_parenthesis === 0 ) {
// This define call has more than 2 arguments! The third one is the
// boolean value indicating $is_case_insensitive. Let's continue capturing
// to $third_arg_buffer.
@@ -194,11 +194,11 @@ function rewrite_wp_config_to_define_constants( $content, $constants = [] ) {
}
// Capture until the semicolon
- // define("WP_DEBUG", true) ;
- // ^^^
+ // define("WP_DEBUG", true) ;
+ // ^^^
while ( $token = array_pop( $tokens ) ) {
$buffer[] = $token;
- if ( $token === ";" ) {
+ if ( $token === ';' ) {
break;
}
}
@@ -218,7 +218,7 @@ function rewrite_wp_config_to_define_constants( $content, $constants = [] ) {
$name_is_literal = false;
break;
}
- } elseif ( $token !== "(" && $token !== ")" ) {
+ } elseif ( $token !== '(' && $token !== ')' ) {
$name_is_literal = false;
break;
}
@@ -237,16 +237,16 @@ function rewrite_wp_config_to_define_constants( $content, $constants = [] ) {
}
$output = array_merge(
$output,
- [ "if(!defined(" ],
+ array( 'if(!defined(' ),
$name_buffer,
- [ ")) {\n " ],
- [ 'define(' ],
+ array( ")) {\n " ),
+ array( 'define(' ),
$name_buffer,
- [ ',' ],
+ array( ',' ),
$value_buffer,
$third_arg_buffer,
- [ ");" ],
- [ "\n}\n" ]
+ array( ');' ),
+ array( "\n}\n" )
);
continue;
}
@@ -266,12 +266,12 @@ function rewrite_wp_config_to_define_constants( $content, $constants = [] ) {
// Let's rewrite its value to the one
$output = array_merge(
$output,
- [ 'define(' ],
+ array( 'define(' ),
$name_buffer,
- [ ',' ],
- [ var_export( $constants[ $name ], true ) ],
+ array( ',' ),
+ array( var_export( $constants[ $name ], true ) ),
$third_arg_buffer,
- [ ");" ]
+ array( ');' )
);
// Remove the constant from the list so we can process any remaining
@@ -281,22 +281,22 @@ function rewrite_wp_config_to_define_constants( $content, $constants = [] ) {
// Add any constants that weren't found in the file
if ( count( $constants ) ) {
- $prepend = [
+ $prepend = array(
" $value ) {
$prepend = array_merge(
$prepend,
- [
- "define(",
+ array(
+ 'define(',
var_export( $name, true ),
',',
var_export( $value, true ),
");\n",
- ]
+ )
);
}
- $prepend[] = "?>";
+ $prepend[] = '?>';
$output = array_merge(
$prepend,
$output
@@ -321,7 +321,7 @@ function stringify_tokens( $tokens ) {
}
function skip_whitespace( $tokens ) {
- $output = [];
+ $output = array();
foreach ( $tokens as $token ) {
if ( is_array( $token ) && ( $token[0] === T_WHITESPACE || $token[0] === T_COMMENT || $token[0] === T_DOC_COMMENT ) ) {
continue;
diff --git a/src/WordPress/Blueprints/Runner/Step/DefineWpConfigConstsStepRunner.php b/src/WordPress/Blueprints/Runner/Step/DefineWpConfigConstsStepRunner.php
index 0c84cd5c..dad321da 100644
--- a/src/WordPress/Blueprints/Runner/Step/DefineWpConfigConstsStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/DefineWpConfigConstsStepRunner.php
@@ -7,9 +7,9 @@
class DefineWpConfigConstsStepRunner extends BaseStepRunner {
/**
- * @param \WordPress\Blueprints\Model\DataClass\DefineWpConfigConstsStep $input
- */
- function run( $input ) {
+ * @param \WordPress\Blueprints\Model\DataClass\DefineWpConfigConstsStep $input
+ */
+ function run( $input ) {
$functions = file_get_contents( __DIR__ . '/DefineWpConfigConsts/functions.php' );
return $this->getRuntime()->evalPhpInSubProcess(
@@ -20,14 +20,13 @@ function run( $input ) {
$new_wp_config = rewrite_wp_config_to_define_constants($wp_config, $consts);
file_put_contents($wp_config_path, $new_wp_config);
',
- [
+ array(
'CONSTS' => json_encode( $input->consts ),
- ]
+ )
);
}
public function getDefaultCaption( $input ) {
- return "Defining wp-config constants";
+ return 'Defining wp-config constants';
}
-
}
diff --git a/src/WordPress/Blueprints/Runner/Step/DownloadWordPressStepRunner.php b/src/WordPress/Blueprints/Runner/Step/DownloadWordPressStepRunner.php
index e39d443e..6c34c443 100644
--- a/src/WordPress/Blueprints/Runner/Step/DownloadWordPressStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/DownloadWordPressStepRunner.php
@@ -8,24 +8,23 @@
class DownloadWordPressStepRunner extends InstallAssetStepRunner {
/**
- * @param \WordPress\Blueprints\Model\DataClass\DownloadWordPressStep $input
- * @param \WordPress\Blueprints\Progress\Tracker $progress
- */
- public function run(
+ * @param \WordPress\Blueprints\Model\DataClass\DownloadWordPressStep $input
+ * @param \WordPress\Blueprints\Progress\Tracker $progress
+ */
+ public function run(
$input,
$progress
) {
$this->unzipAssetTo( $input->wordPressZip, $this->getRuntime()->getDocumentRoot() );
$cofigSample = $this->getRuntime()->resolvePath( 'wp-config-sample.php' );
- $cofig = $this->getRuntime()->resolvePath( 'wp-config.php' );
+ $cofig = $this->getRuntime()->resolvePath( 'wp-config.php' );
if ( file_exists( $cofigSample ) && ! file_exists( $cofig ) ) {
copy( $cofigSample, $cofig );
}
}
public function getDefaultCaption( $input ) {
- return "Extracting WordPress";
+ return 'Extracting WordPress';
}
-
}
diff --git a/src/WordPress/Blueprints/Runner/Step/EnableMultisiteStepRunner.php b/src/WordPress/Blueprints/Runner/Step/EnableMultisiteStepRunner.php
index f8aad316..39bf5cc9 100644
--- a/src/WordPress/Blueprints/Runner/Step/EnableMultisiteStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/EnableMultisiteStepRunner.php
@@ -12,16 +12,16 @@ function run( $input ) {
throw new \LogicException( 'Not implemented yet' );
// @TODO:
-// return $this->getRuntime()->runShellCommand(
-// [
-// 'php',
-// 'wp-cli.phar',
-// 'core',
-// 'multisite-convert',
-// // @TODO: Base path should come from the runtime, e.g.
-// // Playground need to provide the /scope:0.892173/ value
-// '--base=/wordpress',
-// ]
-// );
+ // return $this->getRuntime()->runShellCommand(
+ // [
+ // 'php',
+ // 'wp-cli.phar',
+ // 'core',
+ // 'multisite-convert',
+ // @TODO: Base path should come from the runtime, e.g.
+ // Playground need to provide the /scope:0.892173/ value
+ // '--base=/wordpress',
+ // ]
+ // );
}
}
diff --git a/src/WordPress/Blueprints/Runner/Step/EvalPHPCallbackStepRunner.php b/src/WordPress/Blueprints/Runner/Step/EvalPHPCallbackStepRunner.php
index 000fc0dc..849b893d 100644
--- a/src/WordPress/Blueprints/Runner/Step/EvalPHPCallbackStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/EvalPHPCallbackStepRunner.php
@@ -8,7 +8,7 @@
class EvalPHPCallbackStepRunner extends BaseStepRunner {
/**
* @param EvalPHPCallbackStep $input
- * @param Tracker $tracker
+ * @param Tracker $tracker
*/
function run( $input, $tracker ) {
if ( ! is_callable( $input->callback ) ) {
diff --git a/src/WordPress/Blueprints/Runner/Step/ImportFileStepRunner.php b/src/WordPress/Blueprints/Runner/Step/ImportFileStepRunner.php
index 1aa6f15c..24eb3362 100644
--- a/src/WordPress/Blueprints/Runner/Step/ImportFileStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/ImportFileStepRunner.php
@@ -10,28 +10,28 @@
class ImportFileStepRunner extends BaseStepRunner {
/**
- * @param \WordPress\Blueprints\Model\DataClass\ImportFileStep $input
- * @param \WordPress\Blueprints\Progress\Tracker $tracker
- */
- function run( $input, $tracker ) {
- ($nullsafeVariable1 = $tracker) ? $nullsafeVariable1->setCaption($input->progress->caption ?? "Importing starter content") : null;
+ * @param \WordPress\Blueprints\Model\DataClass\ImportFileStep $input
+ * @param \WordPress\Blueprints\Progress\Tracker $tracker
+ */
+ function run( $input, $tracker ) {
+ ( $nullsafeVariable1 = $tracker ) ? $nullsafeVariable1->setCaption( $input->progress->caption ?? 'Importing starter content' ) : null;
// @TODO: Install the wordpress-importer plugin if it's not already installed
- // wp plugin install wordpress-importer --activate
- // Perhaps we'll need to package up some of these tasks in separate classes
- // to make them more reusable? Or should we just reuse the existing steps?
+ // wp plugin install wordpress-importer --activate
+ // Perhaps we'll need to package up some of these tasks in separate classes
+ // to make them more reusable? Or should we just reuse the existing steps?
return $this->resourceManager->bufferToTemporaryFile(
$input->file,
function ( $path ) use ( $input ) {
return $this->getRuntime()->runShellCommand(
- [
+ array(
'php',
'wp-cli.phar',
'import',
$path,
'--authors=create',
- ]
+ )
);
},
'.wxr'
diff --git a/src/WordPress/Blueprints/Runner/Step/InstallAssetStepRunner.php b/src/WordPress/Blueprints/Runner/Step/InstallAssetStepRunner.php
index 7995403e..61c75940 100644
--- a/src/WordPress/Blueprints/Runner/Step/InstallAssetStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/InstallAssetStepRunner.php
@@ -15,16 +15,18 @@ protected function unzipAssetTo( $zipResource, $targetPath ) {
if ( ! file_exists( $targetPath ) ) {
mkdir( $targetPath, 0777, true );
}
- $this->getRuntime()->withTemporaryDirectory( function ( $tmpPath ) use ( $zipResource, $targetPath ) {
- zip_extract_to( $this->getResource( $zipResource ), $tmpPath );
- $extractedFiles = list_files( $tmpPath, $omitDotFiles = true );
- $onlyExtractedSingleDirectory = count( $extractedFiles ) === 1 && is_dir( $tmpPath . '/' . $extractedFiles[0] );
- $moveFromPath = $onlyExtractedSingleDirectory ? "$tmpPath/$extractedFiles[0]" : $tmpPath;
+ $this->getRuntime()->withTemporaryDirectory(
+ function ( $tmpPath ) use ( $zipResource, $targetPath ) {
+ zip_extract_to( $this->getResource( $zipResource ), $tmpPath );
+ $extractedFiles = list_files( $tmpPath, $omitDotFiles = true );
+ $onlyExtractedSingleDirectory = count( $extractedFiles ) === 1 && is_dir( $tmpPath . '/' . $extractedFiles[0] );
+ $moveFromPath = $onlyExtractedSingleDirectory ? "$tmpPath/$extractedFiles[0]" : $tmpPath;
- move_files_from_directory_to_directory(
- $moveFromPath,
- $this->getRuntime()->resolvePath( $targetPath )
- );
- } );
+ move_files_from_directory_to_directory(
+ $moveFromPath,
+ $this->getRuntime()->resolvePath( $targetPath )
+ );
+ }
+ );
}
}
diff --git a/src/WordPress/Blueprints/Runner/Step/InstallPluginStepRunner.php b/src/WordPress/Blueprints/Runner/Step/InstallPluginStepRunner.php
index b5322189..ccf56447 100644
--- a/src/WordPress/Blueprints/Runner/Step/InstallPluginStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/InstallPluginStepRunner.php
@@ -9,12 +9,12 @@
class InstallPluginStepRunner extends InstallAssetStepRunner {
/**
- * @param \WordPress\Blueprints\Model\DataClass\InstallPluginStep $input
- * @param \WordPress\Blueprints\Progress\Tracker $tracker
- */
- function run( $input, $tracker ) {
+ * @param \WordPress\Blueprints\Model\DataClass\InstallPluginStep $input
+ * @param \WordPress\Blueprints\Progress\Tracker $tracker
+ */
+ function run( $input, $tracker ) {
// @TODO: inject this information into this step
- $pluginDir = 'plugin' . rand( 0, 1000 );
+ $pluginDir = 'plugin' . rand( 0, 1000 );
$targetPath = $this->getRuntime()->resolvePath( 'wp-content/plugins/' . $pluginDir );
$this->unzipAssetTo( $input->pluginZipFile, $targetPath );
@@ -23,14 +23,14 @@ function run( $input, $tracker ) {
// plugins in WordPress are identified by their path, not slug.
$this->getRuntime()->evalPhpInSubProcess(
file_get_contents( __DIR__ . '/ActivatePlugin/wp_activate_plugin.php' ),
- [
+ array(
'PLUGIN_PATH' => $targetPath,
- ]
+ )
);
}
}
public function getDefaultCaption( $input ) {
- return "Installing plugin " . $input->pluginZipFile;
+ return 'Installing plugin ' . $input->pluginZipFile;
}
}
diff --git a/src/WordPress/Blueprints/Runner/Step/InstallSqliteIntegrationStepRunner.php b/src/WordPress/Blueprints/Runner/Step/InstallSqliteIntegrationStepRunner.php
index 6be1d28b..63ffe998 100644
--- a/src/WordPress/Blueprints/Runner/Step/InstallSqliteIntegrationStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/InstallSqliteIntegrationStepRunner.php
@@ -9,10 +9,10 @@
class InstallSqliteIntegrationStepRunner extends InstallAssetStepRunner {
/**
* @param InstallSqliteIntegrationStep $input
- * @param Tracker $tracker
+ * @param Tracker $tracker
*/
function run( $input, $tracker ) {
- $pluginDir = 'sqlite-database-integration';
+ $pluginDir = 'sqlite-database-integration';
$targetPath = $this->getRuntime()->resolvePath( 'wp-content/mu-plugins/' . $pluginDir );
$this->unzipAssetTo( $input->sqlitePluginZip, $targetPath );
@@ -29,12 +29,13 @@ function run( $input, $tracker ) {
$db
);
file_put_contents( $this->getRuntime()->resolvePath( 'wp-content/db.php' ), $db );
- file_put_contents( $this->getRuntime()->resolvePath( 'wp-content/mu-plugins/0-sqlite.php' ),
- 'getRuntime()->resolvePath( 'wp-content/mu-plugins/0-sqlite.php' ),
+ 'getRuntime()->resolvePath( 'wp-content/themes/' . $themeDir );
$this->unzipAssetTo( $input->themeZipFile, $targetPath );
@@ -25,15 +25,14 @@ function run( $input, $tracker ) {
// plugins in WordPress are identified by their path, not slug.
$this->getRuntime()->evalPhpInSubProcess(
file_get_contents( __DIR__ . '/ActivateTheme/wp_activate_theme.php' ),
- [
+ array(
'THEME_FOLDER_NAME' => $themeDir,
- ]
+ )
);
}
}
public function getDefaultCaption( $input ) {
- return "Installing theme " . $input->themeZipFile;
+ return 'Installing theme ' . $input->themeZipFile;
}
-
}
diff --git a/src/WordPress/Blueprints/Runner/Step/MkdirStepRunner.php b/src/WordPress/Blueprints/Runner/Step/MkdirStepRunner.php
index e7af07c5..86d99370 100644
--- a/src/WordPress/Blueprints/Runner/Step/MkdirStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/MkdirStepRunner.php
@@ -8,9 +8,9 @@
class MkdirStepRunner extends BaseStepRunner {
/**
- * @param \WordPress\Blueprints\Model\DataClass\MkdirStep $input
- */
- function run( $input ) {
+ * @param \WordPress\Blueprints\Model\DataClass\MkdirStep $input
+ */
+ function run( $input ) {
// @TODO: Treat $input->path as relative path to the document root (unless it's absolute)
$success = mkdir( $input->path );
if ( ! $success ) {
diff --git a/src/WordPress/Blueprints/Runner/Step/RmStepRunner.php b/src/WordPress/Blueprints/Runner/Step/RmStepRunner.php
index 23df8388..63394382 100644
--- a/src/WordPress/Blueprints/Runner/Step/RmStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/RmStepRunner.php
@@ -7,22 +7,21 @@
use WordPress\Blueprints\BlueprintException;
use WordPress\Blueprints\Model\DataClass\RmStep;
-class RmStepRunner extends BaseStepRunner
-{
- /**
- * @param RmStep $input
- */
- public function run($input)
- {
- $resolvedPath = $this->getRuntime()->resolvePath($input->path);
- $fileSystem = new Filesystem();
- if (false === $fileSystem->exists($resolvedPath)) {
- throw new BlueprintException("Failed to remove \"$resolvedPath\": the directory or file does not exist.");
- }
- try {
- $fileSystem->remove($resolvedPath);
- } catch (IOException $exception) {
- throw new BlueprintException("Failed to remove the directory or file at \"$resolvedPath\"", 0, $exception);
- }
- }
+class RmStepRunner extends BaseStepRunner {
+
+ /**
+ * @param RmStep $input
+ */
+ public function run( $input ) {
+ $resolvedPath = $this->getRuntime()->resolvePath( $input->path );
+ $fileSystem = new Filesystem();
+ if ( false === $fileSystem->exists( $resolvedPath ) ) {
+ throw new BlueprintException( "Failed to remove \"$resolvedPath\": the directory or file does not exist." );
+ }
+ try {
+ $fileSystem->remove( $resolvedPath );
+ } catch ( IOException $exception ) {
+ throw new BlueprintException( "Failed to remove the directory or file at \"$resolvedPath\"", 0, $exception );
+ }
+ }
}
diff --git a/src/WordPress/Blueprints/Runner/Step/RunPHPStepRunner.php b/src/WordPress/Blueprints/Runner/Step/RunPHPStepRunner.php
index f1ae4a40..65f4f9f3 100644
--- a/src/WordPress/Blueprints/Runner/Step/RunPHPStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/RunPHPStepRunner.php
@@ -7,11 +7,11 @@
class RunPHPStepRunner extends BaseStepRunner {
/**
- * @param \WordPress\Blueprints\Model\DataClass\RunPHPStep $input
- * @param \WordPress\Blueprints\Progress\Tracker $tracker
- */
- function run( $input, $tracker ) {
- ($nullsafeVariable1 = $tracker) ? $nullsafeVariable1->setCaption("Running custom PHP code") : null;
+ * @param \WordPress\Blueprints\Model\DataClass\RunPHPStep $input
+ * @param \WordPress\Blueprints\Progress\Tracker $tracker
+ */
+ function run( $input, $tracker ) {
+ ( $nullsafeVariable1 = $tracker ) ? $nullsafeVariable1->setCaption( 'Running custom PHP code' ) : null;
return $this->getRuntime()->evalPhpInSubProcess( $input->code );
}
diff --git a/src/WordPress/Blueprints/Runner/Step/RunSQLStepRunner.php b/src/WordPress/Blueprints/Runner/Step/RunSQLStepRunner.php
index 8032d545..c2f96728 100644
--- a/src/WordPress/Blueprints/Runner/Step/RunSQLStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/RunSQLStepRunner.php
@@ -11,14 +11,15 @@
class RunSQLStepRunner extends BaseStepRunner {
/**
- * @param RunSQLStep $input
- * @param \WordPress\Blueprints\Progress\Tracker|null $progress
- */
- function run(
+ * @param RunSQLStep $input
+ * @param \WordPress\Blueprints\Progress\Tracker|null $progress
+ */
+ function run(
$input,
$progress = null
) {
- return $this->getRuntime()->evalPhpInSubProcess( <<<'CODE'
+ return $this->getRuntime()->evalPhpInSubProcess(
+ <<<'CODE'
getResource( $input->sql )
);
}
public function getDefaultCaption( $input ) {
- return "Running SQL queries";
+ return 'Running SQL queries';
}
}
diff --git a/src/WordPress/Blueprints/Runner/Step/RunWordPressInstallerStepRunner.php b/src/WordPress/Blueprints/Runner/Step/RunWordPressInstallerStepRunner.php
index 0ef91f3f..b32f5044 100644
--- a/src/WordPress/Blueprints/Runner/Step/RunWordPressInstallerStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/RunWordPressInstallerStepRunner.php
@@ -7,12 +7,12 @@
class RunWordPressInstallerStepRunner extends BaseStepRunner {
/**
- * @param \WordPress\Blueprints\Model\DataClass\RunWordPressInstallerStep $input
- * @param \WordPress\Blueprints\Progress\Tracker $tracker
- */
- function run( $input, $tracker ) {
+ * @param \WordPress\Blueprints\Model\DataClass\RunWordPressInstallerStep $input
+ * @param \WordPress\Blueprints\Progress\Tracker $tracker
+ */
+ function run( $input, $tracker ) {
return $this->getRuntime()->runShellCommand(
- [
+ array(
'php',
'wp-cli.phar',
'core',
@@ -22,13 +22,12 @@ function run( $input, $tracker ) {
'--admin_user=' . $input->options->adminUsername,
'--admin_password=' . $input->options->adminPassword,
'--admin_email=admin@wordpress.internal',
- ],
+ ),
$this->getRuntime()->getDocumentRoot()
);
}
public function getDefaultCaption( $input ) {
- return "Installing WordPress";
+ return 'Installing WordPress';
}
-
}
diff --git a/src/WordPress/Blueprints/Runner/Step/SetSiteOptionsStepRunner.php b/src/WordPress/Blueprints/Runner/Step/SetSiteOptionsStepRunner.php
index e032b12d..4bc9447b 100644
--- a/src/WordPress/Blueprints/Runner/Step/SetSiteOptionsStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/SetSiteOptionsStepRunner.php
@@ -8,13 +8,14 @@
class SetSiteOptionsStepRunner extends BaseStepRunner {
/**
- * @param SetSiteOptionsStep $input
- * @param \WordPress\Blueprints\Progress\Tracker $tracker
- */
- function run( $input, $tracker ) {
+ * @param SetSiteOptionsStep $input
+ * @param \WordPress\Blueprints\Progress\Tracker $tracker
+ */
+ function run( $input, $tracker ) {
// Running a custom PHP script is much faster than setting each option
// with a separate wp-cli command.
- return $this->getRuntime()->evalPhpInSubProcess( '
+ return $this->getRuntime()->evalPhpInSubProcess(
+ '
json_encode( $input->options ),
- ]
+ )
);
}
public function getDefaultCaption( $input ) {
- return "Setting site options";
+ return 'Setting site options';
}
-
}
diff --git a/src/WordPress/Blueprints/Runner/Step/StepRunnerInterface.php b/src/WordPress/Blueprints/Runner/Step/StepRunnerInterface.php
index 1f3a83c1..5056ba20 100644
--- a/src/WordPress/Blueprints/Runner/Step/StepRunnerInterface.php
+++ b/src/WordPress/Blueprints/Runner/Step/StepRunnerInterface.php
@@ -8,16 +8,16 @@
interface StepRunnerInterface {
/**
- * @param \WordPress\Blueprints\Resources\ResourceManager $map
- */
- public function setResourceManager( $map );
+ * @param \WordPress\Blueprints\Resources\ResourceManager $map
+ */
+ public function setResourceManager( $map );
/**
- * @param \WordPress\Blueprints\Runtime\RuntimeInterface $runtime
- */
- public function setRuntime( $runtime );
+ * @param \WordPress\Blueprints\Runtime\RuntimeInterface $runtime
+ */
+ public function setRuntime( $runtime );
-// @TODO: Document how this method isn't defined because
-// PHP doens't support covariant arguments
-// function run( StepInterface $input, Tracker $tracker );
+ // @TODO: Document how this method isn't defined because
+ // PHP doens't support covariant arguments
+ // function run( StepInterface $input, Tracker $tracker );
}
diff --git a/src/WordPress/Blueprints/Runner/Step/WriteFileStepRunner.php b/src/WordPress/Blueprints/Runner/Step/WriteFileStepRunner.php
index a7a83930..3e9bee3b 100644
--- a/src/WordPress/Blueprints/Runner/Step/WriteFileStepRunner.php
+++ b/src/WordPress/Blueprints/Runner/Step/WriteFileStepRunner.php
@@ -7,10 +7,10 @@
class WriteFileStepRunner extends BaseStepRunner {
/**
- * @param \WordPress\Blueprints\Model\DataClass\WriteFileStep $input
- * @param \WordPress\Blueprints\Progress\Tracker|null $progress
- */
- public function run(
+ * @param \WordPress\Blueprints\Model\DataClass\WriteFileStep $input
+ * @param \WordPress\Blueprints\Progress\Tracker|null $progress
+ */
+ public function run(
$input,
$progress = null
) {
@@ -30,7 +30,6 @@ public function run(
}
public function getDefaultCaption( $input ) {
- return "Writing file " . $input->path;
+ return 'Writing file ' . $input->path;
}
-
}
diff --git a/src/WordPress/Blueprints/Runtime/ProcessFailedException.php b/src/WordPress/Blueprints/Runtime/ProcessFailedException.php
index 5bd5909d..8a6bf161 100644
--- a/src/WordPress/Blueprints/Runtime/ProcessFailedException.php
+++ b/src/WordPress/Blueprints/Runtime/ProcessFailedException.php
@@ -16,7 +16,7 @@ class ProcessFailedException extends BlueprintException {
public function __construct( Process $process, Throwable $previous = null ) {
$this->process = $process;
parent::__construct(
- "Process `" . $process->getCommandLine() . "` failed with exit code " . $process->getExitCode() . " and the following stderr output: \n" . $process->getErrorOutput() . "\n" . $process->getOutput(),
+ 'Process `' . $process->getCommandLine() . '` failed with exit code ' . $process->getExitCode() . " and the following stderr output: \n" . $process->getErrorOutput() . "\n" . $process->getOutput(),
$process->getExitCode(),
$previous
);
@@ -25,5 +25,4 @@ public function __construct( Process $process, Throwable $previous = null ) {
public function getProcess(): Process {
return $this->process;
}
-
}
diff --git a/src/WordPress/Blueprints/Runtime/Runtime.php b/src/WordPress/Blueprints/Runtime/Runtime.php
index 011b3918..22e03579 100644
--- a/src/WordPress/Blueprints/Runtime/Runtime.php
+++ b/src/WordPress/Blueprints/Runtime/Runtime.php
@@ -16,7 +16,7 @@ public function __construct(
string $documentRoot
) {
$this->documentRoot = $documentRoot;
- $this->fs = new Filesystem();
+ $this->fs = new Filesystem();
if ( ! file_exists( $this->getDocumentRoot() ) ) {
$this->fs->mkdir( $this->getDocumentRoot() );
}
@@ -29,15 +29,15 @@ public function __construct(
// @TODO: should this class mediate network requests?
// @TODO: Move these filesystem operations to a separate class
- // Maybe ExecutionContext? Or a separate Filesystem class?
+ // Maybe ExecutionContext? Or a separate Filesystem class?
public function getDocumentRoot(): string {
return $this->documentRoot;
}
/**
- * @param string $path
- */
- public function resolvePath( $path ): string {
+ * @param string $path
+ */
+ public function resolvePath( $path ): string {
return Path::makeAbsolute( $path, $this->getDocumentRoot() );
}
@@ -50,7 +50,6 @@ public function withTemporaryDirectory( $callback ) {
} finally {
$this->fs->remove( $path );
}
-
}
public function withTemporaryFile( $callback, $suffix = null ) {
@@ -67,32 +66,32 @@ public function getTempRoot() {
// `/tmp` may be on another filesystem and we couldn't move files across filesystems
// without a slow recursive copy.
return join_paths( $this->getDocumentRoot(), '/tmp' );
-// return sys_get_temp_dir();
+ // return sys_get_temp_dir();
}
// @TODO: Move this to a separate class
- /**
- * @param mixed[]|null $env
- * @param float $timeout
- */
- public function evalPhpInSubProcess(
+ /**
+ * @param mixed[]|null $env
+ * @param float $timeout
+ */
+ public function evalPhpInSubProcess(
$code,
$env = null,
$input = null,
$timeout = 60
) {
return $this->runShellCommand(
- [
+ array(
'php',
'-r',
'?>' . $code,
- ],
+ ),
null,
array_merge(
- [
+ array(
'DOCROOT' => $this->getDocumentRoot(),
- ],
- $env ?? []
+ ),
+ $env ?? array()
),
$input,
$timeout
@@ -100,13 +99,13 @@ public function evalPhpInSubProcess(
}
// @TODO: Move this to a separate class
- /**
- * @param mixed[] $command
- * @param string|null $cwd
- * @param mixed[]|null $env
- * @param float $timeout
- */
- public function runShellCommand(
+ /**
+ * @param mixed[] $command
+ * @param string|null $cwd
+ * @param mixed[]|null $env
+ * @param float $timeout
+ */
+ public function runShellCommand(
$command,
$cwd = null,
$env = null,
@@ -130,12 +129,12 @@ public function runShellCommand(
}
/**
- * @param mixed[] $command
- * @param string|null $cwd
- * @param mixed[]|null $env
- * @param float $timeout
- */
- public function startProcess(
+ * @param mixed[] $command
+ * @param string|null $cwd
+ * @param mixed[]|null $env
+ * @param float $timeout
+ */
+ public function startProcess(
$command,
$cwd = null,
$env = null,
diff --git a/src/WordPress/Blueprints/Runtime/RuntimeInterface.php b/src/WordPress/Blueprints/Runtime/RuntimeInterface.php
index cab23cc5..0e3278e7 100644
--- a/src/WordPress/Blueprints/Runtime/RuntimeInterface.php
+++ b/src/WordPress/Blueprints/Runtime/RuntimeInterface.php
@@ -7,17 +7,16 @@
interface RuntimeInterface {
/**
- * @param mixed[] $command
- * @param string|null $cwd
- * @param mixed[]|null $env
- * @param float $timeout
- */
- public function startProcess(
+ * @param mixed[] $command
+ * @param string|null $cwd
+ * @param mixed[]|null $env
+ * @param float $timeout
+ */
+ public function startProcess(
$command,
$cwd = null,
$env = null,
$input = null,
$timeout = 60
): Process;
-
}
diff --git a/src/WordPress/Blueprints/bin/autogenerate_models.php b/src/WordPress/Blueprints/bin/autogenerate_models.php
index 6be4c267..26e6bf8f 100644
--- a/src/WordPress/Blueprints/bin/autogenerate_models.php
+++ b/src/WordPress/Blueprints/bin/autogenerate_models.php
@@ -25,19 +25,26 @@
throw new \RuntimeException( "Target directory $targetDirectory does not exist" );
}
-$jane = Jane::build( [
- 'reference' => '#',
- 'validation' => true,
- 'strict' => false,
-] );
-$registry = new Registry();
+$jane = Jane::build(
+ array(
+ 'reference' => '#',
+ 'validation' => true,
+ 'strict' => false,
+ )
+);
+$registry = new Registry();
$schemaLoader = new SchemaLoader();
-$registry->addSchema( $schemaLoader->resolve( $schemaPath, [
- 'namespace' => $targetNamespace,
- 'directory' => $targetDirectory,
- 'root-class' => 'Blueprint',
- 'strict' => false,
-] ) );
+$registry->addSchema(
+ $schemaLoader->resolve(
+ $schemaPath,
+ array(
+ 'namespace' => $targetNamespace,
+ 'directory' => $targetDirectory,
+ 'root-class' => 'Blueprint',
+ 'strict' => false,
+ )
+ )
+);
$context = $jane->createContext( $registry );
$jane->generate( $registry );
@@ -45,30 +52,30 @@
mkdir( $targetDirectory, 0777, true );
}
-$schema = $context->getRegistry()->getSchemas()[0];
+$schema = $context->getRegistry()->getSchemas()[0];
$janeClasses = $schema->getClasses();
// Every group of classes with a discriminator and oneOf should have
// an interface that all the classes in the group implement.
-$netteInterfaces = [];
-$shouldImplement = [];
-$interfaceImplementors = [];
+$netteInterfaces = array();
+$shouldImplement = array();
+$interfaceImplementors = array();
foreach ( $janeClasses as $ref => $class ) {
// If $ref ends with /([^/]+)/oneOf/\d, extract the first group
if ( 1 !== preg_match( '/\/([^\/]+)\/oneOf\/\d+$/', $ref, $matches ) ) {
continue;
}
- $interfaceName = $matches[1] . 'Interface';
- $shouldImplement[ $class->getName() ] = $interfaceName;
+ $interfaceName = $matches[1] . 'Interface';
+ $shouldImplement[ $class->getName() ] = $interfaceName;
$interfaceImplementors[ $interfaceName ][] = $class->getName();
if ( array_key_exists( $interfaceName, $netteInterfaces ) ) {
continue;
}
- $namespace = new PhpNamespace( $targetNamespace );
- $interface = $namespace->addInterface( $interfaceName );
+ $namespace = new PhpNamespace( $targetNamespace );
+ $interface = $namespace->addInterface( $interfaceName );
$netteInterfaces[ $interface->getName() ] = $interface;
}
@@ -78,9 +85,12 @@
*/
$modelInfoClass = ( new PhpNamespace( $targetNamespace ) )->addClass( 'ModelInfo' );
foreach ( $interfaceImplementors as $interfaceName => $implementors ) {
- $implementorsClassExpressions = array_map( function ($implementor) {
- return $implementor . '::class';
- }, $implementors );
+ $implementorsClassExpressions = array_map(
+ function ( $implementor ) {
+ return $implementor . '::class';
+ },
+ $implementors
+ );
$modelInfoClass->addMethod( 'get' . $interfaceName . 'Implementations' )
->setStatic( true )
->setReturnType( 'array' )
@@ -107,13 +117,16 @@
*
* For that, we'll need a map of replacements.
*/
-$unionReplacements = [];
+$unionReplacements = array();
foreach ( $interfaceImplementors as $interfaceName => $implementors ) {
$unionReplacements[ implode( '|', $implementors ) ] = $interfaceName;
- $arrayUnion = array_map( function ($implementor) {
- return $implementor . '[]';
- }, $implementors );
+ $arrayUnion = array_map(
+ function ( $implementor ) {
+ return $implementor . '[]';
+ },
+ $implementors
+ );
$unionReplacements[ implode( '|', $arrayUnion ) ] = $interfaceName . '[]';
}
@@ -130,24 +143,24 @@ function fixTypeHint( string $typeHint, array $replacements ): string {
* the PHP classes. However, the classes it generates are too opinionated.
* Let's convert them to Nette classes and customize them to our needs.
*/
-$typeHintMap = [];
-$netteClasses = [];
+$typeHintMap = array();
+$netteClasses = array();
/** @var ClassType[] $netteClasses */
foreach ( $janeClasses as $ref => $janeClass ) {
- $namespace = new PhpNamespace( $targetNamespace );
- $class = $namespace->addClass( $janeClass->getName() );
+ $namespace = new PhpNamespace( $targetNamespace );
+ $class = $namespace->addClass( $janeClass->getName() );
$hasInterface = isset( $shouldImplement[ $janeClass->getName() ] );
if ( $hasInterface ) {
$class->addImplement( $targetNamespace . '\\' . $shouldImplement[ $janeClass->getName() ] );
}
- $typeHintMap[ $janeClass->getName() ] = [];
+ $typeHintMap[ $janeClass->getName() ] = array();
foreach ( $janeClass->getProperties() as $janeProperty ) {
// Add the property to the class.
- $property = $class->addProperty( $janeProperty->getName() );
+ $property = $class->addProperty( $janeProperty->getName() );
$description = $janeProperty->getDescription();
- $typeHint = $janeProperty->getType()->getTypeHint( '' );
+ $typeHint = $janeProperty->getType()->getTypeHint( '' );
$docTypeHint = $janeProperty->getType()->getDocTypeHint( '' );
- if ( strpos($docTypeHint, $targetNamespace) !== false ) {
+ if ( strpos( $docTypeHint, $targetNamespace ) !== false ) {
// Jane prepends "\$namespace\Model\" to type hints, let's remove that.
$docTypeHint = str_replace( '\\' . $targetNamespace . '\\Model\\', '', $docTypeHint );
// Let's replace the lengthy union types with the interface types.
@@ -160,14 +173,14 @@ function fixTypeHint( string $typeHint, array $replacements ): string {
// fix that by moving the object types to the front.
$subTypes = explode( '|', $docTypeHint );
if ( count( $subTypes ) > 1 ) {
- $phpPrimitiveTypes = [ 'string', 'int', 'float', 'bool', 'array', 'object' ];
- $finalTypes = [];
+ $phpPrimitiveTypes = array( 'string', 'int', 'float', 'bool', 'array', 'object' );
+ $finalTypes = array();
foreach ( $phpPrimitiveTypes as $phpPrimitiveType ) {
if ( in_array( $phpPrimitiveType, $subTypes ) ) {
$finalTypes[] = $phpPrimitiveType;
}
}
- $finalTypes = array_merge( $finalTypes, array_diff( $subTypes, $phpPrimitiveTypes ) );
+ $finalTypes = array_merge( $finalTypes, array_diff( $subTypes, $phpPrimitiveTypes ) );
$docTypeHint = implode( '|', $finalTypes );
}
}
@@ -183,13 +196,15 @@ function fixTypeHint( string $typeHint, array $replacements ): string {
// Add a setter
$setter = $class->addMethod( 'set' . ucfirst( $janeProperty->getName() ) );
- $setterArg = $setter->addParameter( $janeProperty->getName() );
+ $setterArg = $setter->addParameter( $janeProperty->getName() );
$argTypeHint = $janeProperty->getType()->getTypeHint( $targetNamespace ) . '';
if ( $argTypeHint ) {
- if ( strpos($argTypeHint, '\\') !== false ) {
- $argTypeHint = $targetNamespace . '\\' . str_replace( '\\' . $targetNamespace . '\\Model\\',
- '',
- $argTypeHint );
+ if ( strpos( $argTypeHint, '\\' ) !== false ) {
+ $argTypeHint = $targetNamespace . '\\' . str_replace(
+ '\\' . $targetNamespace . '\\Model\\',
+ '',
+ $argTypeHint
+ );
}
$setterArg->setType( $argTypeHint );
}
@@ -218,7 +233,7 @@ function fixTypeHint( string $typeHint, array $replacements ): string {
// value of all class properties.
$property->setValue( $schema->getDefault() );
} elseif ( $schema->getType() === 'array' ) {
- $property->setValue( [] );
+ $property->setValue( array() );
}
}
}
@@ -228,7 +243,7 @@ function fixTypeHint( string $typeHint, array $replacements ): string {
/**
* We're finished, yay! Let's write the generated classes to the disk.
*/
-$netteOutput = array_merge( $netteInterfaces, $netteClasses, [ $modelInfoClass ] );
+$netteOutput = array_merge( $netteInterfaces, $netteClasses, array( $modelInfoClass ) );
foreach ( glob( $targetDirectory . '/*.php' ) as $file ) {
unlink( $file );
}
@@ -238,4 +253,4 @@ function fixTypeHint( string $typeHint, array $replacements ): string {
file_put_contents( $filename, "getNamespace() );
}
-echo "Generated " . count( $netteOutput ) . " classes in $targetDirectory\n";
+echo 'Generated ' . count( $netteOutput ) . " classes in $targetDirectory\n";
diff --git a/src/WordPress/Blueprints/functions.php b/src/WordPress/Blueprints/functions.php
index bdc97850..83d233bc 100644
--- a/src/WordPress/Blueprints/functions.php
+++ b/src/WordPress/Blueprints/functions.php
@@ -7,19 +7,19 @@
use Symfony\Component\Filesystem\Exception\IOException;
use WordPress\Blueprints\Runtime\Runtime;
-function run_blueprint( $json, $options = [] ) {
+function run_blueprint( $json, $options = array() ) {
- $environment = $options['environment'] ?? ContainerBuilder::ENVIRONMENT_NATIVE;
- $documentRoot = $options['documentRoot'] ?? '/wordpress';
+ $environment = $options['environment'] ?? ContainerBuilder::ENVIRONMENT_NATIVE;
+ $documentRoot = $options['documentRoot'] ?? '/wordpress';
$progressSubscriber = $options['progressSubscriber'] ?? null;
- $progressType = $options['progressType'] ?? 'all';
+ $progressType = $options['progressType'] ?? 'all';
$c = ( new ContainerBuilder() )->build(
$environment,
new Runtime( $documentRoot )
);
- $engine = $c['blueprint.engine'];
+ $engine = $c['blueprint.engine'];
$compiledBlueprint = $engine->parseAndCompile( $json );
/** @var $engine Engine */
@@ -35,24 +35,29 @@ function run_blueprint( $json, $options = [] ) {
}
function list_files( string $path, $omitDotFiles = false ): array {
- return array_values( array_filter( scandir( $path ), function ( $file ) use ( $omitDotFiles ) {
- if ( $omitDotFiles && $file[0] === '.' ) {
- return false;
- }
+ return array_values(
+ array_filter(
+ scandir( $path ),
+ function ( $file ) use ( $omitDotFiles ) {
+ if ( $omitDotFiles && $file[0] === '.' ) {
+ return false;
+ }
- return '.' !== $file && '..' !== $file;
- } ) );
+ return '.' !== $file && '..' !== $file;
+ }
+ )
+ );
}
function move_files_from_directory_to_directory( string $from, string $to ) {
- $fs = new Filesystem();
+ $fs = new Filesystem();
$files = scandir( $from );
foreach ( $files as $file ) {
if ( '.' === $file || '..' === $file ) {
continue;
}
$fromPath = Path::canonicalize( $from . '/' . $file );
- $toPath = Path::canonicalize( $to . '/' . $file );
+ $toPath = Path::canonicalize( $to . '/' . $file );
try {
$fs->rename( $fromPath, $toPath );
} catch ( IOException $exception ) {
diff --git a/src/WordPress/DataSource/BaseDataSource.php b/src/WordPress/DataSource/BaseDataSource.php
index 8407aaf3..aea9bf42 100644
--- a/src/WordPress/DataSource/BaseDataSource.php
+++ b/src/WordPress/DataSource/BaseDataSource.php
@@ -13,5 +13,4 @@ public function __construct() {
}
abstract public function stream( $resourceIdentifier );
-
}
diff --git a/src/WordPress/DataSource/DataSourceProgressEvent.php b/src/WordPress/DataSource/DataSourceProgressEvent.php
index b444d112..b0704740 100644
--- a/src/WordPress/DataSource/DataSourceProgressEvent.php
+++ b/src/WordPress/DataSource/DataSourceProgressEvent.php
@@ -6,24 +6,23 @@
class DataSourceProgressEvent extends Event {
/**
- * @var string
- */
- public $url;
- /**
- * @var int
- */
- public $downloadedBytes;
- /**
- * @var int|null
- */
- public $totalBytes;
- /**
- * @param int|null $totalBytes
- */
- public function __construct(string $url, int $downloadedBytes, $totalBytes)
- {
- $this->url = $url;
- $this->downloadedBytes = $downloadedBytes;
- $this->totalBytes = $totalBytes;
- }
+ * @var string
+ */
+ public $url;
+ /**
+ * @var int
+ */
+ public $downloadedBytes;
+ /**
+ * @var int|null
+ */
+ public $totalBytes;
+ /**
+ * @param int|null $totalBytes
+ */
+ public function __construct( string $url, int $downloadedBytes, $totalBytes ) {
+ $this->url = $url;
+ $this->downloadedBytes = $downloadedBytes;
+ $this->totalBytes = $totalBytes;
+ }
}
diff --git a/src/WordPress/DataSource/PlaygroundFetchSource.php b/src/WordPress/DataSource/PlaygroundFetchSource.php
index f18089bf..ba2b458e 100644
--- a/src/WordPress/DataSource/PlaygroundFetchSource.php
+++ b/src/WordPress/DataSource/PlaygroundFetchSource.php
@@ -7,13 +7,16 @@
class PlaygroundFetchSource extends BaseDataSource {
- public $proc_handles = [];
+ public $proc_handles = array();
public function stream( $resourceIdentifier ) {
- $url = $resourceIdentifier;
+ $url = $resourceIdentifier;
$proc_handle = proc_open(
- is_array([ 'fetch', $url, ]) ? implode(' ', array_map('escapeshellarg', [ 'fetch', $url, ])) : [ 'fetch', $url, ],
- [ 1 => [ 'pipe', 'w' ], 2 => [ 'pipe', 'w' ] ],
+ is_array( array( 'fetch', $url ) ) ? implode( ' ', array_map( 'escapeshellarg', array( 'fetch', $url ) ) ) : array( 'fetch', $url ),
+ array(
+ 1 => array( 'pipe', 'w' ),
+ 2 => array( 'pipe', 'w' ),
+ ),
$pipes
);
// This prevents the process handle from getting garbage collected and
@@ -23,13 +26,11 @@ public function stream( $resourceIdentifier ) {
// Without this line, we get the following error:
// PHP Fatal error: Uncaught TypeError: stream_copy_to_stream(): supplied resource is not a valid stream resource i
// var_dump()–ing first says
- // resource(457) of type (stream)
+ // resource(457) of type (stream)
// but then it says
- // resource(457) of type (Unknown)
+ // resource(457) of type (Unknown)
$this->proc_handles[] = $proc_handle;
return $pipes[1];
}
-
}
-
diff --git a/src/WordPress/DataSource/UrlSource.php b/src/WordPress/DataSource/UrlSource.php
index d02fe310..9b9ebf4a 100644
--- a/src/WordPress/DataSource/UrlSource.php
+++ b/src/WordPress/DataSource/UrlSource.php
@@ -18,16 +18,20 @@ public function __construct(
CacheInterface $cache
) {
$this->client = $client;
- $this->cache = $cache;
+ $this->cache = $cache;
parent::__construct();
- $client->set_progress_callback( function ( Request $request, $downloaded, $total ) {
- $this->events->dispatch( new DataSourceProgressEvent(
- $request->url,
- $downloaded,
- $total
- ) );
- } );
+ $client->set_progress_callback(
+ function ( Request $request, $downloaded, $total ) {
+ $this->events->dispatch(
+ new DataSourceProgressEvent(
+ $request->url,
+ $downloaded,
+ $total
+ )
+ );
+ }
+ );
}
public function stream( $resourceIdentifier ) {
@@ -36,13 +40,15 @@ public function stream( $resourceIdentifier ) {
if ( false && $this->cache->has( $url ) ) {
// Return a stream resource.
// @TODO: Stream directly from the cache
- $cached = $this->cache->get( $url );
+ $cached = $this->cache->get( $url );
$data_size = strlen( $cached );
- $this->events->dispatch( new DataSourceProgressEvent(
- $url,
- $data_size,
- $data_size
- ) );
+ $this->events->dispatch(
+ new DataSourceProgressEvent(
+ $url,
+ $data_size,
+ $data_size
+ )
+ );
$stream = fopen( 'php://memory', 'r+' );
fwrite( $stream, $cached );
rewind( $stream );
@@ -57,11 +63,11 @@ public function stream( $resourceIdentifier ) {
// Cache
$onChunk = function ( $chunk ) use ( $url, $stream ) {
// Handle response caching
- static $bufferedChunks = [];
- $bufferedChunks[] = $chunk;
+ static $bufferedChunks = array();
+ $bufferedChunks[] = $chunk;
if ( feof( $stream ) ) {
$this->cache->set( $url, implode( '', $bufferedChunks ) );
- $bufferedChunks = [];
+ $bufferedChunks = array();
}
};
@@ -72,5 +78,4 @@ public function stream( $resourceIdentifier ) {
)
);
}
-
}
diff --git a/src/WordPress/JsonMapper/JsonMapper.php b/src/WordPress/JsonMapper/JsonMapper.php
index 86b54a9e..b8f5d8dd 100644
--- a/src/WordPress/JsonMapper/JsonMapper.php
+++ b/src/WordPress/JsonMapper/JsonMapper.php
@@ -38,7 +38,7 @@ public function __construct( array $custom_factories = array() ) {
* Creates an instance of $class_name based on parsed JSON data.
*
* @param stdClass $json The JSON object containing the data to populate the new object with.
- * @param string $class_name The fully qualified name of the class to create an instance of.
+ * @param string $class_name The fully qualified name of the class to create an instance of.
*
* @return object An instance of the class specified by $class_name, populated with data from $json.
* @throws ReflectionException If the class does not exist and the instance is being created manually.
@@ -55,7 +55,7 @@ public function hydrate( $json, $class_name ) {
* Populates an instance of $class_name created via ReflectionClass::newInstance.
*
* @param stdClass $json The JSON object containing the data to populate the new object with.
- * @param string $class_name The fully qualified name of the class to create an instance of.
+ * @param string $class_name The fully qualified name of the class to create an instance of.
*
* @return object An instance of the class specified by $class_name, populated with data from $json.
* @throws ReflectionException If the class does not exist.
@@ -64,8 +64,8 @@ public function hydrate( $json, $class_name ) {
*/
private function create_and_hydrate( string $class_name, stdClass $json ) {
$reflection_class = new ReflectionClass( $class_name );
- $object = $reflection_class->newInstance();
- $property_map = PropertyParser::compute_property_map( $reflection_class );
+ $object = $reflection_class->newInstance();
+ $property_map = PropertyParser::compute_property_map( $reflection_class );
foreach ( (array) $json as $key => $value ) {
// Ignore null data in JSON.
@@ -91,7 +91,7 @@ private function create_and_hydrate( string $class_name, stdClass $json ) {
* Warning - array depths are not fully checked during mapping.
*
* @param Property $property The Property object with a list of possible types the value could be mapped to.
- * @param mixed $value The value from the JSON object.
+ * @param mixed $value The value from the JSON object.
*
* @return mixed The mapped value, of the type specified by the Property.
* @throws JsonMapperException If the Property type is not supported, or if the value cannot be mapped to the Property type.
@@ -104,8 +104,8 @@ private function map_value( Property $property, $value ) {
foreach ( $property->property_types as $property_type ) {
$array_dimensions = PropertyParser::get_array_dimensions( $property_type );
- $property_type = PropertyParser::without_dimensions( $property_type );
- $type_is_array = 'array' === $property_type || $array_dimensions > 0;
+ $property_type = PropertyParser::without_dimensions( $property_type );
+ $type_is_array = 'array' === $property_type || $array_dimensions > 0;
if ( is_array( $value ) && $type_is_array && count( $value ) === 0 ) {
return array();
@@ -146,7 +146,7 @@ private function set_value( $object, Property $property, $value ) {
// Use a setter if it exists.
$method_name = 'set' . ucfirst( $property->name );
if ( method_exists( $object, $method_name ) ) {
- $method = new ReflectionMethod( $object, $method_name );
+ $method = new ReflectionMethod( $object, $method_name );
$parameters = $method->getParameters();
if ( is_array( $value ) && count( $parameters ) === 1 && $parameters[0]->isVariadic() ) {
@@ -171,7 +171,6 @@ private function set_value( $object, Property $property, $value ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
"Property: '" . get_class( $object ) . "::$property->name' is non-public and no setter method was found."
);
-
}
private function is_scalar_recursive( $value, string $property_type ) {
@@ -311,7 +310,7 @@ private function has_factory( string $class_name ): bool {
}
private function run_factory( string $class_name, $params ) {
- return $this->factories[$this->sanitize_class_name( $class_name )]( $params );
+ return $this->factories[ $this->sanitize_class_name( $class_name ) ]( $params );
}
private function add_factory( string $class_name, callable $factory ) {
diff --git a/src/WordPress/JsonMapper/JsonMapperException.php b/src/WordPress/JsonMapper/JsonMapperException.php
index f80b1350..25e87038 100644
--- a/src/WordPress/JsonMapper/JsonMapperException.php
+++ b/src/WordPress/JsonMapper/JsonMapperException.php
@@ -4,4 +4,4 @@
use Exception;
-class JsonMapperException extends Exception {}
\ No newline at end of file
+class JsonMapperException extends Exception {}
diff --git a/src/WordPress/JsonMapper/PropertyParser.php b/src/WordPress/JsonMapper/PropertyParser.php
index e200c9e0..d6b9c9aa 100644
--- a/src/WordPress/JsonMapper/PropertyParser.php
+++ b/src/WordPress/JsonMapper/PropertyParser.php
@@ -24,9 +24,9 @@ public static function without_dimensions( $type ) {
public static function get_array_dimensions( $type ) {
$dimension = 0;
- $at = strlen( $type );
+ $at = strlen( $type );
while ( substr( $type, $at - 2, 2 ) === '[]' ) {
- $dimension ++;
+ ++$dimension;
$at -= 2;
}
@@ -108,7 +108,7 @@ private static function parse_property_types( ReflectionProperty $reflection_pro
$var = null;
if ( preg_match_all( self::DOC_BLOCK_REGEX, $doc_block, $matches ) ) {
- for ( $x = 0, $max = count( $matches[0] ); $x < $max; $x ++ ) {
+ for ( $x = 0, $max = count( $matches[0] ); $x < $max; $x++ ) {
if ( 'var' === $matches['name'][ $x ] ) {
$var = $matches['value'][ $x ];
}
@@ -126,11 +126,11 @@ private static function parse_property_types( ReflectionProperty $reflection_pro
continue;
}
$array_brackets = '';
- $type = $original_property_type;
+ $type = $original_property_type;
preg_match( '/(\[\])+$/', $type, $matches );
if ( ! empty( $matches ) ) {
$array_brackets = $matches[0];
- $type = substr( $type, 0, - strlen( $array_brackets ) );
+ $type = substr( $type, 0, - strlen( $array_brackets ) );
}
if ( Utils::is_type_scalar( $type ) || $type === 'array' || $type === 'object' || $type === 'mixed' ) {
@@ -143,7 +143,7 @@ private static function parse_property_types( ReflectionProperty $reflection_pro
$property_types[] = '\\' . $type . $array_brackets;
continue;
}
-
+
if ( class_exists( $type ) ) {
$property_types[] = $type . $array_brackets;
continue;
@@ -176,11 +176,11 @@ class_exists( $namespaced_type )
* @return ReflectionProperty[] array of properties.
*/
private static function get_properties( ReflectionClass $reflection_class ) {
- $properties = $reflection_class->getProperties();
+ $properties = $reflection_class->getProperties();
$reflected_parent = $reflection_class->getParentClass();
while ( false !== $reflected_parent ) {
- $properties = array_merge( $properties, $reflected_parent->getProperties() );
+ $properties = array_merge( $properties, $reflected_parent->getProperties() );
$reflected_parent = $reflected_parent->getParentClass();
}
diff --git a/src/WordPress/JsonMapper/Utils.php b/src/WordPress/JsonMapper/Utils.php
index 7086bcdd..01079c97 100644
--- a/src/WordPress/JsonMapper/Utils.php
+++ b/src/WordPress/JsonMapper/Utils.php
@@ -4,13 +4,12 @@
class Utils {
- static public $scalar_types = array( 'string', 'bool', 'boolean', 'int', 'integer', 'double', 'float' );
+ public static $scalar_types = array( 'string', 'bool', 'boolean', 'int', 'integer', 'double', 'float' );
/**
- * @param string $type
- */
- static public function is_type_scalar( $type ) {
+ * @param string $type
+ */
+ public static function is_type_scalar( $type ) {
return in_array( $type, self::$scalar_types, true );
}
-
}
diff --git a/src/WordPress/Streams/StreamPeekerData.php b/src/WordPress/Streams/StreamPeekerData.php
index a1b355a4..08a51f18 100644
--- a/src/WordPress/Streams/StreamPeekerData.php
+++ b/src/WordPress/Streams/StreamPeekerData.php
@@ -5,12 +5,12 @@
class StreamPeekerData extends VanillaStreamWrapperData {
public $fp;
- public $onChunk = null;
- public $onClose = null;
- public function __construct( $fp, $onChunk = null, $onClose = null ) {
- $this->fp = $fp;
- $this->onChunk = $onChunk;
- $this->onClose = $onClose;
- parent::__construct( $fp );
+ public $onChunk = null;
+ public $onClose = null;
+ public function __construct( $fp, $onChunk = null, $onClose = null ) {
+ $this->fp = $fp;
+ $this->onChunk = $onChunk;
+ $this->onClose = $onClose;
+ parent::__construct( $fp );
}
}
diff --git a/src/WordPress/Streams/StreamPeekerWrapper.php b/src/WordPress/Streams/StreamPeekerWrapper.php
index 6bfb6f4b..2b83aca2 100644
--- a/src/WordPress/Streams/StreamPeekerWrapper.php
+++ b/src/WordPress/Streams/StreamPeekerWrapper.php
@@ -42,7 +42,7 @@ public function stream_open( $path, $mode, $options, &$opened_path ) {
// Reads from the stream
public function stream_read( $count ) {
- $ret = fread( $this->stream, $count );
+ $ret = fread( $this->stream, $count );
$this->position += strlen( $ret );
$onChunk = $this->onChunk;
@@ -53,7 +53,7 @@ public function stream_read( $count ) {
// Writes to the stream
public function stream_write( $data ) {
- $written = fwrite( $this->stream, $data );
+ $written = fwrite( $this->stream, $data );
$this->position += $written;
return $written;
@@ -70,5 +70,4 @@ public function stream_close() {
public function stream_tell() {
return $this->position;
}
-
}
diff --git a/src/WordPress/Streams/StreamWrapperInterface.php b/src/WordPress/Streams/StreamWrapperInterface.php
index 9bc9d752..e5ceeec5 100644
--- a/src/WordPress/Streams/StreamWrapperInterface.php
+++ b/src/WordPress/Streams/StreamWrapperInterface.php
@@ -7,8 +7,8 @@ interface StreamWrapperInterface {
/**
* Sets an option on the stream
*
- * @param int $option
- * @param int $arg1
+ * @param int $option
+ * @param int $arg1
* @param int|null $arg2
*
* @return bool
@@ -21,9 +21,9 @@ public function stream_set_option( $option, $arg1, $arg2 = null ): bool;
public function stream_open( $path, $mode, $options, &$opened_path );
/**
- * @param int $cast_as
- */
- public function stream_cast( $cast_as );
+ * @param int $cast_as
+ */
+ public function stream_cast( $cast_as );
/**
* Reads from the stream
diff --git a/src/WordPress/Streams/VanillaStreamWrapper.php b/src/WordPress/Streams/VanillaStreamWrapper.php
index 810af238..0cc636df 100644
--- a/src/WordPress/Streams/VanillaStreamWrapper.php
+++ b/src/WordPress/Streams/VanillaStreamWrapper.php
@@ -12,21 +12,23 @@ class VanillaStreamWrapper implements StreamWrapperInterface {
const SCHEME = 'vanilla';
/**
- * @param \WordPress\Streams\VanillaStreamWrapperData $data
- */
- static public function create_resource( $data ) {
+ * @param \WordPress\Streams\VanillaStreamWrapperData $data
+ */
+ public static function create_resource( $data ) {
static::register();
- $context = stream_context_create( [
- static::SCHEME => [
- 'wrapper_data' => $data,
- ],
- ] );
+ $context = stream_context_create(
+ array(
+ static::SCHEME => array(
+ 'wrapper_data' => $data,
+ ),
+ )
+ );
return fopen( static::SCHEME . '://', 'r', false, $context );
}
- static public function register() {
+ public static function register() {
if ( in_array( static::SCHEME, stream_get_wrappers() ) ) {
return;
}
@@ -36,17 +38,17 @@ static public function register() {
}
}
- static public function unregister() {
+ public static function unregister() {
stream_wrapper_unregister( 'async' );
}
/**
- * @param int $option
- * @param int $arg1
- * @param int|null $arg2
- */
- public function stream_set_option( $option, $arg1, $arg2 = null ): bool {
+ * @param int $option
+ * @param int $arg1
+ * @param int|null $arg2
+ */
+ public function stream_set_option( $option, $arg1, $arg2 = null ): bool {
if ( \STREAM_OPTION_BLOCKING === $option ) {
return stream_set_blocking( $this->stream, (bool) $arg1 );
} elseif ( \STREAM_OPTION_READ_TIMEOUT === $option ) {
@@ -73,9 +75,9 @@ public function stream_open( $path, $mode, $options, &$opened_path ) {
}
/**
- * @param int $cast_as
- */
- public function stream_cast( $cast_as ) {
+ * @param int $cast_as
+ */
+ public function stream_cast( $cast_as ) {
return $this->stream;
}
@@ -104,6 +106,6 @@ public function stream_seek( $offset, $whence ) {
}
public function stream_stat() {
- return [];
+ return array();
}
}
diff --git a/src/WordPress/Util/ArrayPairIterator.php b/src/WordPress/Util/ArrayPairIterator.php
index acef8157..8d8a64a9 100644
--- a/src/WordPress/Util/ArrayPairIterator.php
+++ b/src/WordPress/Util/ArrayPairIterator.php
@@ -22,7 +22,7 @@ public function key() {
#[\ReturnTypeWillChange]
public function next() {
- ++ $this->position;
+ ++$this->position;
}
#[\ReturnTypeWillChange]
diff --git a/src/WordPress/Util/Map.php b/src/WordPress/Util/Map.php
index 65ff8558..0253a19e 100644
--- a/src/WordPress/Util/Map.php
+++ b/src/WordPress/Util/Map.php
@@ -7,7 +7,7 @@
use Traversable;
class Map implements ArrayAccess, IteratorAggregate {
- private $pairs = [];
+ private $pairs = array();
public function __construct() {
}
@@ -31,18 +31,18 @@ public function offsetGet( $offset ) {
}
// TODO Evaluate waring: 'ext-json' is missing in composer.json
- throw new \Exception( "Stream for resource " . json_encode( $offset ) . " not found" );
+ throw new \Exception( 'Stream for resource ' . json_encode( $offset ) . ' not found' );
}
public function offsetSet( $offset, $value ) {
foreach ( $this->pairs as $k => $pair ) {
if ( $pair[0] === $offset ) {
- $this->pairs[ $k ] = [ $offset, $value ];
+ $this->pairs[ $k ] = array( $offset, $value );
return;
}
}
- $this->pairs[] = [ $offset, $value ];
+ $this->pairs[] = array( $offset, $value );
}
public function offsetUnset( $offset ) {
diff --git a/src/WordPress/Zip/ZipCentralDirectoryEntry.php b/src/WordPress/Zip/ZipCentralDirectoryEntry.php
index 807d9260..3c2f2503 100644
--- a/src/WordPress/Zip/ZipCentralDirectoryEntry.php
+++ b/src/WordPress/Zip/ZipCentralDirectoryEntry.php
@@ -42,24 +42,24 @@ public function __construct(
string $extra,
string $fileComment
) {
- $this->fileComment = $fileComment;
- $this->extra = $extra;
- $this->path = $path;
- $this->lastByteAt = $lastByteAt;
+ $this->fileComment = $fileComment;
+ $this->extra = $extra;
+ $this->path = $path;
+ $this->lastByteAt = $lastByteAt;
$this->externalAttributes = $externalAttributes;
$this->internalAttributes = $internalAttributes;
- $this->diskNumber = $diskNumber;
- $this->uncompressedSize = $uncompressedSize;
- $this->compressedSize = $compressedSize;
- $this->crc = $crc;
- $this->lastModifiedDate = $lastModifiedDate;
- $this->lastModifiedTime = $lastModifiedTime;
- $this->compressionMethod = $compressionMethod;
- $this->generalPurpose = $generalPurpose;
- $this->versionNeeded = $versionNeeded;
- $this->versionCreated = $versionCreated;
- $this->firstByteAt = $firstByteAt;
- $this->isDirectory = $this->path[ - 1 ] === '/';
+ $this->diskNumber = $diskNumber;
+ $this->uncompressedSize = $uncompressedSize;
+ $this->compressedSize = $compressedSize;
+ $this->crc = $crc;
+ $this->lastModifiedDate = $lastModifiedDate;
+ $this->lastModifiedTime = $lastModifiedTime;
+ $this->compressionMethod = $compressionMethod;
+ $this->generalPurpose = $generalPurpose;
+ $this->versionNeeded = $versionNeeded;
+ $this->versionCreated = $versionCreated;
+ $this->firstByteAt = $firstByteAt;
+ $this->isDirectory = $this->path[- 1] === '/';
}
public function isFileEntry() {
diff --git a/src/WordPress/Zip/ZipEndCentralDirectoryEntry.php b/src/WordPress/Zip/ZipEndCentralDirectoryEntry.php
index d71a2365..632f41db 100644
--- a/src/WordPress/Zip/ZipEndCentralDirectoryEntry.php
+++ b/src/WordPress/Zip/ZipEndCentralDirectoryEntry.php
@@ -5,33 +5,33 @@
class ZipEndCentralDirectoryEntry {
/**
- * @var int
- */
- public $diskNumber;
+ * @var int
+ */
+ public $diskNumber;
/**
- * @var int
- */
- public $centralDirectoryStartDisk;
+ * @var int
+ */
+ public $centralDirectoryStartDisk;
/**
- * @var int
- */
- public $numberCentralDirectoryRecordsOnThisDisk;
+ * @var int
+ */
+ public $numberCentralDirectoryRecordsOnThisDisk;
/**
- * @var int
- */
- public $numberCentralDirectoryRecords;
+ * @var int
+ */
+ public $numberCentralDirectoryRecords;
/**
- * @var int
- */
- public $centralDirectorySize;
+ * @var int
+ */
+ public $centralDirectorySize;
/**
- * @var int
- */
- public $centralDirectoryOffset;
+ * @var int
+ */
+ public $centralDirectoryOffset;
/**
- * @var string
- */
- public $comment;
+ * @var string
+ */
+ public $comment;
public function __construct(
int $diskNumber,
diff --git a/src/WordPress/Zip/ZipFileEntry.php b/src/WordPress/Zip/ZipFileEntry.php
index 088a525d..6536b968 100644
--- a/src/WordPress/Zip/ZipFileEntry.php
+++ b/src/WordPress/Zip/ZipFileEntry.php
@@ -4,53 +4,53 @@
class ZipFileEntry {
/**
- * @var bool
- */
- public $isDirectory;
+ * @var bool
+ */
+ public $isDirectory;
/**
- * @var int
- */
- public $version;
+ * @var int
+ */
+ public $version;
/**
- * @var int
- */
- public $generalPurpose;
+ * @var int
+ */
+ public $generalPurpose;
/**
- * @var int
- */
- public $compressionMethod;
+ * @var int
+ */
+ public $compressionMethod;
/**
- * @var int
- */
- public $lastModifiedTime;
+ * @var int
+ */
+ public $lastModifiedTime;
/**
- * @var int
- */
- public $lastModifiedDate;
+ * @var int
+ */
+ public $lastModifiedDate;
/**
- * @var int
- */
- public $crc;
+ * @var int
+ */
+ public $crc;
/**
- * @var int
- */
- public $compressedSize;
+ * @var int
+ */
+ public $compressedSize;
/**
- * @var int
- */
- public $uncompressedSize;
+ * @var int
+ */
+ public $uncompressedSize;
/**
- * @var string
- */
- public $path;
+ * @var string
+ */
+ public $path;
/**
- * @var string
- */
- public $extra;
+ * @var string
+ */
+ public $extra;
/**
- * @var string
- */
- public $bytes;
+ * @var string
+ */
+ public $bytes;
public function __construct(
int $version,
diff --git a/src/WordPress/Zip/ZipStreamReader.php b/src/WordPress/Zip/ZipStreamReader.php
index af3cca38..daf087b5 100644
--- a/src/WordPress/Zip/ZipStreamReader.php
+++ b/src/WordPress/Zip/ZipStreamReader.php
@@ -4,17 +4,17 @@
class ZipStreamReader {
- const SIGNATURE_FILE = 0x04034b50;
- const SIGNATURE_CENTRAL_DIRECTORY = 0x02014b50;
+ const SIGNATURE_FILE = 0x04034b50;
+ const SIGNATURE_CENTRAL_DIRECTORY = 0x02014b50;
const SIGNATURE_CENTRAL_DIRECTORY_END = 0x06054b50;
- const COMPRESSION_DEFLATE = 8;
+ const COMPRESSION_DEFLATE = 8;
/**
* Reads the next zip entry from a stream of zip file bytes.
*
* @param resource $fp A stream of zip file bytes.
*/
- static public function readEntry( $fp ) {
+ public static function readEntry( $fp ) {
$signature = static::read_bytes( $fp, 4 );
if ( $signature === false ) {
return null;
@@ -56,11 +56,13 @@ static public function readEntry( $fp ) {
*
* @param resource $stream
*/
- static protected function readFileEntry( $stream ): ZipFileEntry {
- $data = self::read_bytes( $stream, 26 );
- $data = unpack( 'vversionNeeded/vgeneralPurpose/vcompressionMethod/vlastModifiedTime/vlastModifiedDate/Vcrc/VcompressedSize/VuncompressedSize/vpathLength/vextraLength',
- $data );
- $path = self::read_bytes( $stream, $data['pathLength'] );
+ protected static function readFileEntry( $stream ): ZipFileEntry {
+ $data = self::read_bytes( $stream, 26 );
+ $data = unpack(
+ 'vversionNeeded/vgeneralPurpose/vcompressionMethod/vlastModifiedTime/vlastModifiedDate/Vcrc/VcompressedSize/VuncompressedSize/vpathLength/vextraLength',
+ $data
+ );
+ $path = self::read_bytes( $stream, $data['pathLength'] );
$extra = self::read_bytes( $stream, $data['extraLength'] );
$bytes = self::read_bytes( $stream, $data['compressedSize'] );
@@ -118,12 +120,14 @@ static protected function readFileEntry( $stream ): ZipFileEntry {
*
* @param resource stream
*/
- static protected function readCentralDirectoryEntry( $stream ): ZipCentralDirectoryEntry {
- $data = static::read_bytes( $stream, 42 );
- $data = unpack( 'vversionCreated/vversionNeeded/vgeneralPurpose/vcompressionMethod/vlastModifiedTime/vlastModifiedDate/Vcrc/VcompressedSize/VuncompressedSize/vpathLength/vextraLength/vfileCommentLength/vdiskNumber/vinternalAttributes/VexternalAttributes/VfirstByteAt',
- $data );
- $path = static::read_bytes( $stream, $data['pathLength'] );
- $extra = static::read_bytes( $stream, $data['extraLength'] );
+ protected static function readCentralDirectoryEntry( $stream ): ZipCentralDirectoryEntry {
+ $data = static::read_bytes( $stream, 42 );
+ $data = unpack(
+ 'vversionCreated/vversionNeeded/vgeneralPurpose/vcompressionMethod/vlastModifiedTime/vlastModifiedDate/Vcrc/VcompressedSize/VuncompressedSize/vpathLength/vextraLength/vfileCommentLength/vdiskNumber/vinternalAttributes/VexternalAttributes/VfirstByteAt',
+ $data
+ );
+ $path = static::read_bytes( $stream, $data['pathLength'] );
+ $extra = static::read_bytes( $stream, $data['extraLength'] );
$fileComment = static::read_bytes( $stream, $data['fileCommentLength'] );
return new ZipCentralDirectoryEntry(
@@ -167,10 +171,12 @@ static protected function readCentralDirectoryEntry( $stream ): ZipCentralDirect
*
* @param resource $stream
*/
- static protected function readEndCentralDirectoryEntry( $stream ): ZipEndCentralDirectoryEntry {
+ protected static function readEndCentralDirectoryEntry( $stream ): ZipEndCentralDirectoryEntry {
$data = static::read_bytes( $stream, 18 );
- $data = unpack( 'vdiskNumber/vcentralDirectoryStartDisk/vnumberCentralDirectoryRecordsOnThisDisk/vnumberCentralDirectoryRecords/VcentralDirectorySize/VcentralDirectoryOffset/vcommentLength',
- $data );
+ $data = unpack(
+ 'vdiskNumber/vcentralDirectoryStartDisk/vnumberCentralDirectoryRecordsOnThisDisk/vnumberCentralDirectoryRecords/VcentralDirectorySize/VcentralDirectoryOffset/vcommentLength',
+ $data
+ );
return new ZipEndCentralDirectoryEntry(
$data['diskNumber'],
@@ -192,12 +198,12 @@ static protected function readEndCentralDirectoryEntry( $stream ): ZipEndCentral
*
* @return false|string
*/
- static protected function read_bytes( $stream, $length ) {
+ protected static function read_bytes( $stream, $length ) {
if ( $length === 0 ) {
return '';
}
- $data = '';
+ $data = '';
$remaining_length = $length;
while ( $remaining_length > 0 ) {
$chunk = fread( $stream, $remaining_length );
@@ -205,10 +211,9 @@ static protected function read_bytes( $stream, $length ) {
return strlen( $data ) ? $data : false;
}
$remaining_length -= strlen( $chunk );
- $data .= $chunk;
+ $data .= $chunk;
}
return $data;
}
-
}
diff --git a/src/WordPress/Zip/functions.php b/src/WordPress/Zip/functions.php
index eaa84fcc..4f02a0f2 100644
--- a/src/WordPress/Zip/functions.php
+++ b/src/WordPress/Zip/functions.php
@@ -14,7 +14,7 @@ function zip_extract_to( $fp, $to_path ) {
continue;
}
- $path = Path::canonicalize( $to_path . '/' . $entry->path );
+ $path = Path::canonicalize( $to_path . '/' . $entry->path );
$parent = Path::getDirectory( $path );
if ( ! is_dir( $parent ) ) {
mkdir( $parent, 0777, true );
diff --git a/src/opis/json-schema/autoload.php b/src/opis/json-schema/autoload.php
index 649fab8c..c408fef7 100644
--- a/src/opis/json-schema/autoload.php
+++ b/src/opis/json-schema/autoload.php
@@ -1,23 +1,25 @@
false,
- 'allowFormats' => true,
- 'allowMappers' => false,
- 'allowTemplates' => false,
- 'allowGlobals' => false,
- 'allowDefaults' => false,
- 'allowSlots' => false,
- 'allowKeywordValidators' => false,
- 'allowPragmas' => false,
- 'allowDataKeyword' => false,
- 'allowKeywordsAlongsideRef' => false,
- 'allowUnevaluated' => true,
- 'allowRelativeJsonPointerInRef' => false,
- 'allowExclusiveMinMaxAsBool' => false,
- 'keepDependenciesKeyword' => false,
- 'keepAdditionalItemsKeyword' => false,
- ];
+class CompliantValidator extends Validator {
- public function __construct($loader = null, int $max_errors = 1)
- {
- parent::__construct($loader, $max_errors);
+ const COMPLIANT_OPTIONS = array(
+ 'allowFilters' => false,
+ 'allowFormats' => true,
+ 'allowMappers' => false,
+ 'allowTemplates' => false,
+ 'allowGlobals' => false,
+ 'allowDefaults' => false,
+ 'allowSlots' => false,
+ 'allowKeywordValidators' => false,
+ 'allowPragmas' => false,
+ 'allowDataKeyword' => false,
+ 'allowKeywordsAlongsideRef' => false,
+ 'allowUnevaluated' => true,
+ 'allowRelativeJsonPointerInRef' => false,
+ 'allowExclusiveMinMaxAsBool' => false,
+ 'keepDependenciesKeyword' => false,
+ 'keepAdditionalItemsKeyword' => false,
+ );
- // Set parser options
- $parser = $this->parser();
- foreach (static::COMPLIANT_OPTIONS as $name => $value) {
- $parser->setOption($name, $value);
- }
- }
+ public function __construct( $loader = null, int $max_errors = 1 ) {
+ parent::__construct( $loader, $max_errors );
+
+ // Set parser options
+ $parser = $this->parser();
+ foreach ( static::COMPLIANT_OPTIONS as $name => $value ) {
+ $parser->setOption( $name, $value );
+ }
+ }
}
diff --git a/src/opis/json-schema/src/ContentEncoding.php b/src/opis/json-schema/src/ContentEncoding.php
index 9c8255cf..83dfc026 100644
--- a/src/opis/json-schema/src/ContentEncoding.php
+++ b/src/opis/json-schema/src/ContentEncoding.php
@@ -1,5 +1,6 @@
args = $args;
- }
+ /**
+ * @var mixed[]
+ */
+ protected $args;
- public function getArgs(): array {
- return $this->args;
- }
+ public function __construct( string $message, array $args = array() ) {
+ parent::__construct( $message );
+ $this->args = $args;
+ }
+
+ public function getArgs(): array {
+ return $this->args;
+ }
}
diff --git a/src/opis/json-schema/src/Errors/ErrorContainer.php b/src/opis/json-schema/src/Errors/ErrorContainer.php
index 48e4b4d9..1013c322 100644
--- a/src/opis/json-schema/src/Errors/ErrorContainer.php
+++ b/src/opis/json-schema/src/Errors/ErrorContainer.php
@@ -1,5 +1,6 @@
getErrors($error) as $error => $message) {
- $key = $key_formatter($error);
-
- if ($multiple) {
- if (!isset($list[$key])) {
- $list[$key] = [];
- }
- $list[$key][] = $formatter($error, $message);
- } else {
- if (!isset($list[$key])) {
- $list[$key] = $formatter($error, $message);
- }
- }
- }
-
- return $list;
- }
-
- /**
- * @param ValidationError|null $error
- * @param string $mode One of: flag, basic, detailed or verbose
- * @return array
- */
- public function formatOutput($error, $mode = "flag"): array
- {
- if ($error === null) {
- return ['valid' => true];
- }
-
- if ($mode === 'flag') {
- return ['valid' => false];
- }
-
- if ($mode === 'basic') {
- return [
- 'valid' => false,
- 'errors' => $this->formatFlat($error, [$this, 'formatOutputError']),
- ];
- }
-
- if ($mode === 'detailed' || $mode === 'verbose') {
- $isVerbose = $mode === 'verbose';
-
- return $this->getNestedErrors($error, function (ValidationError $error, $subErrors = null) use ($isVerbose) {
- $info = $this->formatOutputError($error);
-
- $info['valid'] = false;
-
- if ($isVerbose) {
- $id = $error->schema()->info();
- $id = $id->root() ?? $id->id();
- if ($id) {
- $id = rtrim($id, '#');
- }
- $info['absoluteKeywordLocation'] = $id . $info['keywordLocation'];
- }
-
- if ($subErrors) {
- $info['errors'] = $subErrors;
- if (!$isVerbose) {
- unset($info['error']);
- }
- }
-
- return $info;
- }
- );
- }
-
- return ['valid' => false];
- }
-
- /**
- * @param ValidationError $error
- * @param ?callable(ValidationError,?array):mixed $formatter
- * @return mixed
- */
- public function formatNested($error, $formatter = null)
- {
- if (!$formatter) {
- $formatter = function (ValidationError $error, $subErrors = null): array {
- $ret = [
- 'message' => $this->formatErrorMessage($error),
- 'keyword' => $error->keyword(),
- 'path' => $this->formatErrorKey($error),
- ];
-
- if ($subErrors) {
- $ret['errors'] = $subErrors;
- }
-
- return $ret;
- };
- }
-
- return $this->getNestedErrors($error, $formatter);
- }
-
- /**
- * @param ValidationError $error
- * @param ?callable(ValidationError):mixed $formatter
- * @return array
- */
- public function formatFlat($error, $formatter = null): array
- {
- if (!$formatter) {
- $formatter = [$this, 'formatErrorMessage'];
- }
-
- $list = [];
-
- foreach ($this->getFlatErrors($error) as $error) {
- $list[] = $formatter($error);
- }
-
- return $list;
- }
-
- /**
- * @param ValidationError $error
- * @param ?callable(ValidationError):mixed $formatter
- * @param ?callable(ValidationError):string $key_formatter
- * @return array
- */
- public function formatKeyed(
- $error,
- $formatter = null,
- $key_formatter = null
- ): array {
- if (!$formatter) {
- $formatter = [$this, 'formatErrorMessage'];
- }
-
- if (!$key_formatter) {
- $key_formatter = [$this, 'formatErrorKey'];
- }
-
- $list = [];
-
- foreach ($this->getLeafErrors($error) as $error) {
- $key = $key_formatter($error);
-
- if (!isset($list[$key])) {
- $list[$key] = [];
- }
-
- $list[$key][] = $formatter($error);
- }
-
- return $list;
- }
-
- /**
- * @param ValidationError $error
- * @param string|null $message The message to use, if null $error->message() is used
- * @return string
- */
- public function formatErrorMessage($error, $message = null): string
- {
- $message = $message ?? $error->message();
- $args = $this->getDefaultArgs($error) + $error->args();
-
- if (!$args) {
- return $message;
- }
-
- return preg_replace_callback(
- '~{([^}]+)}~imu',
- static function (array $m) use ($args) {
- if (!isset($args[$m[1]])) {
- return $m[0];
- }
-
- $value = $args[$m[1]];
-
- if (is_array($value)) {
- return implode(', ', $value);
- }
-
- return (string) $value;
- },
- $message
- );
- }
-
- /**
- * @param \Opis\JsonSchema\Errors\ValidationError $error
- */
- public function formatErrorKey($error): string
- {
- return JsonPointer::pathToString($error->data()->fullPath());
- }
-
- /**
- * @param \Opis\JsonSchema\Errors\ValidationError $error
- */
- protected function getDefaultArgs($error): array
- {
- $data = $error->data();
- $info = $error->schema()->info();
-
- $path = $info->path();
- $path[] = $error->keyword();
-
- return [
- 'data:type' => $data->type(),
- 'data:value' => $data->value(),
- 'data:path' => JsonPointer::pathToString($data->fullPath()),
-
- 'schema:id' => $info->id(),
- 'schema:root' => $info->root(),
- 'schema:base' => $info->base(),
- 'schema:draft' => $info->draft(),
- 'schema:keyword' => $error->keyword(),
- 'schema:path' => JsonPointer::pathToString($path),
- ];
- }
-
- /**
- * @param \Opis\JsonSchema\Errors\ValidationError $error
- */
- protected function formatOutputError($error): array
- {
- $path = $error->schema()->info()->path();
-
- $path[] = $error->keyword();
-
- return [
- 'keywordLocation' => JsonPointer::pathToFragment($path),
- 'instanceLocation' => JsonPointer::pathToFragment($error->data()->fullPath()),
- 'error' => $this->formatErrorMessage($error),
- ];
- }
-
- /**
- * @param ValidationError $error
- * @param callable(ValidationError,?array):mixed $formatter
- * @return mixed
- */
- protected function getNestedErrors($error, $formatter)
- {
- if ($subErrors = $error->subErrors()) {
- foreach ($subErrors as &$subError) {
- $subError = $this->getNestedErrors($subError, $formatter);
- unset($subError);
- }
- }
-
- return $formatter($error, $subErrors);
- }
-
- /**
- * @param ValidationError $error
- * @return iterable|ValidationError[]
- */
- protected function getFlatErrors($error)
- {
- yield $error;
-
- foreach ($error->subErrors() as $subError) {
- yield from $this->getFlatErrors($subError);
- }
- }
-
- /**
- * @param ValidationError $error
- * @return iterable|ValidationError[]
- */
- protected function getLeafErrors($error)
- {
- if ($subErrors = $error->subErrors()) {
- foreach ($subErrors as $subError) {
- yield from $this->getLeafErrors($subError);
- }
- } else {
- yield $error;
- }
- }
-
- /**
- * @param ValidationError $error
- * @return iterable
- */
- protected function getErrors($error)
- {
- $data = $error->schema()->info()->data();
-
- $map = null;
- $pMap = null;
-
- if (is_object($data)) {
- switch ($error->keyword()) {
- case 'required':
- if (isset($data->{'$error'}->required) && is_object($data->{'$error'}->required)) {
- $e = $data->{'$error'}->required;
- $found = false;
- foreach ($error->args()['missing'] as $prop) {
- if (isset($e->{$prop})) {
- yield $error => $e->{$prop};
- $found = true;
- }
- }
- if ($found) {
- return;
- }
- if (isset($e->{'*'})) {
- yield $error => $e->{'*'};
- return;
- }
- unset($e, $found, $prop);
- }
- break;
- case '$filters':
- if (($args = $error->args()) && isset($args['args']['$error'])) {
- yield $error => $args['args']['$error'];
- return;
- }
- unset($args);
- break;
- }
-
- if (isset($data->{'$error'})) {
- $map = $data->{'$error'};
-
- if (is_string($map)) {
- // We have an global error
- yield $error => $map;
- return;
- }
-
- if (is_object($map)) {
- if (isset($map->{$error->keyword()})) {
- $pMap = $map->{'*'} ?? null;
- $map = $map->{$error->keyword()};
- if (is_string($map)) {
- yield $error => $map;
- return;
- }
- } elseif (isset($map->{'*'})) {
- yield $error => $map->{'*'};
- return;
- }
- }
- }
- }
-
- if (!is_object($map)) {
- $map = null;
- }
-
- $subErrors = $error->subErrors();
-
- if (!$subErrors) {
- yield $error => $pMap ?? $error->message();
- return;
- }
-
- if (!$map) {
- foreach ($subErrors as $subError) {
- yield from $this->getErrors($subError);
- }
- return;
- }
-
- foreach ($subErrors as $subError) {
- $path = $subError->data()->path();
- if (count($path) !== 1) {
- yield from $this->getErrors($subError);
- } else {
- $path = $path[0];
- if (isset($map->{$path})) {
- yield $subError => $map->{$path};
- } elseif (isset($map->{'*'})) {
- yield $subError => $map->{'*'};
- } else {
- yield from $this->getErrors($subError);
- }
- }
- }
- }
+class ErrorFormatter {
+
+ /**
+ * @param ValidationError $error
+ * @param bool $multiple True if the same key can have multiple errors
+ * @param ?callable(ValidationError,?string=null):mixed $formatter
+ * @param ?callable(ValidationError):string $key_formatter
+ * @return array
+ */
+ public function format(
+ $error,
+ $multiple = true,
+ $formatter = null,
+ $key_formatter = null
+ ): array {
+ if ( ! $formatter ) {
+ $formatter = array( $this, 'formatErrorMessage' );
+ }
+
+ if ( ! $key_formatter ) {
+ $key_formatter = array( $this, 'formatErrorKey' );
+ }
+
+ $list = array();
+
+ /**
+ * @var ValidationError $error
+ * @var string $message
+ */
+
+ foreach ( $this->getErrors( $error ) as $error => $message ) {
+ $key = $key_formatter( $error );
+
+ if ( $multiple ) {
+ if ( ! isset( $list[ $key ] ) ) {
+ $list[ $key ] = array();
+ }
+ $list[ $key ][] = $formatter( $error, $message );
+ } elseif ( ! isset( $list[ $key ] ) ) {
+ $list[ $key ] = $formatter( $error, $message );
+ }
+ }
+
+ return $list;
+ }
+
+ /**
+ * @param ValidationError|null $error
+ * @param string $mode One of: flag, basic, detailed or verbose
+ * @return array
+ */
+ public function formatOutput( $error, $mode = 'flag' ): array {
+ if ( $error === null ) {
+ return array( 'valid' => true );
+ }
+
+ if ( $mode === 'flag' ) {
+ return array( 'valid' => false );
+ }
+
+ if ( $mode === 'basic' ) {
+ return array(
+ 'valid' => false,
+ 'errors' => $this->formatFlat( $error, array( $this, 'formatOutputError' ) ),
+ );
+ }
+
+ if ( $mode === 'detailed' || $mode === 'verbose' ) {
+ $isVerbose = $mode === 'verbose';
+
+ return $this->getNestedErrors(
+ $error,
+ function ( ValidationError $error, $subErrors = null ) use ( $isVerbose ) {
+ $info = $this->formatOutputError( $error );
+
+ $info['valid'] = false;
+
+ if ( $isVerbose ) {
+ $id = $error->schema()->info();
+ $id = $id->root() ?? $id->id();
+ if ( $id ) {
+ $id = rtrim( $id, '#' );
+ }
+ $info['absoluteKeywordLocation'] = $id . $info['keywordLocation'];
+ }
+
+ if ( $subErrors ) {
+ $info['errors'] = $subErrors;
+ if ( ! $isVerbose ) {
+ unset( $info['error'] );
+ }
+ }
+
+ return $info;
+ }
+ );
+ }
+
+ return array( 'valid' => false );
+ }
+
+ /**
+ * @param ValidationError $error
+ * @param ?callable(ValidationError,?array):mixed $formatter
+ * @return mixed
+ */
+ public function formatNested( $error, $formatter = null ) {
+ if ( ! $formatter ) {
+ $formatter = function ( ValidationError $error, $subErrors = null ): array {
+ $ret = array(
+ 'message' => $this->formatErrorMessage( $error ),
+ 'keyword' => $error->keyword(),
+ 'path' => $this->formatErrorKey( $error ),
+ );
+
+ if ( $subErrors ) {
+ $ret['errors'] = $subErrors;
+ }
+
+ return $ret;
+ };
+ }
+
+ return $this->getNestedErrors( $error, $formatter );
+ }
+
+ /**
+ * @param ValidationError $error
+ * @param ?callable(ValidationError):mixed $formatter
+ * @return array
+ */
+ public function formatFlat( $error, $formatter = null ): array {
+ if ( ! $formatter ) {
+ $formatter = array( $this, 'formatErrorMessage' );
+ }
+
+ $list = array();
+
+ foreach ( $this->getFlatErrors( $error ) as $error ) {
+ $list[] = $formatter( $error );
+ }
+
+ return $list;
+ }
+
+ /**
+ * @param ValidationError $error
+ * @param ?callable(ValidationError):mixed $formatter
+ * @param ?callable(ValidationError):string $key_formatter
+ * @return array
+ */
+ public function formatKeyed(
+ $error,
+ $formatter = null,
+ $key_formatter = null
+ ): array {
+ if ( ! $formatter ) {
+ $formatter = array( $this, 'formatErrorMessage' );
+ }
+
+ if ( ! $key_formatter ) {
+ $key_formatter = array( $this, 'formatErrorKey' );
+ }
+
+ $list = array();
+
+ foreach ( $this->getLeafErrors( $error ) as $error ) {
+ $key = $key_formatter( $error );
+
+ if ( ! isset( $list[ $key ] ) ) {
+ $list[ $key ] = array();
+ }
+
+ $list[ $key ][] = $formatter( $error );
+ }
+
+ return $list;
+ }
+
+ /**
+ * @param ValidationError $error
+ * @param string|null $message The message to use, if null $error->message() is used
+ * @return string
+ */
+ public function formatErrorMessage( $error, $message = null ): string {
+ $message = $message ?? $error->message();
+ $args = $this->getDefaultArgs( $error ) + $error->args();
+
+ if ( ! $args ) {
+ return $message;
+ }
+
+ return preg_replace_callback(
+ '~{([^}]+)}~imu',
+ static function ( array $m ) use ( $args ) {
+ if ( ! isset( $args[ $m[1] ] ) ) {
+ return $m[0];
+ }
+
+ $value = $args[ $m[1] ];
+
+ if ( is_array( $value ) ) {
+ return implode( ', ', $value );
+ }
+
+ return (string) $value;
+ },
+ $message
+ );
+ }
+
+ /**
+ * @param \Opis\JsonSchema\Errors\ValidationError $error
+ */
+ public function formatErrorKey( $error ): string {
+ return JsonPointer::pathToString( $error->data()->fullPath() );
+ }
+
+ /**
+ * @param \Opis\JsonSchema\Errors\ValidationError $error
+ */
+ protected function getDefaultArgs( $error ): array {
+ $data = $error->data();
+ $info = $error->schema()->info();
+
+ $path = $info->path();
+ $path[] = $error->keyword();
+
+ return array(
+ 'data:type' => $data->type(),
+ 'data:value' => $data->value(),
+ 'data:path' => JsonPointer::pathToString( $data->fullPath() ),
+
+ 'schema:id' => $info->id(),
+ 'schema:root' => $info->root(),
+ 'schema:base' => $info->base(),
+ 'schema:draft' => $info->draft(),
+ 'schema:keyword' => $error->keyword(),
+ 'schema:path' => JsonPointer::pathToString( $path ),
+ );
+ }
+
+ /**
+ * @param \Opis\JsonSchema\Errors\ValidationError $error
+ */
+ protected function formatOutputError( $error ): array {
+ $path = $error->schema()->info()->path();
+
+ $path[] = $error->keyword();
+
+ return array(
+ 'keywordLocation' => JsonPointer::pathToFragment( $path ),
+ 'instanceLocation' => JsonPointer::pathToFragment( $error->data()->fullPath() ),
+ 'error' => $this->formatErrorMessage( $error ),
+ );
+ }
+
+ /**
+ * @param ValidationError $error
+ * @param callable(ValidationError,?array):mixed $formatter
+ * @return mixed
+ */
+ protected function getNestedErrors( $error, $formatter ) {
+ if ( $subErrors = $error->subErrors() ) {
+ foreach ( $subErrors as &$subError ) {
+ $subError = $this->getNestedErrors( $subError, $formatter );
+ unset( $subError );
+ }
+ }
+
+ return $formatter( $error, $subErrors );
+ }
+
+ /**
+ * @param ValidationError $error
+ * @return iterable|ValidationError[]
+ */
+ protected function getFlatErrors( $error ) {
+ yield $error;
+
+ foreach ( $error->subErrors() as $subError ) {
+ yield from $this->getFlatErrors( $subError );
+ }
+ }
+
+ /**
+ * @param ValidationError $error
+ * @return iterable|ValidationError[]
+ */
+ protected function getLeafErrors( $error ) {
+ if ( $subErrors = $error->subErrors() ) {
+ foreach ( $subErrors as $subError ) {
+ yield from $this->getLeafErrors( $subError );
+ }
+ } else {
+ yield $error;
+ }
+ }
+
+ /**
+ * @param ValidationError $error
+ * @return iterable
+ */
+ protected function getErrors( $error ) {
+ $data = $error->schema()->info()->data();
+
+ $map = null;
+ $pMap = null;
+
+ if ( is_object( $data ) ) {
+ switch ( $error->keyword() ) {
+ case 'required':
+ if ( isset( $data->{'$error'}->required ) && is_object( $data->{'$error'}->required ) ) {
+ $e = $data->{'$error'}->required;
+ $found = false;
+ foreach ( $error->args()['missing'] as $prop ) {
+ if ( isset( $e->{$prop} ) ) {
+ yield $error => $e->{$prop};
+ $found = true;
+ }
+ }
+ if ( $found ) {
+ return;
+ }
+ if ( isset( $e->{'*'} ) ) {
+ yield $error => $e->{'*'};
+ return;
+ }
+ unset( $e, $found, $prop );
+ }
+ break;
+ case '$filters':
+ if ( ( $args = $error->args() ) && isset( $args['args']['$error'] ) ) {
+ yield $error => $args['args']['$error'];
+ return;
+ }
+ unset( $args );
+ break;
+ }
+
+ if ( isset( $data->{'$error'} ) ) {
+ $map = $data->{'$error'};
+
+ if ( is_string( $map ) ) {
+ // We have an global error
+ yield $error => $map;
+ return;
+ }
+
+ if ( is_object( $map ) ) {
+ if ( isset( $map->{$error->keyword()} ) ) {
+ $pMap = $map->{'*'} ?? null;
+ $map = $map->{$error->keyword()};
+ if ( is_string( $map ) ) {
+ yield $error => $map;
+ return;
+ }
+ } elseif ( isset( $map->{'*'} ) ) {
+ yield $error => $map->{'*'};
+ return;
+ }
+ }
+ }
+ }
+
+ if ( ! is_object( $map ) ) {
+ $map = null;
+ }
+
+ $subErrors = $error->subErrors();
+
+ if ( ! $subErrors ) {
+ yield $error => $pMap ?? $error->message();
+ return;
+ }
+
+ if ( ! $map ) {
+ foreach ( $subErrors as $subError ) {
+ yield from $this->getErrors( $subError );
+ }
+ return;
+ }
+
+ foreach ( $subErrors as $subError ) {
+ $path = $subError->data()->path();
+ if ( count( $path ) !== 1 ) {
+ yield from $this->getErrors( $subError );
+ } else {
+ $path = $path[0];
+ if ( isset( $map->{$path} ) ) {
+ yield $subError => $map->{$path};
+ } elseif ( isset( $map->{'*'} ) ) {
+ yield $subError => $map->{'*'};
+ } else {
+ yield from $this->getErrors( $subError );
+ }
+ }
+ }
+ }
}
diff --git a/src/opis/json-schema/src/Errors/ValidationError.php b/src/opis/json-schema/src/Errors/ValidationError.php
index 84fd5f7f..9fc978bb 100644
--- a/src/opis/json-schema/src/Errors/ValidationError.php
+++ b/src/opis/json-schema/src/Errors/ValidationError.php
@@ -1,5 +1,6 @@
keyword = $keyword;
- $this->schema = $schema;
- $this->data = $data;
- $this->message = $message;
- $this->args = $args;
- $this->subErrors = $subErrors;
- }
-
- public function keyword(): string
- {
- return $this->keyword;
- }
-
- public function schema(): Schema
- {
- return $this->schema;
- }
-
- public function data(): DataInfo
- {
- return $this->data;
- }
-
- public function args(): array
- {
- return $this->args;
- }
-
- public function message(): string
- {
- return $this->message;
- }
-
- public function subErrors(): array
- {
- return $this->subErrors;
- }
-
- public function __toString(): string
- {
- return $this->message;
- }
-}
\ No newline at end of file
+class ValidationError {
+
+ /**
+ * @var string
+ */
+ protected $keyword;
+
+ /**
+ * @var \Opis\JsonSchema\Schema
+ */
+ protected $schema;
+
+ /**
+ * @var \Opis\JsonSchema\Info\DataInfo
+ */
+ protected $data;
+
+ /**
+ * @var mixed[]
+ */
+ protected $args;
+
+ /**
+ * @var string
+ */
+ protected $message;
+
+ /** @var ValidationError[] */
+ protected $subErrors;
+
+ /**
+ * @param string $keyword
+ * @param Schema $schema
+ * @param DataInfo $data
+ * @param string $message
+ * @param array $args
+ * @param ValidationError[] $subErrors
+ */
+ public function __construct(
+ string $keyword,
+ Schema $schema,
+ DataInfo $data,
+ string $message,
+ array $args = array(),
+ array $subErrors = array()
+ ) {
+ $this->keyword = $keyword;
+ $this->schema = $schema;
+ $this->data = $data;
+ $this->message = $message;
+ $this->args = $args;
+ $this->subErrors = $subErrors;
+ }
+
+ public function keyword(): string {
+ return $this->keyword;
+ }
+
+ public function schema(): Schema {
+ return $this->schema;
+ }
+
+ public function data(): DataInfo {
+ return $this->data;
+ }
+
+ public function args(): array {
+ return $this->args;
+ }
+
+ public function message(): string {
+ return $this->message;
+ }
+
+ public function subErrors(): array {
+ return $this->subErrors;
+ }
+
+ public function __toString(): string {
+ return $this->message;
+ }
+}
diff --git a/src/opis/json-schema/src/Exceptions/DuplicateSchemaIdException.php b/src/opis/json-schema/src/Exceptions/DuplicateSchemaIdException.php
index a6cc228c..baa7981f 100644
--- a/src/opis/json-schema/src/Exceptions/DuplicateSchemaIdException.php
+++ b/src/opis/json-schema/src/Exceptions/DuplicateSchemaIdException.php
@@ -1,5 +1,6 @@
id = $id;
- $this->data = $data;
- }
-
- /**
- * @return null|object
- */
- public function getData()
- {
- return $this->data;
- }
-
- /**
- * @return Uri
- */
- public function getId(): Uri
- {
- return $this->id;
- }
-}
\ No newline at end of file
+class DuplicateSchemaIdException extends RuntimeException implements SchemaException {
+
+
+ /**
+ * @var \Opis\JsonSchema\Uri
+ */
+ protected $id;
+
+ /**
+ * @var object|null
+ */
+ protected $data;
+
+ /**
+ * DuplicateSchemaIdException constructor.
+ *
+ * @param Uri $id
+ * @param object|null $data
+ */
+ public function __construct( Uri $id, $data = null ) {
+ parent::__construct( "Duplicate schema id: {$id}", 0 );
+ $this->id = $id;
+ $this->data = $data;
+ }
+
+ /**
+ * @return null|object
+ */
+ public function getData() {
+ return $this->data;
+ }
+
+ /**
+ * @return Uri
+ */
+ public function getId(): Uri {
+ return $this->id;
+ }
+}
diff --git a/src/opis/json-schema/src/Exceptions/InvalidKeywordException.php b/src/opis/json-schema/src/Exceptions/InvalidKeywordException.php
index f17bd002..7ea69bcf 100644
--- a/src/opis/json-schema/src/Exceptions/InvalidKeywordException.php
+++ b/src/opis/json-schema/src/Exceptions/InvalidKeywordException.php
@@ -1,5 +1,6 @@
keyword = $keyword;
- }
+ /**
+ * @var string
+ */
+ protected $keyword;
- /**
- * @return string
- */
- public function keyword(): string
- {
- return $this->keyword;
- }
+ /**
+ * InvalidKeywordException constructor.
+ *
+ * @param string $message
+ * @param string $keyword
+ * @param SchemaInfo|null $info
+ */
+ public function __construct( string $message, string $keyword, $info = null ) {
+ parent::__construct( $message, $info );
+ $this->keyword = $keyword;
+ }
+
+ /**
+ * @return string
+ */
+ public function keyword(): string {
+ return $this->keyword;
+ }
}
diff --git a/src/opis/json-schema/src/Exceptions/InvalidPragmaException.php b/src/opis/json-schema/src/Exceptions/InvalidPragmaException.php
index 87f89895..78efa0c4 100644
--- a/src/opis/json-schema/src/Exceptions/InvalidPragmaException.php
+++ b/src/opis/json-schema/src/Exceptions/InvalidPragmaException.php
@@ -1,5 +1,6 @@
pragma = $pragma;
- }
+ /**
+ * @var string
+ */
+ protected $pragma;
- /**
- * @return string
- */
- public function pragma(): string
- {
- return $this->pragma;
- }
+ /**
+ * InvalidPragmaException constructor.
+ *
+ * @param string $message
+ * @param string $pragma
+ * @param SchemaInfo|null $info
+ */
+ public function __construct( string $message, string $pragma, $info = null ) {
+ parent::__construct( $message, '$pragma', $info );
+ $this->pragma = $pragma;
+ }
+
+ /**
+ * @return string
+ */
+ public function pragma(): string {
+ return $this->pragma;
+ }
}
diff --git a/src/opis/json-schema/src/Exceptions/ParseException.php b/src/opis/json-schema/src/Exceptions/ParseException.php
index c77c4c71..b388c437 100644
--- a/src/opis/json-schema/src/Exceptions/ParseException.php
+++ b/src/opis/json-schema/src/Exceptions/ParseException.php
@@ -1,5 +1,6 @@
info = $info;
- }
+ /**
+ * @var \Opis\JsonSchema\Info\SchemaInfo|null
+ */
+ protected $info;
- /**
- * @return SchemaInfo|null
- */
- public function schemaInfo()
- {
- return $this->info;
- }
+ /**
+ * @param string $message
+ * @param SchemaInfo|null $info
+ */
+ public function __construct( string $message, $info = null ) {
+ parent::__construct( $message, 0 );
+ $this->info = $info;
+ }
+
+ /**
+ * @return SchemaInfo|null
+ */
+ public function schemaInfo() {
+ return $this->info;
+ }
}
diff --git a/src/opis/json-schema/src/Exceptions/SchemaException.php b/src/opis/json-schema/src/Exceptions/SchemaException.php
index feedbcd4..40f56911 100644
--- a/src/opis/json-schema/src/Exceptions/SchemaException.php
+++ b/src/opis/json-schema/src/Exceptions/SchemaException.php
@@ -1,5 +1,6 @@
encoding = $encoding;
- }
+ /**
+ * @var string
+ */
+ protected $encoding;
- /**
- * @return string
- */
- public function getContentEncoding(): string
- {
- return $this->encoding;
- }
-}
\ No newline at end of file
+ /**
+ * @param string $encoding
+ * @param Schema $schema
+ * @param ValidationContext $context
+ */
+ public function __construct( string $encoding, Schema $schema, ValidationContext $context ) {
+ parent::__construct( "Cannot resolve '{$encoding}' content encoding", $schema, $context );
+ $this->encoding = $encoding;
+ }
+
+ /**
+ * @return string
+ */
+ public function getContentEncoding(): string {
+ return $this->encoding;
+ }
+}
diff --git a/src/opis/json-schema/src/Exceptions/UnresolvedContentMediaTypeException.php b/src/opis/json-schema/src/Exceptions/UnresolvedContentMediaTypeException.php
index 1f23677c..ffc5c3b8 100644
--- a/src/opis/json-schema/src/Exceptions/UnresolvedContentMediaTypeException.php
+++ b/src/opis/json-schema/src/Exceptions/UnresolvedContentMediaTypeException.php
@@ -1,5 +1,6 @@
media = $media;
- }
+ /**
+ * @var string
+ */
+ protected $media;
- /**
- * @return string
- */
- public function getContentMediaType(): string
- {
- return $this->media;
- }
-}
\ No newline at end of file
+ /**
+ * @param string $media
+ * @param Schema $schema
+ * @param ValidationContext $context
+ */
+ public function __construct( string $media, Schema $schema, ValidationContext $context ) {
+ parent::__construct( "Cannot resolve '{$media}' content media type", $schema, $context );
+ $this->media = $media;
+ }
+
+ /**
+ * @return string
+ */
+ public function getContentMediaType(): string {
+ return $this->media;
+ }
+}
diff --git a/src/opis/json-schema/src/Exceptions/UnresolvedException.php b/src/opis/json-schema/src/Exceptions/UnresolvedException.php
index e122cae2..76a848ee 100644
--- a/src/opis/json-schema/src/Exceptions/UnresolvedException.php
+++ b/src/opis/json-schema/src/Exceptions/UnresolvedException.php
@@ -1,5 +1,6 @@
schema = $schema;
- $this->context = $context;
- }
-
- /**
- * @return Schema
- */
- public function getSchema(): Schema
- {
- return $this->schema;
- }
-
- /**
- * @return ValidationContext
- */
- public function getContext(): ValidationContext
- {
- return $this->context;
- }
-}
\ No newline at end of file
+class UnresolvedException extends RuntimeException implements SchemaException {
+
+
+ /**
+ * @var \Opis\JsonSchema\Schema
+ */
+ protected $schema;
+
+ /**
+ * @var \Opis\JsonSchema\ValidationContext
+ */
+ protected $context;
+
+ /**
+ * @param string $message
+ * @param Schema $schema
+ * @param ValidationContext $context
+ */
+ public function __construct( string $message, Schema $schema, ValidationContext $context ) {
+ parent::__construct( $message );
+ $this->schema = $schema;
+ $this->context = $context;
+ }
+
+ /**
+ * @return Schema
+ */
+ public function getSchema(): Schema {
+ return $this->schema;
+ }
+
+ /**
+ * @return ValidationContext
+ */
+ public function getContext(): ValidationContext {
+ return $this->context;
+ }
+}
diff --git a/src/opis/json-schema/src/Exceptions/UnresolvedFilterException.php b/src/opis/json-schema/src/Exceptions/UnresolvedFilterException.php
index 3acddb7b..c983e4dc 100644
--- a/src/opis/json-schema/src/Exceptions/UnresolvedFilterException.php
+++ b/src/opis/json-schema/src/Exceptions/UnresolvedFilterException.php
@@ -1,5 +1,6 @@
filter = $filter;
- $this->type = $type;
- }
-
- /**
- * @return string
- */
- public function getFilter(): string
- {
- return $this->filter;
- }
-
- /**
- * @return string
- */
- public function getType(): string
- {
- return $this->type;
- }
-}
\ No newline at end of file
+class UnresolvedFilterException extends UnresolvedException {
+
+
+ /**
+ * @var string
+ */
+ protected $filter;
+
+ /**
+ * @var string
+ */
+ protected $type;
+
+ /**
+ * @param string $filter
+ * @param string $type
+ * @param Schema $schema
+ * @param ValidationContext $context
+ */
+ public function __construct( string $filter, string $type, Schema $schema, ValidationContext $context ) {
+ parent::__construct( "Cannot resolve filter '{$filter}' for type '{$type}'", $schema, $context );
+ $this->filter = $filter;
+ $this->type = $type;
+ }
+
+ /**
+ * @return string
+ */
+ public function getFilter(): string {
+ return $this->filter;
+ }
+
+ /**
+ * @return string
+ */
+ public function getType(): string {
+ return $this->type;
+ }
+}
diff --git a/src/opis/json-schema/src/Exceptions/UnresolvedReferenceException.php b/src/opis/json-schema/src/Exceptions/UnresolvedReferenceException.php
index 7b9c2f92..c6a0b9e8 100644
--- a/src/opis/json-schema/src/Exceptions/UnresolvedReferenceException.php
+++ b/src/opis/json-schema/src/Exceptions/UnresolvedReferenceException.php
@@ -1,5 +1,6 @@
ref = $ref;
- }
+ /**
+ * @var string
+ */
+ protected $ref;
- /**
- * @return string
- */
- public function getRef(): string
- {
- return $this->ref;
- }
-}
\ No newline at end of file
+ /**
+ * @param string $ref
+ * @param Schema $schema
+ * @param ValidationContext $context
+ */
+ public function __construct( string $ref, Schema $schema, ValidationContext $context ) {
+ parent::__construct( "Unresolved reference: {$ref}", $schema, $context );
+ $this->ref = $ref;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRef(): string {
+ return $this->ref;
+ }
+}
diff --git a/src/opis/json-schema/src/Filter.php b/src/opis/json-schema/src/Filter.php
index 90583080..8ce12551 100644
--- a/src/opis/json-schema/src/Filter.php
+++ b/src/opis/json-schema/src/Filter.php
@@ -1,5 +1,6 @@
currentData();
- if (!is_string($ref)) {
- return false;
- }
+class DataExistsFilter implements Filter {
- $ref = JsonPointer::parse($ref);
- if ($ref === null) {
- return false;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ * @param mixed[] $args
+ */
+ public function validate( $context, $schema, $args = array() ): bool {
+ $ref = $args['ref'] ?? $context->currentData();
+ if ( ! is_string( $ref ) ) {
+ return false;
+ }
- return $ref->data($context->rootData(), $context->currentDataPath(), $this) !== $this;
- }
-}
\ No newline at end of file
+ $ref = JsonPointer::parse( $ref );
+ if ( $ref === null ) {
+ return false;
+ }
+
+ return $ref->data( $context->rootData(), $context->currentDataPath(), $this ) !== $this;
+ }
+}
diff --git a/src/opis/json-schema/src/Filters/DateTimeFilters.php b/src/opis/json-schema/src/Filters/DateTimeFilters.php
index 1df0fe2e..f770f0db 100644
--- a/src/opis/json-schema/src/Filters/DateTimeFilters.php
+++ b/src/opis/json-schema/src/Filters/DateTimeFilters.php
@@ -1,5 +1,6 @@
= self::CreateDate($min, $tz, false);
- }
-
- public static function MaxDate(string $date, array $args): bool
- {
- $max = $args['value'];
- $tz = $args['timezone'] ?? null;
-
- return self::CreateDate($date, $tz, false) <= self::CreateDate($max, $tz, false);
- }
-
- public static function NotDate(string $date, array $args): bool
- {
- $not = $args['value'];
- $tz = $args['timezone'] ?? null;
-
- if (!is_array($not)) {
- $not = [$not];
- }
-
- $date = self::CreateDate($date, $tz, false);
-
- foreach ($not as $d) {
- if ($date == self::CreateDate($d, $tz, false)) {
- return false;
- }
- }
-
- return true;
- }
-
- public static function MinDateTime(string $date, array $args): bool
- {
- $min = $args['value'];
- $tz = $args['timezone'] ?? null;
-
- return self::CreateDate($date, $tz) >= self::CreateDate($min, $tz);
- }
-
- public static function MaxDateTime(string $date, array $args): bool
- {
- $max = $args['value'];
- $tz = $args['timezone'] ?? null;
-
- return self::CreateDate($date, $tz) <= self::CreateDate($max, $tz);
- }
-
- public static function MinTime(string $time, array $args): bool
- {
- $min = $args['value'];
- $prefix = '1970-01-01 ';
-
- return self::CreateDate($prefix . $time) >= self::CreateDate($prefix . $min);
- }
-
- public static function MaxTime(string $time, array $args): bool
- {
- $max = $args['value'];
- $prefix = '1970-01-01 ';
-
- return self::CreateDate($prefix . $time) <= self::CreateDate($prefix . $max);
- }
-
- private static function CreateDate(string $value, $timezone = null, bool $time = true): DateTime
- {
- $date = new DateTime($value, $timezone);
- if (!$time) {
- return $date->setTime(0, 0, 0, 0);
- }
- return $date;
- }
+final class DateTimeFilters {
+
+ public static function MinDate( string $date, array $args ): bool {
+ $min = $args['value'];
+ $tz = $args['timezone'] ?? null;
+
+ return self::CreateDate( $date, $tz, false ) >= self::CreateDate( $min, $tz, false );
+ }
+
+ public static function MaxDate( string $date, array $args ): bool {
+ $max = $args['value'];
+ $tz = $args['timezone'] ?? null;
+
+ return self::CreateDate( $date, $tz, false ) <= self::CreateDate( $max, $tz, false );
+ }
+
+ public static function NotDate( string $date, array $args ): bool {
+ $not = $args['value'];
+ $tz = $args['timezone'] ?? null;
+
+ if ( ! is_array( $not ) ) {
+ $not = array( $not );
+ }
+
+ $date = self::CreateDate( $date, $tz, false );
+
+ foreach ( $not as $d ) {
+ if ( $date == self::CreateDate( $d, $tz, false ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static function MinDateTime( string $date, array $args ): bool {
+ $min = $args['value'];
+ $tz = $args['timezone'] ?? null;
+
+ return self::CreateDate( $date, $tz ) >= self::CreateDate( $min, $tz );
+ }
+
+ public static function MaxDateTime( string $date, array $args ): bool {
+ $max = $args['value'];
+ $tz = $args['timezone'] ?? null;
+
+ return self::CreateDate( $date, $tz ) <= self::CreateDate( $max, $tz );
+ }
+
+ public static function MinTime( string $time, array $args ): bool {
+ $min = $args['value'];
+ $prefix = '1970-01-01 ';
+
+ return self::CreateDate( $prefix . $time ) >= self::CreateDate( $prefix . $min );
+ }
+
+ public static function MaxTime( string $time, array $args ): bool {
+ $max = $args['value'];
+ $prefix = '1970-01-01 ';
+
+ return self::CreateDate( $prefix . $time ) <= self::CreateDate( $prefix . $max );
+ }
+
+ private static function CreateDate( string $value, $timezone = null, bool $time = true ): DateTime {
+ $date = new DateTime( $value, $timezone );
+ if ( ! $time ) {
+ return $date->setTime( 0, 0, 0, 0 );
+ }
+ return $date;
+ }
}
diff --git a/src/opis/json-schema/src/Filters/FilterExistsFilter.php b/src/opis/json-schema/src/Filters/FilterExistsFilter.php
index 3ce635d3..bad51708 100644
--- a/src/opis/json-schema/src/Filters/FilterExistsFilter.php
+++ b/src/opis/json-schema/src/Filters/FilterExistsFilter.php
@@ -1,5 +1,6 @@
currentData();
- if (!is_string($filter)) {
- return false;
- }
-
- $type = null;
- if (isset($args['type'])) {
- if (!is_string($args['type'])) {
- return false;
- }
- $type = $args['type'];
- }
-
- $resolver = $context->loader()->parser()->getFilterResolver();
-
- if (!$resolver) {
- return false;
- }
-
- if ($type === null) {
- return (bool)$resolver->resolveAll($filter);
- }
-
- return (bool)$resolver->resolve($filter, $type);
- }
-}
\ No newline at end of file
+class FilterExistsFilter implements Filter {
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ * @param mixed[] $args
+ */
+ public function validate( $context, $schema, $args = array() ): bool {
+ $filter = $args['filter'] ?? $context->currentData();
+ if ( ! is_string( $filter ) ) {
+ return false;
+ }
+
+ $type = null;
+ if ( isset( $args['type'] ) ) {
+ if ( ! is_string( $args['type'] ) ) {
+ return false;
+ }
+ $type = $args['type'];
+ }
+
+ $resolver = $context->loader()->parser()->getFilterResolver();
+
+ if ( ! $resolver ) {
+ return false;
+ }
+
+ if ( $type === null ) {
+ return (bool) $resolver->resolveAll( $filter );
+ }
+
+ return (bool) $resolver->resolve( $filter, $type );
+ }
+}
diff --git a/src/opis/json-schema/src/Filters/FormatExistsFilter.php b/src/opis/json-schema/src/Filters/FormatExistsFilter.php
index 7dc7f4e2..dde33510 100644
--- a/src/opis/json-schema/src/Filters/FormatExistsFilter.php
+++ b/src/opis/json-schema/src/Filters/FormatExistsFilter.php
@@ -1,5 +1,6 @@
currentData();
- if (!is_string($format)) {
- return false;
- }
-
- $type = null;
- if (isset($args['type'])) {
- if (!is_string($args['type'])) {
- return false;
- }
- $type = $args['type'];
- }
-
- $resolver = $context->loader()->parser()->getFormatResolver();
-
- if (!$resolver) {
- return false;
- }
-
- if ($type === null) {
- return (bool)$resolver->resolveAll($format);
- }
-
- return (bool)$resolver->resolve($format, $type);
- }
-}
\ No newline at end of file
+class FormatExistsFilter implements Filter {
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ * @param mixed[] $args
+ */
+ public function validate( $context, $schema, $args = array() ): bool {
+ $format = $args['format'] ?? $context->currentData();
+ if ( ! is_string( $format ) ) {
+ return false;
+ }
+
+ $type = null;
+ if ( isset( $args['type'] ) ) {
+ if ( ! is_string( $args['type'] ) ) {
+ return false;
+ }
+ $type = $args['type'];
+ }
+
+ $resolver = $context->loader()->parser()->getFormatResolver();
+
+ if ( ! $resolver ) {
+ return false;
+ }
+
+ if ( $type === null ) {
+ return (bool) $resolver->resolveAll( $format );
+ }
+
+ return (bool) $resolver->resolve( $format, $type );
+ }
+}
diff --git a/src/opis/json-schema/src/Filters/GlobalVarExistsFilter.php b/src/opis/json-schema/src/Filters/GlobalVarExistsFilter.php
index e8393d40..e6ea6fa2 100644
--- a/src/opis/json-schema/src/Filters/GlobalVarExistsFilter.php
+++ b/src/opis/json-schema/src/Filters/GlobalVarExistsFilter.php
@@ -1,5 +1,6 @@
currentData();
-
- if (!is_string($var)) {
- return false;
- }
-
- $globals = $context->globals();
-
- if (!array_key_exists($var, $globals)) {
- return false;
- }
-
- if (array_key_exists('value', $args)) {
- return $globals[$var] == $args['value'];
- }
-
- return true;
- }
-}
\ No newline at end of file
+class GlobalVarExistsFilter implements Filter {
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ * @param mixed[] $args
+ */
+ public function validate( $context, $schema, $args = array() ): bool {
+ $var = $args['var'] ?? $context->currentData();
+
+ if ( ! is_string( $var ) ) {
+ return false;
+ }
+
+ $globals = $context->globals();
+
+ if ( ! array_key_exists( $var, $globals ) ) {
+ return false;
+ }
+
+ if ( array_key_exists( 'value', $args ) ) {
+ return $globals[ $var ] == $args['value'];
+ }
+
+ return true;
+ }
+}
diff --git a/src/opis/json-schema/src/Filters/SchemaExistsFilter.php b/src/opis/json-schema/src/Filters/SchemaExistsFilter.php
index 071d7448..828bf794 100644
--- a/src/opis/json-schema/src/Filters/SchemaExistsFilter.php
+++ b/src/opis/json-schema/src/Filters/SchemaExistsFilter.php
@@ -1,5 +1,6 @@
currentData();
- if (!is_string($ref)) {
- return false;
- }
+class SchemaExistsFilter implements Filter {
- if (UriTemplate::isTemplate($ref)) {
- if (isset($args['vars']) && is_object($args['vars'])) {
- $vars = new VariablesContainer($args['vars'], false);
- $vars = $vars->resolve($context->rootData(), $context->currentDataPath());
- if (!is_array($vars)) {
- $vars = (array)$vars;
- }
- $vars += $context->globals();
- } else {
- $vars = $context->globals();
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ * @param mixed[] $args
+ */
+ public function validate( $context, $schema, $args = array() ): bool {
+ $ref = $args['ref'] ?? $context->currentData();
+ if ( ! is_string( $ref ) ) {
+ return false;
+ }
- $ref = (new UriTemplate($ref))->resolve($vars);
+ if ( UriTemplate::isTemplate( $ref ) ) {
+ if ( isset( $args['vars'] ) && is_object( $args['vars'] ) ) {
+ $vars = new VariablesContainer( $args['vars'], false );
+ $vars = $vars->resolve( $context->rootData(), $context->currentDataPath() );
+ if ( ! is_array( $vars ) ) {
+ $vars = (array) $vars;
+ }
+ $vars += $context->globals();
+ } else {
+ $vars = $context->globals();
+ }
- unset($vars);
- }
+ $ref = ( new UriTemplate( $ref ) )->resolve( $vars );
- unset($args);
+ unset( $vars );
+ }
- return $this->refExists($ref, $context, $schema);
- }
+ unset( $args );
- /**
- * @param string $ref
- * @param ValidationContext $context
- * @param Schema $schema
- * @return bool
- */
- protected function refExists($ref, $context, $schema): bool
- {
- if ($ref === '') {
- return false;
- }
+ return $this->refExists( $ref, $context, $schema );
+ }
- if ($ref === '#') {
- return true;
- }
+ /**
+ * @param string $ref
+ * @param ValidationContext $context
+ * @param Schema $schema
+ * @return bool
+ */
+ protected function refExists( $ref, $context, $schema ): bool {
+ if ( $ref === '' ) {
+ return false;
+ }
- $info = $schema->info();
+ if ( $ref === '#' ) {
+ return true;
+ }
- $id = Uri::merge($ref, $info->idBaseRoot(), true);
+ $info = $schema->info();
- if ($id === null) {
- return false;
- }
+ $id = Uri::merge( $ref, $info->idBaseRoot(), true );
- return $context->loader()->loadSchemaById($id) !== null;
- }
-}
\ No newline at end of file
+ if ( $id === null ) {
+ return false;
+ }
+
+ return $context->loader()->loadSchemaById( $id ) !== null;
+ }
+}
diff --git a/src/opis/json-schema/src/Filters/SlotExistsFilter.php b/src/opis/json-schema/src/Filters/SlotExistsFilter.php
index af4c8cb6..dac8a10c 100644
--- a/src/opis/json-schema/src/Filters/SlotExistsFilter.php
+++ b/src/opis/json-schema/src/Filters/SlotExistsFilter.php
@@ -1,5 +1,6 @@
currentData();
- if (!is_string($slot)) {
- return false;
- }
+class SlotExistsFilter implements Filter {
- return $context->slot($slot) !== null;
- }
-}
\ No newline at end of file
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ * @param mixed[] $args
+ */
+ public function validate( $context, $schema, $args = array() ): bool {
+ $slot = $args['slot'] ?? $context->currentData();
+ if ( ! is_string( $slot ) ) {
+ return false;
+ }
+
+ return $context->slot( $slot ) !== null;
+ }
+}
diff --git a/src/opis/json-schema/src/Format.php b/src/opis/json-schema/src/Format.php
index 577a5349..e487a6f4 100644
--- a/src/opis/json-schema/src/Format.php
+++ b/src/opis/json-schema/src/Format.php
@@ -1,5 +1,6 @@
.+)@(?.+)$/u', $value, $m)) {
- return false;
- }
-
- $m['name'] = $idn($m['name']);
- if ($m['name'] === null) {
- return false;
- }
-
- $m['domain'] = $idn($m['domain']);
- if ($m['domain'] === null) {
- return false;
- }
-
- $value = $m['name'] . '@' . $m['domain'];
- }
-
- return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
- }
-
- /**
- * @return callable|null
- */
- public static function idn()
- {
- if (static::$idn === false) {
- if (function_exists('idn_to_ascii')) {
- static::$idn = static function (string $value) {
- /** @noinspection PhpComposerExtensionStubsInspection */
- $value = idn_to_ascii($value, 0, INTL_IDNA_VARIANT_UTS46);
-
- return is_string($value) ? $value : null;
- };
- } else {
- static::$idn = null;
- }
- }
-
- return static::$idn;
- }
+class IriFormats {
+
+ const SKIP = array( 0x23, 0x26, 0x2F, 0x3A, 0x3D, 0x3F, 0x40, 0x5B, 0x5C, 0x5D );
+
+ /** @var bool|null|callable */
+ private static $idn = false;
+
+ /**
+ * @param string $value
+ * @return bool
+ */
+ public static function iri( $value ): bool {
+ if ( $value === '' ) {
+ return false;
+ }
+
+ try {
+ $components = Uri::parseComponents( Uri::encodeComponent( $value, self::SKIP ), true, true );
+ } catch ( Throwable $e ) {
+ return false;
+ }
+
+ return isset( $components['scheme'] ) && $components['scheme'] !== '';
+ }
+
+ /**
+ * @param string $value
+ * @return bool
+ */
+ public static function iriReference( $value ): bool {
+ if ( $value === '' ) {
+ return true;
+ }
+
+ try {
+ return Uri::parseComponents( Uri::encodeComponent( $value, self::SKIP ), true, true ) !== null;
+ } catch ( Throwable $e ) {
+ return false;
+ }
+ }
+
+ /**
+ * @param string $value
+ * @param callable|null $idn
+ * @return bool
+ */
+ public static function idnHostname( $value, $idn = null ): bool {
+ $idn = $idn ?? static::idn();
+
+ if ( $idn ) {
+ $value = $idn( $value );
+ if ( $value === null ) {
+ return false;
+ }
+ }
+
+ return Uri::isValidHost( $value );
+ }
+
+ /**
+ * @param string $value
+ * @param callable|null $idn
+ * @return bool
+ */
+ public static function idnEmail( $value, $idn = null ): bool {
+ $idn = $idn ?? static::idn();
+
+ if ( $idn ) {
+ if ( ! preg_match( '/^(?.+)@(?.+)$/u', $value, $m ) ) {
+ return false;
+ }
+
+ $m['name'] = $idn( $m['name'] );
+ if ( $m['name'] === null ) {
+ return false;
+ }
+
+ $m['domain'] = $idn( $m['domain'] );
+ if ( $m['domain'] === null ) {
+ return false;
+ }
+
+ $value = $m['name'] . '@' . $m['domain'];
+ }
+
+ return filter_var( $value, FILTER_VALIDATE_EMAIL ) !== false;
+ }
+
+ /**
+ * @return callable|null
+ */
+ public static function idn() {
+ if ( static::$idn === false ) {
+ if ( function_exists( 'idn_to_ascii' ) ) {
+ static::$idn = static function ( string $value ) {
+ /** @noinspection PhpComposerExtensionStubsInspection */
+ $value = idn_to_ascii( $value, 0, INTL_IDNA_VARIANT_UTS46 );
+
+ return is_string( $value ) ? $value : null;
+ };
+ } else {
+ static::$idn = null;
+ }
+ }
+
+ return static::$idn;
+ }
}
diff --git a/src/opis/json-schema/src/Formats/MiscFormats.php b/src/opis/json-schema/src/Formats/MiscFormats.php
index a5098907..e5030830 100644
--- a/src/opis/json-schema/src/Formats/MiscFormats.php
+++ b/src/opis/json-schema/src/Formats/MiscFormats.php
@@ -1,5 +1,6 @@
isAbsolute();
- }
+ $uri = Uri::parse( $value );
- /**
- * @param string $value
- * @return bool
- */
- public static function uriReference($value): bool
- {
- if ($value === '') {
- return true;
- }
+ return $uri !== null && $uri->isAbsolute();
+ }
- return Uri::parse($value) !== null;
- }
+ /**
+ * @param string $value
+ * @return bool
+ */
+ public static function uriReference( $value ): bool {
+ if ( $value === '' ) {
+ return true;
+ }
- /**
- * @param string $value
- * @return bool
- */
- public static function uriTemplate($value): bool
- {
- if ($value === '') {
- return true;
- }
+ return Uri::parse( $value ) !== null;
+ }
- if (UriTemplate::isTemplate($value)) {
- return true;
- }
+ /**
+ * @param string $value
+ * @return bool
+ */
+ public static function uriTemplate( $value ): bool {
+ if ( $value === '' ) {
+ return true;
+ }
- return Uri::parse($value) !== null;
- }
-}
\ No newline at end of file
+ if ( UriTemplate::isTemplate( $value ) ) {
+ return true;
+ }
+
+ return Uri::parse( $value ) !== null;
+ }
+}
diff --git a/src/opis/json-schema/src/Helper.php b/src/opis/json-schema/src/Helper.php
index 7ba5578b..98511464 100644
--- a/src/opis/json-schema/src/Helper.php
+++ b/src/opis/json-schema/src/Helper.php
@@ -1,5 +1,6 @@
'number'];
-
- /** @var string[] */
- const PHP_TYPE_MAP = [
- 'NULL' => 'null',
- 'integer' => 'integer',
- 'double' => 'number',
- 'boolean' => 'boolean',
- 'array' => 'array',
- 'object' => 'object',
- 'string' => 'string',
- ];
-
- /**
- * @param string $type
- * @return bool
- */
- public static function isValidJsonType(string $type): bool
- {
- if (isset(self::JSON_SUBTYPES[$type])) {
- return true;
- }
-
- return in_array($type, self::JSON_TYPES, true);
- }
-
- /**
- * @param string $type
- * @return null|string
- */
- public static function getJsonSuperType(string $type)
- {
- return self::JSON_SUBTYPES[$type] ?? null;
- }
-
- /**
- * @param mixed $value
- * @param bool $use_subtypes
- * @return null|string
- */
- public static function getJsonType($value, bool $use_subtypes = true)
- {
- $type = self::PHP_TYPE_MAP[gettype($value)] ?? null;
- if ($type === null) {
- return null;
- } elseif ($type === 'array') {
- return self::isIndexedArray($value) ? 'array' : null;
- }
-
- if ($use_subtypes) {
- if ($type === 'number' && self::isMultipleOf($value, 1)) {
- return 'integer';
- }
- } elseif ($type === 'integer') {
- return 'number';
- }
-
- return $type;
- }
-
- /**
- * @param string $type
- * @param string|string[] $allowed
- * @return bool
- */
- public static function jsonTypeMatches(string $type, $allowed): bool
- {
- if (!$allowed) {
- return false;
- }
-
- if (is_string($allowed)) {
- if ($type === $allowed) {
- return true;
- }
-
- return $allowed === self::getJsonSuperType($type);
- }
-
- if (is_array($allowed)) {
- if (in_array($type, $allowed, true)) {
- return true;
- }
-
- if ($type = self::getJsonSuperType($type)) {
- return in_array($type, $allowed, true);
- }
- }
-
- return false;
- }
-
- /**
- * @param mixed $value
- * @param string|string[] $type
- * @return bool
- */
- public static function valueIsOfJsonType($value, $type): bool
- {
- $t = self::getJsonType($value);
- if ($t === null) {
- return false;
- }
-
- return self::jsonTypeMatches($t, $type);
- }
-
- /**
- * @param array $array
- * @return bool
- */
- public static function isIndexedArray(array $array): bool
- {
- for ($i = 0, $max = count($array); $i < $max; $i++) {
- if (!array_key_exists($i, $array)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Converts assoc-arrays to objects (recursive)
- * @param scalar|object|array|null $schema
- * @return scalar|object|array|null
- */
- public static function convertAssocArrayToObject($schema)
- {
- if (is_null($schema) || is_scalar($schema)) {
- return $schema;
- }
-
- $keepArray = is_array($schema) && self::isIndexedArray($schema);
-
- $data = [];
-
- foreach ($schema as $key => $value) {
- $data[$key] = is_array($value) || is_object($value) ? self::convertAssocArrayToObject($value) : $value;
- }
-
- return $keepArray ? $data : (object) $data;
- }
-
- /**
- * @param mixed $a
- * @param mixed $b
- * @return bool
- */
- public static function equals($a, $b): bool
- {
- if ($a === $b) {
- return true;
- }
-
- $type = self::getJsonType($a, false);
- if ($type === null || $type !== self::getJsonType($b, false)) {
- return false;
- }
-
- if ($type === 'number') {
- return $a == $b;
- }
-
- if ($type === "array") {
- $count = count($a);
- if ($count !== count($b)) {
- return false;
- }
-
- for ($i = 0; $i < $count; $i++) {
- if (!array_key_exists($i, $a) || !array_key_exists($i, $b)) {
- return false;
- }
- if (!self::equals($a[$i], $b[$i])) {
- return false;
- }
- }
-
- return true;
- }
-
- if ($type === "object") {
- $a = get_object_vars($a);
- if ($a === null) {
- return false;
- }
-
- $b = get_object_vars($b);
- if ($b === null) {
- return false;
- }
-
- if (count($a) !== count($b)) {
- return false;
- }
-
- foreach ($a as $prop => $value) {
- if (!array_key_exists($prop, $b)) {
- return false;
- }
- if (!self::equals($value, $b[$prop])) {
- return false;
- }
- }
-
- return true;
- }
-
- return false;
- }
-
- /**
- * @param $number
- * @param $divisor
- * @param int $scale
- * @return bool
- */
- public static function isMultipleOf($number, $divisor, int $scale = 14): bool
- {
- static $bcMath = null;
- if ($bcMath === null) {
- $bcMath = extension_loaded('bcmath');
- }
- if ($divisor == 0) {
- return $number == 0;
- }
-
- if ($bcMath) {
- $number = number_format($number, $scale, '.', '');
- $divisor = number_format($divisor, $scale, '.', '');
-
- /** @noinspection PhpComposerExtensionStubsInspection */
- $x = bcdiv($number, $divisor, 0);
- /** @noinspection PhpComposerExtensionStubsInspection */
- $x = bcmul($divisor, $x, $scale);
- /** @noinspection PhpComposerExtensionStubsInspection */
- $x = bcsub($number, $x, $scale);
-
- /** @noinspection PhpComposerExtensionStubsInspection */
- return 0 === bccomp($x, 0, $scale);
- }
-
- $div = $number / $divisor;
-
- return $div == (int)$div;
- }
-
- /**
- * @param $value
- * @return mixed
- */
- public static function cloneValue($value)
- {
- if ($value === null || is_scalar($value)) {
- return $value;
- }
-
- if (is_array($value)) {
- return array_map(self::class . '::cloneValue', $value);
- }
-
- if (is_object($value)) {
- return (object)array_map(self::class . '::cloneValue', get_object_vars($value));
- }
-
- return null;
- }
-
- /**
- * @param string $pattern
- * @return bool
- */
- public static function isValidPattern(string $pattern): bool
- {
- if (strpos($pattern, '\Z') !== false) {
- return false;
- }
-
- return @preg_match("\x07{$pattern}\x07u", '') !== false;
- }
-
- /**
- * @param string $pattern
- * @return string
- */
- public static function patternToRegex(string $pattern): string
- {
- return "\x07{$pattern}\x07uD";
- }
-
- /**
- * @param mixed $data
- * @return mixed
- */
- public static function toJSON($data)
- {
- if ($data === null || is_scalar($data)) {
- return $data;
- }
-
- $map = [];
-
- $isArray = true;
- $index = 0;
- foreach ($data as $key => $value) {
- $map[$key] = self::toJSON($value);
- if ($isArray) {
- if ($index !== $key) {
- $isArray = false;
- } else {
- $index++;
- }
- }
- }
-
- if ($isArray) {
- if (!$map && is_object($data)) {
- return (object) $map;
- }
- return $map;
- }
-
- return (object) $map;
- }
+final class Helper {
+
+ /** @var string[] */
+ const JSON_TYPES = array( 'string', 'number', 'boolean', 'null', 'object', 'array' );
+
+ /** @var string[] */
+ const JSON_SUBTYPES = array( 'integer' => 'number' );
+
+ /** @var string[] */
+ const PHP_TYPE_MAP = array(
+ 'NULL' => 'null',
+ 'integer' => 'integer',
+ 'double' => 'number',
+ 'boolean' => 'boolean',
+ 'array' => 'array',
+ 'object' => 'object',
+ 'string' => 'string',
+ );
+
+ /**
+ * @param string $type
+ * @return bool
+ */
+ public static function isValidJsonType( string $type ): bool {
+ if ( isset( self::JSON_SUBTYPES[ $type ] ) ) {
+ return true;
+ }
+
+ return in_array( $type, self::JSON_TYPES, true );
+ }
+
+ /**
+ * @param string $type
+ * @return null|string
+ */
+ public static function getJsonSuperType( string $type ) {
+ return self::JSON_SUBTYPES[ $type ] ?? null;
+ }
+
+ /**
+ * @param mixed $value
+ * @param bool $use_subtypes
+ * @return null|string
+ */
+ public static function getJsonType( $value, bool $use_subtypes = true ) {
+ $type = self::PHP_TYPE_MAP[ gettype( $value ) ] ?? null;
+ if ( $type === null ) {
+ return null;
+ } elseif ( $type === 'array' ) {
+ return self::isIndexedArray( $value ) ? 'array' : null;
+ }
+
+ if ( $use_subtypes ) {
+ if ( $type === 'number' && self::isMultipleOf( $value, 1 ) ) {
+ return 'integer';
+ }
+ } elseif ( $type === 'integer' ) {
+ return 'number';
+ }
+
+ return $type;
+ }
+
+ /**
+ * @param string $type
+ * @param string|string[] $allowed
+ * @return bool
+ */
+ public static function jsonTypeMatches( string $type, $allowed ): bool {
+ if ( ! $allowed ) {
+ return false;
+ }
+
+ if ( is_string( $allowed ) ) {
+ if ( $type === $allowed ) {
+ return true;
+ }
+
+ return $allowed === self::getJsonSuperType( $type );
+ }
+
+ if ( is_array( $allowed ) ) {
+ if ( in_array( $type, $allowed, true ) ) {
+ return true;
+ }
+
+ if ( $type = self::getJsonSuperType( $type ) ) {
+ return in_array( $type, $allowed, true );
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param mixed $value
+ * @param string|string[] $type
+ * @return bool
+ */
+ public static function valueIsOfJsonType( $value, $type ): bool {
+ $t = self::getJsonType( $value );
+ if ( $t === null ) {
+ return false;
+ }
+
+ return self::jsonTypeMatches( $t, $type );
+ }
+
+ /**
+ * @param array $array
+ * @return bool
+ */
+ public static function isIndexedArray( array $array ): bool {
+ for ( $i = 0, $max = count( $array ); $i < $max; $i++ ) {
+ if ( ! array_key_exists( $i, $array ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Converts assoc-arrays to objects (recursive)
+ *
+ * @param scalar|object|array|null $schema
+ * @return scalar|object|array|null
+ */
+ public static function convertAssocArrayToObject( $schema ) {
+ if ( is_null( $schema ) || is_scalar( $schema ) ) {
+ return $schema;
+ }
+
+ $keepArray = is_array( $schema ) && self::isIndexedArray( $schema );
+
+ $data = array();
+
+ foreach ( $schema as $key => $value ) {
+ $data[ $key ] = is_array( $value ) || is_object( $value ) ? self::convertAssocArrayToObject( $value ) : $value;
+ }
+
+ return $keepArray ? $data : (object) $data;
+ }
+
+ /**
+ * @param mixed $a
+ * @param mixed $b
+ * @return bool
+ */
+ public static function equals( $a, $b ): bool {
+ if ( $a === $b ) {
+ return true;
+ }
+
+ $type = self::getJsonType( $a, false );
+ if ( $type === null || $type !== self::getJsonType( $b, false ) ) {
+ return false;
+ }
+
+ if ( $type === 'number' ) {
+ return $a == $b;
+ }
+
+ if ( $type === 'array' ) {
+ $count = count( $a );
+ if ( $count !== count( $b ) ) {
+ return false;
+ }
+
+ for ( $i = 0; $i < $count; $i++ ) {
+ if ( ! array_key_exists( $i, $a ) || ! array_key_exists( $i, $b ) ) {
+ return false;
+ }
+ if ( ! self::equals( $a[ $i ], $b[ $i ] ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ if ( $type === 'object' ) {
+ $a = get_object_vars( $a );
+ if ( $a === null ) {
+ return false;
+ }
+
+ $b = get_object_vars( $b );
+ if ( $b === null ) {
+ return false;
+ }
+
+ if ( count( $a ) !== count( $b ) ) {
+ return false;
+ }
+
+ foreach ( $a as $prop => $value ) {
+ if ( ! array_key_exists( $prop, $b ) ) {
+ return false;
+ }
+ if ( ! self::equals( $value, $b[ $prop ] ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param $number
+ * @param $divisor
+ * @param int $scale
+ * @return bool
+ */
+ public static function isMultipleOf( $number, $divisor, int $scale = 14 ): bool {
+ static $bcMath = null;
+ if ( $bcMath === null ) {
+ $bcMath = extension_loaded( 'bcmath' );
+ }
+ if ( $divisor == 0 ) {
+ return $number == 0;
+ }
+
+ if ( $bcMath ) {
+ $number = number_format( $number, $scale, '.', '' );
+ $divisor = number_format( $divisor, $scale, '.', '' );
+
+ /** @noinspection PhpComposerExtensionStubsInspection */
+ $x = bcdiv( $number, $divisor, 0 );
+ /** @noinspection PhpComposerExtensionStubsInspection */
+ $x = bcmul( $divisor, $x, $scale );
+ /** @noinspection PhpComposerExtensionStubsInspection */
+ $x = bcsub( $number, $x, $scale );
+
+ /** @noinspection PhpComposerExtensionStubsInspection */
+ return 0 === bccomp( $x, 0, $scale );
+ }
+
+ $div = $number / $divisor;
+
+ return $div == (int) $div;
+ }
+
+ /**
+ * @param $value
+ * @return mixed
+ */
+ public static function cloneValue( $value ) {
+ if ( $value === null || is_scalar( $value ) ) {
+ return $value;
+ }
+
+ if ( is_array( $value ) ) {
+ return array_map( self::class . '::cloneValue', $value );
+ }
+
+ if ( is_object( $value ) ) {
+ return (object) array_map( self::class . '::cloneValue', get_object_vars( $value ) );
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $pattern
+ * @return bool
+ */
+ public static function isValidPattern( string $pattern ): bool {
+ if ( strpos( $pattern, '\Z' ) !== false ) {
+ return false;
+ }
+
+ return @preg_match( "\x07{$pattern}\x07u", '' ) !== false;
+ }
+
+ /**
+ * @param string $pattern
+ * @return string
+ */
+ public static function patternToRegex( string $pattern ): string {
+ return "\x07{$pattern}\x07uD";
+ }
+
+ /**
+ * @param mixed $data
+ * @return mixed
+ */
+ public static function toJSON( $data ) {
+ if ( $data === null || is_scalar( $data ) ) {
+ return $data;
+ }
+
+ $map = array();
+
+ $isArray = true;
+ $index = 0;
+ foreach ( $data as $key => $value ) {
+ $map[ $key ] = self::toJSON( $value );
+ if ( $isArray ) {
+ if ( $index !== $key ) {
+ $isArray = false;
+ } else {
+ ++$index;
+ }
+ }
+ }
+
+ if ( $isArray ) {
+ if ( ! $map && is_object( $data ) ) {
+ return (object) $map;
+ }
+ return $map;
+ }
+
+ return (object) $map;
+ }
}
diff --git a/src/opis/json-schema/src/Info/DataInfo.php b/src/opis/json-schema/src/Info/DataInfo.php
index d2560ab0..fb28b87c 100644
--- a/src/opis/json-schema/src/Info/DataInfo.php
+++ b/src/opis/json-schema/src/Info/DataInfo.php
@@ -1,5 +1,6 @@
value = $value;
- $this->type = $type;
- $this->root = $root;
- $this->path = $path;
- $this->parent = $parent;
- }
-
- public function value()
- {
- return $this->value;
- }
-
- public function type()
- {
- return $this->type;
- }
-
- public function root()
- {
- return $this->root;
- }
-
- /**
- * @return int[]|string[]
- */
- public function path(): array
- {
- return $this->path;
- }
-
- public function parent()
- {
- return $this->parent;
- }
-
- /**
- * @return int[]|string[]
- */
- public function fullPath(): array
- {
- if ($this->parent === null) {
- return $this->path;
- }
-
- if ($this->fullPath === null) {
- $this->fullPath = array_merge($this->parent->fullPath(), $this->path);
- }
-
- return $this->fullPath;
- }
-
- /**
- * @param ValidationContext $context
- * @return static
- */
- public static function fromContext($context): self
- {
- if ($parent = $context->parent()) {
- $parent = self::fromContext($parent);
- }
-
- return new self($context->currentData(), $context->currentDataType(), $context->rootData(),
- $context->currentDataPath(), $parent);
- }
+class DataInfo {
+
+ /** @var mixed */
+ protected $value;
+
+ /**
+ * @var string|null
+ */
+ protected $type;
+
+ /** @var mixed */
+ protected $root;
+
+ /** @var string[]|int[] */
+ protected $path;
+
+ /**
+ * @var \Opis\JsonSchema\Info\DataInfo|null
+ */
+ protected $parent;
+
+ /** @var string[]|int[]|null */
+ protected $fullPath;
+
+ /**
+ * DataInfo constructor.
+ *
+ * @param $value
+ * @param string|null $type
+ * @param $root
+ * @param string[]|int[] $path
+ * @param DataInfo|null $parent
+ */
+ public function __construct( $value, $type, $root, array $path = array(), $parent = null ) {
+ $this->value = $value;
+ $this->type = $type;
+ $this->root = $root;
+ $this->path = $path;
+ $this->parent = $parent;
+ }
+
+ public function value() {
+ return $this->value;
+ }
+
+ public function type() {
+ return $this->type;
+ }
+
+ public function root() {
+ return $this->root;
+ }
+
+ /**
+ * @return int[]|string[]
+ */
+ public function path(): array {
+ return $this->path;
+ }
+
+ public function parent() {
+ return $this->parent;
+ }
+
+ /**
+ * @return int[]|string[]
+ */
+ public function fullPath(): array {
+ if ( $this->parent === null ) {
+ return $this->path;
+ }
+
+ if ( $this->fullPath === null ) {
+ $this->fullPath = array_merge( $this->parent->fullPath(), $this->path );
+ }
+
+ return $this->fullPath;
+ }
+
+ /**
+ * @param ValidationContext $context
+ * @return static
+ */
+ public static function fromContext( $context ): self {
+ if ( $parent = $context->parent() ) {
+ $parent = self::fromContext( $parent );
+ }
+
+ return new self(
+ $context->currentData(),
+ $context->currentDataType(),
+ $context->rootData(),
+ $context->currentDataPath(),
+ $parent
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Info/SchemaInfo.php b/src/opis/json-schema/src/Info/SchemaInfo.php
index fb381403..ec7a116e 100644
--- a/src/opis/json-schema/src/Info/SchemaInfo.php
+++ b/src/opis/json-schema/src/Info/SchemaInfo.php
@@ -1,5 +1,6 @@
data = $data;
- $this->id = $id;
- $this->root = $root;
- $this->base = $base;
- $this->path = $path;
- $this->draft = $draft;
- }
-
- public function id()
- {
- return $this->id;
- }
-
- public function root()
- {
- return $this->root;
- }
-
- public function base()
- {
- return $this->base;
- }
-
- public function draft()
- {
- return $this->draft;
- }
-
- public function data()
- {
- return $this->data;
- }
-
- public function path(): array
- {
- return $this->path;
- }
-
- /**
- * Returns first non-null property: id, base or root
- * @return Uri|null
- */
- public function idBaseRoot()
- {
- return $this->id ?? $this->base ?? $this->root;
- }
-
- public function isBoolean(): bool
- {
- return is_bool($this->data);
- }
-
- public function isObject(): bool
- {
- return is_object($this->data);
- }
-
- public function isDocumentRoot(): bool
- {
- return $this->id && !$this->root && !$this->base;
- }
+class SchemaInfo {
+
+ /** @var bool|object */
+ protected $data;
+
+ /**
+ * @var \Opis\JsonSchema\Uri|null
+ */
+ protected $id;
+
+ /**
+ * @var \Opis\JsonSchema\Uri|null
+ */
+ protected $root;
+
+ /**
+ * @var \Opis\JsonSchema\Uri|null
+ */
+ protected $base;
+
+ /** @var string[]|int[] */
+ protected $path;
+
+ /**
+ * @var string|null
+ */
+ protected $draft;
+
+ /**
+ * @param object|bool $data
+ * @param Uri|null $id
+ * @param Uri|null $base
+ * @param Uri|null $root
+ * @param string[]|int[] $path
+ * @param string|null $draft
+ */
+ public function __construct( $data, $id, $base = null, $root = null, array $path = array(), $draft = null ) {
+ if ( $root === $id || ( (string) $root === (string) $id ) ) {
+ $root = null;
+ }
+
+ if ( $root === null ) {
+ $base = null;
+ }
+
+ $this->data = $data;
+ $this->id = $id;
+ $this->root = $root;
+ $this->base = $base;
+ $this->path = $path;
+ $this->draft = $draft;
+ }
+
+ public function id() {
+ return $this->id;
+ }
+
+ public function root() {
+ return $this->root;
+ }
+
+ public function base() {
+ return $this->base;
+ }
+
+ public function draft() {
+ return $this->draft;
+ }
+
+ public function data() {
+ return $this->data;
+ }
+
+ public function path(): array {
+ return $this->path;
+ }
+
+ /**
+ * Returns first non-null property: id, base or root
+ *
+ * @return Uri|null
+ */
+ public function idBaseRoot() {
+ return $this->id ?? $this->base ?? $this->root;
+ }
+
+ public function isBoolean(): bool {
+ return is_bool( $this->data );
+ }
+
+ public function isObject(): bool {
+ return is_object( $this->data );
+ }
+
+ public function isDocumentRoot(): bool {
+ return $this->id && ! $this->root && ! $this->base;
+ }
}
diff --git a/src/opis/json-schema/src/JsonPointer.php b/src/opis/json-schema/src/JsonPointer.php
index f9baa545..d79e174a 100644
--- a/src/opis/json-schema/src/JsonPointer.php
+++ b/src/opis/json-schema/src/JsonPointer.php
@@ -1,5 +1,6 @@
0|[1-9][0-9]*)(?(?:\+|-)(?:0|[1-9][0-9]*))?)?(?(?:/[^/#]*)*)(?#)?$~';
-
- /** @var string */
- const UNESCAPED = '/~([^01]|$)/';
-
- /**
- * @var int
- */
- protected $level = -1;
-
- /**
- * @var int
- */
- protected $shift = 0;
-
- /**
- * @var bool
- */
- protected $fragment = false;
-
- /** @var string[]|int[] */
- protected $path;
-
- /**
- * @var string|null
- */
- protected $str;
-
- final protected function __construct(array $path, int $level = -1, int $shift = 0, bool $fragment = false)
- {
- $this->path = $path;
- $this->level = $level < 0 ? -1 : $level;
- $this->shift = $shift;
- $this->fragment = $level >= 0 && $fragment;
- }
-
- public function isRelative(): bool
- {
- return $this->level >= 0;
- }
-
- public function isAbsolute(): bool
- {
- return $this->level < 0;
- }
-
- public function level(): int
- {
- return $this->level;
- }
-
- public function shift(): int
- {
- return $this->shift;
- }
-
- /**
- * @return string[]
- */
- public function path(): array
- {
- return $this->path;
- }
-
- /**
- * @return bool
- */
- public function hasFragment(): bool
- {
- return $this->fragment;
- }
-
- /**
- * @return string
- */
- public function __toString(): string
- {
- if ($this->str === null) {
- if ($this->level >= 0) {
- $this->str = (string)$this->level;
-
- if ($this->shift !== 0) {
- if ($this->shift > 0) {
- $this->str .= '+';
- }
- $this->str .= $this->shift;
- }
-
- if ($this->path) {
- $this->str .= '/';
- $this->str .= implode('/', self::encodePath($this->path));
- }
-
- if ($this->fragment) {
- $this->str .= '#';
- }
- } else {
- $this->str = '/';
- $this->str .= implode('/', self::encodePath($this->path));
- }
- }
-
- return $this->str;
- }
-
- /**
- * @param $data
- * @param array|null $path
- * @param null $default
- * @return mixed
- */
- public function data($data, $path = null, $default = null)
- {
- if ($this->level < 0) {
- return self::getData($data, $this->path, false, $default);
- }
-
- if ($path !== null) {
- $path = $this->absolutePath($path);
- }
-
- if ($path === null) {
- return $default;
- }
-
- return self::getData($data, $path, $this->fragment, $default);
- }
-
- /**
- * @param array $path
- * @return array|null
- */
- public function absolutePath($path = [])
- {
- if ($this->level < 0) {
- // Absolute pointer
- return $this->path;
- }
-
- if ($this->level === 0) {
- if ($this->shift && !$this->handleShift($path)) {
- return null;
- }
- return $this->path ? array_merge($path, $this->path) : $path;
- }
-
- $count = count($path);
- if ($count === $this->level) {
- if ($this->shift) {
- return null;
- }
- return $this->path;
- }
-
- if ($count > $this->level) {
- $count -= $this->level;
-
- /** @var array $path */
- $path = array_slice($path, 0, $count);
-
- if ($this->shift && !$this->handleShift($path, $count)) {
- return null;
- }
-
- return $this->path ? array_merge($path, $this->path) : $path;
- }
-
- return null;
- }
-
- /**
- * @param mixed[] $path
- * @param int|null $count
- */
- protected function handleShift(&$path, $count = null): bool
- {
- if (!$path) {
- return false;
- }
-
- $count = $count ?? count($path);
-
- $last = $path[$count - 1];
-
- if (is_string($last) && preg_match('/^[1-9]\d*$/', $last)) {
- $last = (int) $last;
- }
-
- if (!is_int($last)) {
- return false;
- }
-
- $path[$count - 1] = $last + $this->shift;
-
- return true;
- }
-
- /**
- * @param string $pointer
- * @param bool $decode
- */
- public static function parse($pointer, $decode = true)
- {
- if ($pointer === '' || !preg_match(self::PATTERN, $pointer, $m)) {
- // Not a pointer
- return null;
- }
-
- $pointer = $m['pointer'] ?? null;
-
- // Check if the pointer is escaped
- if ($decode && $pointer && preg_match(self::UNESCAPED, $pointer)) {
- // Invalid pointer
- return null;
- }
-
- $level = isset($m['level']) && $m['level'] !== ''
- ? (int)$m['level']
- : -1;
-
- $shift = 0;
- if ($level >= 0 && isset($m['shift']) && $m['shift'] !== '') {
- $shift = (int) $m['shift'];
- }
-
- $fragment = isset($m['fragment']) && $m['fragment'] === '#';
- unset($m);
-
- if ($fragment && $level < 0) {
- return null;
- }
-
- if ($pointer === '') {
- $pointer = null;
- } elseif ($pointer !== null) {
- // Remove leading slash
- $pointer = substr($pointer, 1);
-
- if ($pointer !== '') {
- $pointer = self::decodePath(explode('/', $pointer));
- } else {
- $pointer = null;
- }
- }
-
- return new self($pointer ?? [], $level, $shift, $fragment);
- }
-
- /**
- * @param $data
- * @param array|null $path
- * @param bool $fragment
- * @param null $default
- * @return mixed
- */
- public static function getData($data, $path = null, $fragment = false, $default = null)
- {
- if ($path === null) {
- return $default;
- }
-
- if (!$path) {
- return $fragment ? $default : $data;
- }
-
- if ($fragment) {
- return end($path);
- }
-
- foreach ($path as $key) {
- if (is_array($data)) {
- if (!array_key_exists($key, $data)) {
- return $default;
- }
- $data = $data[$key];
- } elseif (is_object($data)) {
- if (!property_exists($data, $key)) {
- return $default;
- }
- $data = $data->{$key};
- } else {
- return $default;
- }
- }
-
- return $data;
- }
-
- /**
- * @param string|string[] $path
- * @return string|string[]
- */
- public static function encodePath($path)
- {
- $path = str_replace('~', '~0', $path);
- $path = str_replace('/', '~1', $path);
-
- if (is_array($path)) {
- return array_map('rawurlencode', $path);
- }
-
- return rawurlencode($path);
- }
-
- /**
- * @param string|string[] $path
- * @return string|string[]
- */
- public static function decodePath($path)
- {
- if (is_array($path)) {
- $path = array_map('rawurldecode', $path);
- } else {
- $path = rawurldecode($path);
- }
-
- $path = str_replace('~1', '/', $path);
- $path = str_replace('~0', '~', $path);
-
- return $path;
- }
-
- /**
- * @param array $path
- * @return string
- */
- public static function pathToString($path): string
- {
- if (!$path) {
- return '/';
- }
-
- return '/' . implode('/', self::encodePath($path));
- }
-
- /**
- * @param array $path
- * @return string
- */
- public static function pathToFragment($path): string
- {
- if (!$path) {
- return '#';
- }
-
- return '#/' . implode('/', self::encodePath($path));
- }
-
- /**
- * @param string $pointer
- * @return bool
- */
- public static function isAbsolutePointer($pointer): bool
- {
- if ($pointer === '/') {
- return true;
- }
-
- if (!preg_match(self::PATTERN, $pointer, $m)) {
- return false;
- }
-
- if (isset($m['fragment']) || isset($m['level']) && $m['level'] !== '') {
- return false;
- }
-
- if (!isset($m['pointer']) || $m['pointer'] === '') {
- return true;
- }
-
- return !preg_match(self::UNESCAPED, $m['pointer']);
- }
-
- /**
- * @param string $pointer
- * @return bool
- */
- public static function isRelativePointer($pointer): bool
- {
- if ($pointer === '') {
- return false;
- }
-
- if (!preg_match(self::PATTERN, $pointer, $m)) {
- return false;
- }
-
- if (!isset($m['level']) || $m['level'] === '' || (int)$m['level'] < 0) {
- return false;
- }
-
- if (!isset($m['pointer']) || $m['pointer'] === '') {
- return true;
- }
-
- return !preg_match(self::UNESCAPED, $m['pointer']);
- }
-
- /**
- * @param mixed[] $path
- */
- public static function createAbsolute($path): self
- {
- return new self($path, -1, 0, false);
- }
-
- /**
- * @param int $level
- * @param mixed[] $path
- * @param int $shift
- * @param bool $fragment
- */
- public static function createRelative($level, $path = [], $shift = 0, $fragment = false): self
- {
- return new self($path, $level, $shift, $fragment);
- }
+final class JsonPointer {
+
+ /** @var string */
+ const PATTERN = '~^(?:(?0|[1-9][0-9]*)(?(?:\+|-)(?:0|[1-9][0-9]*))?)?(?(?:/[^/#]*)*)(?#)?$~';
+
+ /** @var string */
+ const UNESCAPED = '/~([^01]|$)/';
+
+ /**
+ * @var int
+ */
+ protected $level = -1;
+
+ /**
+ * @var int
+ */
+ protected $shift = 0;
+
+ /**
+ * @var bool
+ */
+ protected $fragment = false;
+
+ /** @var string[]|int[] */
+ protected $path;
+
+ /**
+ * @var string|null
+ */
+ protected $str;
+
+ final protected function __construct( array $path, int $level = -1, int $shift = 0, bool $fragment = false ) {
+ $this->path = $path;
+ $this->level = $level < 0 ? -1 : $level;
+ $this->shift = $shift;
+ $this->fragment = $level >= 0 && $fragment;
+ }
+
+ public function isRelative(): bool {
+ return $this->level >= 0;
+ }
+
+ public function isAbsolute(): bool {
+ return $this->level < 0;
+ }
+
+ public function level(): int {
+ return $this->level;
+ }
+
+ public function shift(): int {
+ return $this->shift;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function path(): array {
+ return $this->path;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasFragment(): bool {
+ return $this->fragment;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString(): string {
+ if ( $this->str === null ) {
+ if ( $this->level >= 0 ) {
+ $this->str = (string) $this->level;
+
+ if ( $this->shift !== 0 ) {
+ if ( $this->shift > 0 ) {
+ $this->str .= '+';
+ }
+ $this->str .= $this->shift;
+ }
+
+ if ( $this->path ) {
+ $this->str .= '/';
+ $this->str .= implode( '/', self::encodePath( $this->path ) );
+ }
+
+ if ( $this->fragment ) {
+ $this->str .= '#';
+ }
+ } else {
+ $this->str = '/';
+ $this->str .= implode( '/', self::encodePath( $this->path ) );
+ }
+ }
+
+ return $this->str;
+ }
+
+ /**
+ * @param $data
+ * @param array|null $path
+ * @param null $default
+ * @return mixed
+ */
+ public function data( $data, $path = null, $default = null ) {
+ if ( $this->level < 0 ) {
+ return self::getData( $data, $this->path, false, $default );
+ }
+
+ if ( $path !== null ) {
+ $path = $this->absolutePath( $path );
+ }
+
+ if ( $path === null ) {
+ return $default;
+ }
+
+ return self::getData( $data, $path, $this->fragment, $default );
+ }
+
+ /**
+ * @param array $path
+ * @return array|null
+ */
+ public function absolutePath( $path = array() ) {
+ if ( $this->level < 0 ) {
+ // Absolute pointer
+ return $this->path;
+ }
+
+ if ( $this->level === 0 ) {
+ if ( $this->shift && ! $this->handleShift( $path ) ) {
+ return null;
+ }
+ return $this->path ? array_merge( $path, $this->path ) : $path;
+ }
+
+ $count = count( $path );
+ if ( $count === $this->level ) {
+ if ( $this->shift ) {
+ return null;
+ }
+ return $this->path;
+ }
+
+ if ( $count > $this->level ) {
+ $count -= $this->level;
+
+ /** @var array $path */
+ $path = array_slice( $path, 0, $count );
+
+ if ( $this->shift && ! $this->handleShift( $path, $count ) ) {
+ return null;
+ }
+
+ return $this->path ? array_merge( $path, $this->path ) : $path;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param mixed[] $path
+ * @param int|null $count
+ */
+ protected function handleShift( &$path, $count = null ): bool {
+ if ( ! $path ) {
+ return false;
+ }
+
+ $count = $count ?? count( $path );
+
+ $last = $path[ $count - 1 ];
+
+ if ( is_string( $last ) && preg_match( '/^[1-9]\d*$/', $last ) ) {
+ $last = (int) $last;
+ }
+
+ if ( ! is_int( $last ) ) {
+ return false;
+ }
+
+ $path[ $count - 1 ] = $last + $this->shift;
+
+ return true;
+ }
+
+ /**
+ * @param string $pointer
+ * @param bool $decode
+ */
+ public static function parse( $pointer, $decode = true ) {
+ if ( $pointer === '' || ! preg_match( self::PATTERN, $pointer, $m ) ) {
+ // Not a pointer
+ return null;
+ }
+
+ $pointer = $m['pointer'] ?? null;
+
+ // Check if the pointer is escaped
+ if ( $decode && $pointer && preg_match( self::UNESCAPED, $pointer ) ) {
+ // Invalid pointer
+ return null;
+ }
+
+ $level = isset( $m['level'] ) && $m['level'] !== ''
+ ? (int) $m['level']
+ : -1;
+
+ $shift = 0;
+ if ( $level >= 0 && isset( $m['shift'] ) && $m['shift'] !== '' ) {
+ $shift = (int) $m['shift'];
+ }
+
+ $fragment = isset( $m['fragment'] ) && $m['fragment'] === '#';
+ unset( $m );
+
+ if ( $fragment && $level < 0 ) {
+ return null;
+ }
+
+ if ( $pointer === '' ) {
+ $pointer = null;
+ } elseif ( $pointer !== null ) {
+ // Remove leading slash
+ $pointer = substr( $pointer, 1 );
+
+ if ( $pointer !== '' ) {
+ $pointer = self::decodePath( explode( '/', $pointer ) );
+ } else {
+ $pointer = null;
+ }
+ }
+
+ return new self( $pointer ?? array(), $level, $shift, $fragment );
+ }
+
+ /**
+ * @param $data
+ * @param array|null $path
+ * @param bool $fragment
+ * @param null $default
+ * @return mixed
+ */
+ public static function getData( $data, $path = null, $fragment = false, $default = null ) {
+ if ( $path === null ) {
+ return $default;
+ }
+
+ if ( ! $path ) {
+ return $fragment ? $default : $data;
+ }
+
+ if ( $fragment ) {
+ return end( $path );
+ }
+
+ foreach ( $path as $key ) {
+ if ( is_array( $data ) ) {
+ if ( ! array_key_exists( $key, $data ) ) {
+ return $default;
+ }
+ $data = $data[ $key ];
+ } elseif ( is_object( $data ) ) {
+ if ( ! property_exists( $data, $key ) ) {
+ return $default;
+ }
+ $data = $data->{$key};
+ } else {
+ return $default;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * @param string|string[] $path
+ * @return string|string[]
+ */
+ public static function encodePath( $path ) {
+ $path = str_replace( '~', '~0', $path );
+ $path = str_replace( '/', '~1', $path );
+
+ if ( is_array( $path ) ) {
+ return array_map( 'rawurlencode', $path );
+ }
+
+ return rawurlencode( $path );
+ }
+
+ /**
+ * @param string|string[] $path
+ * @return string|string[]
+ */
+ public static function decodePath( $path ) {
+ if ( is_array( $path ) ) {
+ $path = array_map( 'rawurldecode', $path );
+ } else {
+ $path = rawurldecode( $path );
+ }
+
+ $path = str_replace( '~1', '/', $path );
+ $path = str_replace( '~0', '~', $path );
+
+ return $path;
+ }
+
+ /**
+ * @param array $path
+ * @return string
+ */
+ public static function pathToString( $path ): string {
+ if ( ! $path ) {
+ return '/';
+ }
+
+ return '/' . implode( '/', self::encodePath( $path ) );
+ }
+
+ /**
+ * @param array $path
+ * @return string
+ */
+ public static function pathToFragment( $path ): string {
+ if ( ! $path ) {
+ return '#';
+ }
+
+ return '#/' . implode( '/', self::encodePath( $path ) );
+ }
+
+ /**
+ * @param string $pointer
+ * @return bool
+ */
+ public static function isAbsolutePointer( $pointer ): bool {
+ if ( $pointer === '/' ) {
+ return true;
+ }
+
+ if ( ! preg_match( self::PATTERN, $pointer, $m ) ) {
+ return false;
+ }
+
+ if ( isset( $m['fragment'] ) || isset( $m['level'] ) && $m['level'] !== '' ) {
+ return false;
+ }
+
+ if ( ! isset( $m['pointer'] ) || $m['pointer'] === '' ) {
+ return true;
+ }
+
+ return ! preg_match( self::UNESCAPED, $m['pointer'] );
+ }
+
+ /**
+ * @param string $pointer
+ * @return bool
+ */
+ public static function isRelativePointer( $pointer ): bool {
+ if ( $pointer === '' ) {
+ return false;
+ }
+
+ if ( ! preg_match( self::PATTERN, $pointer, $m ) ) {
+ return false;
+ }
+
+ if ( ! isset( $m['level'] ) || $m['level'] === '' || (int) $m['level'] < 0 ) {
+ return false;
+ }
+
+ if ( ! isset( $m['pointer'] ) || $m['pointer'] === '' ) {
+ return true;
+ }
+
+ return ! preg_match( self::UNESCAPED, $m['pointer'] );
+ }
+
+ /**
+ * @param mixed[] $path
+ */
+ public static function createAbsolute( $path ): self {
+ return new self( $path, -1, 0, false );
+ }
+
+ /**
+ * @param int $level
+ * @param mixed[] $path
+ * @param int $shift
+ * @param bool $fragment
+ */
+ public static function createRelative( $level, $path = array(), $shift = 0, $fragment = false ): self {
+ return new self( $path, $level, $shift, $fragment );
+ }
}
diff --git a/src/opis/json-schema/src/Keyword.php b/src/opis/json-schema/src/Keyword.php
index 3fd9acb0..3c63c39e 100644
--- a/src/opis/json-schema/src/Keyword.php
+++ b/src/opis/json-schema/src/Keyword.php
@@ -1,5 +1,6 @@
next;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\KeywordValidator|null $next
- */
- public function setNext($next): KeywordValidator
- {
- $this->next = $next;
-
- return $this;
- }
+abstract class AbstractKeywordValidator implements KeywordValidator {
+
+
+ /**
+ * @var \Opis\JsonSchema\KeywordValidator|null
+ */
+ protected $next;
+
+ /**
+ * @inheritDoc
+ */
+ public function next() {
+ return $this->next;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\KeywordValidator|null $next
+ */
+ public function setNext( $next ): KeywordValidator {
+ $this->next = $next;
+
+ return $this;
+ }
}
diff --git a/src/opis/json-schema/src/KeywordValidators/CallbackKeywordValidator.php b/src/opis/json-schema/src/KeywordValidators/CallbackKeywordValidator.php
index 4d20d6ea..6e6703af 100644
--- a/src/opis/json-schema/src/KeywordValidators/CallbackKeywordValidator.php
+++ b/src/opis/json-schema/src/KeywordValidators/CallbackKeywordValidator.php
@@ -1,5 +1,6 @@
callback = $callback;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function validate($context)
- {
- return ($this->callback)($context);
- }
-
- /**
- * @inheritDoc
- */
- public function next()
- {
- return null;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\KeywordValidator|null $next
- */
- public function setNext($next): KeywordValidator
- {
- return $this;
- }
+final class CallbackKeywordValidator implements KeywordValidator {
+
+ /** @var callable */
+ private $callback;
+
+ /**
+ * @param callable $callback
+ */
+ public function __construct( callable $callback ) {
+ $this->callback = $callback;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function validate( $context ) {
+ return ( $this->callback )( $context );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function next() {
+ return null;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\KeywordValidator|null $next
+ */
+ public function setNext( $next ): KeywordValidator {
+ return $this;
+ }
}
diff --git a/src/opis/json-schema/src/KeywordValidators/PragmaKeywordValidator.php b/src/opis/json-schema/src/KeywordValidators/PragmaKeywordValidator.php
index 5613c92a..f0992b69 100644
--- a/src/opis/json-schema/src/KeywordValidators/PragmaKeywordValidator.php
+++ b/src/opis/json-schema/src/KeywordValidators/PragmaKeywordValidator.php
@@ -1,5 +1,6 @@
pragmas = $pragmas;
- }
+ /** @var Pragma[] */
+ protected $pragmas = array();
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function validate($context)
- {
- if (!$this->next) {
- return null;
- }
+ /**
+ * @param Pragma[] $pragmas
+ */
+ public function __construct( array $pragmas ) {
+ $this->pragmas = $pragmas;
+ }
- if (!$this->pragmas) {
- return $this->next->validate($context);
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function validate( $context ) {
+ if ( ! $this->next ) {
+ return null;
+ }
- $data = [];
+ if ( ! $this->pragmas ) {
+ return $this->next->validate( $context );
+ }
- foreach ($this->pragmas as $key => $handler) {
- $data[$key] = $handler->enter($context);
- }
+ $data = array();
- $error = $this->next->validate($context);
+ foreach ( $this->pragmas as $key => $handler ) {
+ $data[ $key ] = $handler->enter( $context );
+ }
- foreach (array_reverse($this->pragmas, true) as $key => $handler) {
- $handler->leave($context, $data[$key] ?? null);
- }
+ $error = $this->next->validate( $context );
- return $error;
- }
+ foreach ( array_reverse( $this->pragmas, true ) as $key => $handler ) {
+ $handler->leave( $context, $data[ $key ] ?? null );
+ }
+
+ return $error;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/AbstractRefKeyword.php b/src/opis/json-schema/src/Keywords/AbstractRefKeyword.php
index 29ea1674..c6a35370 100644
--- a/src/opis/json-schema/src/Keywords/AbstractRefKeyword.php
+++ b/src/opis/json-schema/src/Keywords/AbstractRefKeyword.php
@@ -1,5 +1,6 @@
mapper = $mapper;
- $this->globals = $globals;
- $this->slots = $slots;
- $this->keyword = $keyword;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($error = $this->doValidate($context, $schema)) {
- $uri = $this->lastRefUri;
- $this->lastRefUri = null;
-
- return $this->error($schema, $context, $this->keyword, 'The data must match {keyword}', [
- 'keyword' => $this->keyword,
- 'uri' => (string) $uri,
- ], $error);
- }
-
- $this->lastRefUri = null;
-
- return null;
- }
-
-
- /**
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- abstract protected function doValidate($context, $schema);
-
- /**
- * @param \Opis\JsonSchema\Uri|null $uri
- */
- protected function setLastRefUri($uri)
- {
- $this->lastRefUri = $uri;
- }
-
- /**
- * @param \Opis\JsonSchema\Schema $schema
- */
- protected function setLastRefSchema($schema)
- {
- $info = $schema->info();
-
- if ($info->id()) {
- $this->lastRefUri = $info->id();
- } else {
- $this->lastRefUri = Uri::merge(JsonPointer::pathToFragment($info->path()), $info->idBaseRoot());
- }
- }
-
- /**
- * @param ValidationContext $context
- * @param Schema $schema
- * @return ValidationContext
- */
- protected function createContext($context, $schema): ValidationContext
- {
- return $context->create($schema, $this->mapper, $this->globals, $this->slots);
- }
-
- /**
- * @param SchemaLoader $repo
- * @param JsonPointer $pointer
- * @param Uri $base
- * @param array|null $path
- * @return null|Schema
- */
- protected function resolvePointer($repo, $pointer,
- $base, $path = null)
- {
- if ($pointer->isAbsolute()) {
- $path = (string)$pointer;
- } else {
- if ($pointer->hasFragment()) {
- return null;
- }
-
- $path = $path ? $pointer->absolutePath($path) : $pointer->path();
- if ($path === null) {
- return null;
- }
-
- $path = JsonPointer::pathToString($path);
- }
-
- return $repo->loadSchemaById(Uri::merge('#' . $path, $base));
- }
+ JsonPointer,
+ Keyword,
+ Schema,
+ SchemaLoader,
+ Uri,
+ ValidationContext,
+ Variables};
+
+abstract class AbstractRefKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var string
+ */
+ protected $keyword;
+ /**
+ * @var \Opis\JsonSchema\Variables|null
+ */
+ protected $mapper;
+ /**
+ * @var \Opis\JsonSchema\Variables|null
+ */
+ protected $globals;
+ /**
+ * @var mixed[]|null
+ */
+ protected $slots;
+ /**
+ * @var \Opis\JsonSchema\Uri|null
+ */
+ protected $lastRefUri;
+
+ /**
+ * @param Variables|null $mapper
+ * @param Variables|null $globals
+ * @param array|null $slots
+ * @param string $keyword
+ */
+ protected function __construct( $mapper, $globals, $slots = null, string $keyword = '$ref' ) {
+ $this->mapper = $mapper;
+ $this->globals = $globals;
+ $this->slots = $slots;
+ $this->keyword = $keyword;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $error = $this->doValidate( $context, $schema ) ) {
+ $uri = $this->lastRefUri;
+ $this->lastRefUri = null;
+
+ return $this->error(
+ $schema,
+ $context,
+ $this->keyword,
+ 'The data must match {keyword}',
+ array(
+ 'keyword' => $this->keyword,
+ 'uri' => (string) $uri,
+ ),
+ $error
+ );
+ }
+
+ $this->lastRefUri = null;
+
+ return null;
+ }
+
+
+ /**
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ abstract protected function doValidate( $context, $schema );
+
+ /**
+ * @param \Opis\JsonSchema\Uri|null $uri
+ */
+ protected function setLastRefUri( $uri ) {
+ $this->lastRefUri = $uri;
+ }
+
+ /**
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ protected function setLastRefSchema( $schema ) {
+ $info = $schema->info();
+
+ if ( $info->id() ) {
+ $this->lastRefUri = $info->id();
+ } else {
+ $this->lastRefUri = Uri::merge( JsonPointer::pathToFragment( $info->path() ), $info->idBaseRoot() );
+ }
+ }
+
+ /**
+ * @param ValidationContext $context
+ * @param Schema $schema
+ * @return ValidationContext
+ */
+ protected function createContext( $context, $schema ): ValidationContext {
+ return $context->create( $schema, $this->mapper, $this->globals, $this->slots );
+ }
+
+ /**
+ * @param SchemaLoader $repo
+ * @param JsonPointer $pointer
+ * @param Uri $base
+ * @param array|null $path
+ * @return null|Schema
+ */
+ protected function resolvePointer(
+ $repo,
+ $pointer,
+ $base,
+ $path = null
+ ) {
+ if ( $pointer->isAbsolute() ) {
+ $path = (string) $pointer;
+ } else {
+ if ( $pointer->hasFragment() ) {
+ return null;
+ }
+
+ $path = $path ? $pointer->absolutePath( $path ) : $pointer->path();
+ if ( $path === null ) {
+ return null;
+ }
+
+ $path = JsonPointer::pathToString( $path );
+ }
+
+ return $repo->loadSchemaById( Uri::merge( '#' . $path, $base ) );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/AdditionalItemsKeyword.php b/src/opis/json-schema/src/Keywords/AdditionalItemsKeyword.php
index a3422b29..adb90b99 100644
--- a/src/opis/json-schema/src/Keywords/AdditionalItemsKeyword.php
+++ b/src/opis/json-schema/src/Keywords/AdditionalItemsKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- $this->index = $startIndex;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($this->value === true) {
- $context->markAllAsEvaluatedItems();
- return null;
- }
-
- $data = $context->currentData();
- $count = count($data);
-
- if ($this->index >= $count) {
- return null;
- }
-
- if ($this->value === false) {
- return $this->error($schema, $context, 'additionalItems', 'Array should not have additional items', [
- 'index' => $this->index,
- ]);
- }
-
- if (is_object($this->value) && !($this->value instanceof Schema)) {
- $this->value = $context->loader()->loadObjectSchema($this->value);
- }
-
- $object = $this->createArrayObject($context);
-
- $error = $this->validateIterableData($schema, $this->value, $context, $this->indexes($this->index, $count),
- 'additionalItems', 'All additional array items must match schema', [], $object);
-
- if ($object && $object->count()) {
- $context->addEvaluatedItems($object->getArrayCopy());
- }
-
- return $error;
- }
-
- /**
- * @param int $start
- * @param int $max
- * @return iterable|int[]
- */
- protected function indexes($start, $max)
- {
- for ($i = $start; $i < $max; $i++) {
- yield $i;
- }
- }
+class AdditionalItemsKeyword implements Keyword {
+
+ use OfTrait;
+ use IterableDataValidationTrait;
+
+ /** @var bool|object|Schema */
+ protected $value;
+
+ /**
+ * @var int
+ */
+ protected $index;
+
+ /**
+ * @param bool|object $value
+ * @param int $startIndex
+ */
+ public function __construct( $value, int $startIndex ) {
+ $this->value = $value;
+ $this->index = $startIndex;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $this->value === true ) {
+ $context->markAllAsEvaluatedItems();
+ return null;
+ }
+
+ $data = $context->currentData();
+ $count = count( $data );
+
+ if ( $this->index >= $count ) {
+ return null;
+ }
+
+ if ( $this->value === false ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'additionalItems',
+ 'Array should not have additional items',
+ array(
+ 'index' => $this->index,
+ )
+ );
+ }
+
+ if ( is_object( $this->value ) && ! ( $this->value instanceof Schema ) ) {
+ $this->value = $context->loader()->loadObjectSchema( $this->value );
+ }
+
+ $object = $this->createArrayObject( $context );
+
+ $error = $this->validateIterableData(
+ $schema,
+ $this->value,
+ $context,
+ $this->indexes( $this->index, $count ),
+ 'additionalItems',
+ 'All additional array items must match schema',
+ array(),
+ $object
+ );
+
+ if ( $object && $object->count() ) {
+ $context->addEvaluatedItems( $object->getArrayCopy() );
+ }
+
+ return $error;
+ }
+
+ /**
+ * @param int $start
+ * @param int $max
+ * @return iterable|int[]
+ */
+ protected function indexes( $start, $max ) {
+ for ( $i = $start; $i < $max; $i++ ) {
+ yield $i;
+ }
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/AdditionalPropertiesKeyword.php b/src/opis/json-schema/src/Keywords/AdditionalPropertiesKeyword.php
index 71b7db6f..b2a1a4c1 100644
--- a/src/opis/json-schema/src/Keywords/AdditionalPropertiesKeyword.php
+++ b/src/opis/json-schema/src/Keywords/AdditionalPropertiesKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
+ /** @var bool|object|Schema */
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($this->value === true) {
- $context->markAllAsEvaluatedProperties();
- return null;
- }
+ /**
+ * @param bool|object|Schema $value
+ */
+ public function __construct( $value ) {
+ $this->value = $value;
+ }
- $props = $context->getUncheckedProperties();
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $this->value === true ) {
+ $context->markAllAsEvaluatedProperties();
+ return null;
+ }
- if (!$props) {
- return null;
- }
+ $props = $context->getUncheckedProperties();
- if ($this->value === false) {
- return $this->error($schema, $context,
- 'additionalProperties', 'Additional object properties are not allowed: {properties}', [
- 'properties' => $props
- ]);
- }
+ if ( ! $props ) {
+ return null;
+ }
- if (is_object($this->value) && !($this->value instanceof Schema)) {
- $this->value = $context->loader()->loadObjectSchema($this->value);
- }
+ if ( $this->value === false ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'additionalProperties',
+ 'Additional object properties are not allowed: {properties}',
+ array(
+ 'properties' => $props,
+ )
+ );
+ }
- $object = $this->createArrayObject($context);
+ if ( is_object( $this->value ) && ! ( $this->value instanceof Schema ) ) {
+ $this->value = $context->loader()->loadObjectSchema( $this->value );
+ }
- $error = $this->validateIterableData($schema, $this->value, $context, $props,
- 'additionalProperties', 'All additional object properties must match schema: {properties}', [
- 'properties' => $props
- ], $object);
+ $object = $this->createArrayObject( $context );
- if ($object && $object->count()) {
- $context->addEvaluatedProperties($object->getArrayCopy());
- }
+ $error = $this->validateIterableData(
+ $schema,
+ $this->value,
+ $context,
+ $props,
+ 'additionalProperties',
+ 'All additional object properties must match schema: {properties}',
+ array(
+ 'properties' => $props,
+ ),
+ $object
+ );
- return $error;
- }
+ if ( $object && $object->count() ) {
+ $context->addEvaluatedProperties( $object->getArrayCopy() );
+ }
+
+ return $error;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/AllOfKeyword.php b/src/opis/json-schema/src/Keywords/AllOfKeyword.php
index 298d6405..10fcec1f 100644
--- a/src/opis/json-schema/src/Keywords/AllOfKeyword.php
+++ b/src/opis/json-schema/src/Keywords/AllOfKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
+ /** @var bool[]|object[] */
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $object = $this->createArrayObject($context);
+ /**
+ * @param bool[]|object[] $value
+ */
+ public function __construct( array $value ) {
+ $this->value = $value;
+ }
- foreach ($this->value as $index => $value) {
- if ($value === true) {
- continue;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $object = $this->createArrayObject( $context );
- if ($value === false) {
- $this->addEvaluatedFromArrayObject($object, $context);
- return $this->error($schema, $context, 'allOf', 'The data should match all schemas', [
- 'index' => $index,
- ]);
- }
+ foreach ( $this->value as $index => $value ) {
+ if ( $value === true ) {
+ continue;
+ }
- if (is_object($value) && !($value instanceof Schema)) {
- $value = $this->value[$index] = $context->loader()->loadObjectSchema($value);
- }
+ if ( $value === false ) {
+ $this->addEvaluatedFromArrayObject( $object, $context );
+ return $this->error(
+ $schema,
+ $context,
+ 'allOf',
+ 'The data should match all schemas',
+ array(
+ 'index' => $index,
+ )
+ );
+ }
- if ($error = $context->validateSchemaWithoutEvaluated($value, null, false, $object)) {
- $this->addEvaluatedFromArrayObject($object, $context);
- return $this->error($schema, $context, 'allOf', 'The data should match all schemas', [
- 'index' => $index,
- ], $error);
- }
- }
+ if ( is_object( $value ) && ! ( $value instanceof Schema ) ) {
+ $value = $this->value[ $index ] = $context->loader()->loadObjectSchema( $value );
+ }
- $this->addEvaluatedFromArrayObject($object, $context);
+ if ( $error = $context->validateSchemaWithoutEvaluated( $value, null, false, $object ) ) {
+ $this->addEvaluatedFromArrayObject( $object, $context );
+ return $this->error(
+ $schema,
+ $context,
+ 'allOf',
+ 'The data should match all schemas',
+ array(
+ 'index' => $index,
+ ),
+ $error
+ );
+ }
+ }
- return null;
- }
+ $this->addEvaluatedFromArrayObject( $object, $context );
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/AnyOfKeyword.php b/src/opis/json-schema/src/Keywords/AnyOfKeyword.php
index 855594e6..c207a136 100644
--- a/src/opis/json-schema/src/Keywords/AnyOfKeyword.php
+++ b/src/opis/json-schema/src/Keywords/AnyOfKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- $this->alwaysValid = $alwaysValid;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $object = $this->createArrayObject($context);
- if ($this->alwaysValid && !$object) {
- return null;
- }
-
- $errors = [];
- $ok = false;
-
- foreach ($this->value as $index => $value) {
- if ($value === true) {
- $ok = true;
- if ($object) {
- continue;
- }
- return null;
- }
-
- if ($value === false) {
- continue;
- }
-
- if (is_object($value) && !($value instanceof Schema)) {
- $value = $this->value[$index] = $context->loader()->loadObjectSchema($value);
- }
-
- if ($error = $context->validateSchemaWithoutEvaluated($value, null, false, $object)) {
- $errors[] = $error;
- continue;
- }
-
- if (!$object) {
- return null;
- }
- $ok = true;
- }
-
- $this->addEvaluatedFromArrayObject($object, $context);
-
- if ($ok) {
- return null;
- }
-
- return $this->error($schema, $context, 'anyOf', 'The data should match at least one schema', [], $errors);
- }
+class AnyOfKeyword implements Keyword {
+
+ use OfTrait;
+ use ErrorTrait;
+
+ /** @var bool[]|object[] */
+ protected $value;
+ /**
+ * @var bool
+ */
+ protected $alwaysValid;
+
+ /**
+ * @param bool[]|object[] $value
+ */
+ public function __construct( array $value, bool $alwaysValid = false ) {
+ $this->value = $value;
+ $this->alwaysValid = $alwaysValid;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $object = $this->createArrayObject( $context );
+ if ( $this->alwaysValid && ! $object ) {
+ return null;
+ }
+
+ $errors = array();
+ $ok = false;
+
+ foreach ( $this->value as $index => $value ) {
+ if ( $value === true ) {
+ $ok = true;
+ if ( $object ) {
+ continue;
+ }
+ return null;
+ }
+
+ if ( $value === false ) {
+ continue;
+ }
+
+ if ( is_object( $value ) && ! ( $value instanceof Schema ) ) {
+ $value = $this->value[ $index ] = $context->loader()->loadObjectSchema( $value );
+ }
+
+ if ( $error = $context->validateSchemaWithoutEvaluated( $value, null, false, $object ) ) {
+ $errors[] = $error;
+ continue;
+ }
+
+ if ( ! $object ) {
+ return null;
+ }
+ $ok = true;
+ }
+
+ $this->addEvaluatedFromArrayObject( $object, $context );
+
+ if ( $ok ) {
+ return null;
+ }
+
+ return $this->error( $schema, $context, 'anyOf', 'The data should match at least one schema', array(), $errors );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ConstDataKeyword.php b/src/opis/json-schema/src/Keywords/ConstDataKeyword.php
index 3e6b8f11..d391c9c4 100644
--- a/src/opis/json-schema/src/Keywords/ConstDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ConstDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(null);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $value = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
- if ($value === $this) {
- return $this->error($schema, $context, 'const', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->const = $value;
- $ret = parent::validate($context, $schema);
- $this->const = null;
-
- return $ret;
- }
+class ConstDataKeyword extends ConstKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( null );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $value = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+ if ( $value === $this ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'const',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->const = $value;
+ $ret = parent::validate( $context, $schema );
+ $this->const = null;
+
+ return $ret;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ConstKeyword.php b/src/opis/json-schema/src/Keywords/ConstKeyword.php
index 7cf7ff18..8e6b6eea 100644
--- a/src/opis/json-schema/src/Keywords/ConstKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ConstKeyword.php
@@ -1,5 +1,6 @@
const = $const;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if (Helper::equals($this->const, $context->currentData())) {
- return null;
- }
-
- return $this->error($schema, $context, 'const', 'The data must must match the const value', [
- 'const' => $this->const
- ]);
- }
+class ConstKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /** @var mixed */
+ protected $const;
+
+ /**
+ * @param $const
+ */
+ public function __construct( $const ) {
+ $this->const = $const;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( Helper::equals( $this->const, $context->currentData() ) ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'const',
+ 'The data must must match the const value',
+ array(
+ 'const' => $this->const,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ContainsKeyword.php b/src/opis/json-schema/src/Keywords/ContainsKeyword.php
index 76223426..c8e2a85f 100644
--- a/src/opis/json-schema/src/Keywords/ContainsKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ContainsKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- $this->min = $min;
- $this->max = $max;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $data = $context->currentData();
- $count = count($data);
-
- $context->markAllAsEvaluatedItems();
-
- if ($this->min > $count) {
- return $this->error($schema, $context, 'minContains', 'Array must have at least {min} items', [
- 'min' => $this->min,
- 'count' => $count,
- ]);
- }
-
- $isMaxNull = $this->max === null;
-
- if ($this->value === true) {
- if ($count) {
- if (!$isMaxNull && $count > $this->max) {
- return $this->error($schema, $context, 'maxContains', 'Array must have at most {max} items', [
- 'max' => $this->max,
- 'count' => $count,
- ]);
- }
- return null;
- }
-
- return $this->error($schema, $context, 'contains', 'Array must not be empty');
- }
-
- if ($this->value === false) {
- return $this->error($schema, $context, 'contains', 'Any array is invalid');
- }
-
- if (is_object($this->value) && !($this->value instanceof Schema)) {
- $this->value = $context->loader()->loadObjectSchema($this->value);
- }
-
- $errors = [];
- $valid = 0;
-
- $isMinNull = $this->min === null;
-
- if ($isMaxNull && $isMinNull) {
- foreach ($data as $key => $item) {
- $context->pushDataPath($key);
- $error = $this->value->validate($context);
- $context->popDataPath();
- if ($error) {
- $errors[] = $error;
- } else {
- return null;
- }
- }
-
- return $this->error($schema, $context, 'contains', 'At least one array item must match schema', [],
- $errors);
- }
-
- foreach ($data as $key => $item) {
- $context->pushDataPath($key);
- $error = $this->value->validate($context);
- $context->popDataPath();
-
- if ($error) {
- $errors[] = $error;
- } else {
- $valid++;
- }
- }
-
- if (!$isMinNull && $valid < $this->min) {
- return $this->error($schema, $context, 'minContains', 'At least {min} array items must match schema', [
- 'min' => $this->min,
- 'count' => $valid,
- ]);
- }
-
- if (!$isMaxNull && $valid > $this->max) {
- return $this->error($schema, $context, 'maxContains', 'At most {max} array items must match schema', [
- 'max' => $this->max,
- 'count' => $valid,
- ]);
- }
-
- if ($valid) {
- return null;
- }
-
- return $this->error($schema, $context, 'contains', 'At least one array item must match schema', [],
- $errors);
- }
+class ContainsKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /** @var bool|object */
+ protected $value;
+ /**
+ * @var int|null
+ */
+ protected $min;
+ /**
+ * @var int|null
+ */
+ protected $max;
+
+ /**
+ * @param bool|object $value
+ * @param int|null $min
+ * @param int|null $max
+ */
+ public function __construct( $value, $min = null, $max = null ) {
+ $this->value = $value;
+ $this->min = $min;
+ $this->max = $max;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $data = $context->currentData();
+ $count = count( $data );
+
+ $context->markAllAsEvaluatedItems();
+
+ if ( $this->min > $count ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'minContains',
+ 'Array must have at least {min} items',
+ array(
+ 'min' => $this->min,
+ 'count' => $count,
+ )
+ );
+ }
+
+ $isMaxNull = $this->max === null;
+
+ if ( $this->value === true ) {
+ if ( $count ) {
+ if ( ! $isMaxNull && $count > $this->max ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'maxContains',
+ 'Array must have at most {max} items',
+ array(
+ 'max' => $this->max,
+ 'count' => $count,
+ )
+ );
+ }
+ return null;
+ }
+
+ return $this->error( $schema, $context, 'contains', 'Array must not be empty' );
+ }
+
+ if ( $this->value === false ) {
+ return $this->error( $schema, $context, 'contains', 'Any array is invalid' );
+ }
+
+ if ( is_object( $this->value ) && ! ( $this->value instanceof Schema ) ) {
+ $this->value = $context->loader()->loadObjectSchema( $this->value );
+ }
+
+ $errors = array();
+ $valid = 0;
+
+ $isMinNull = $this->min === null;
+
+ if ( $isMaxNull && $isMinNull ) {
+ foreach ( $data as $key => $item ) {
+ $context->pushDataPath( $key );
+ $error = $this->value->validate( $context );
+ $context->popDataPath();
+ if ( $error ) {
+ $errors[] = $error;
+ } else {
+ return null;
+ }
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'contains',
+ 'At least one array item must match schema',
+ array(),
+ $errors
+ );
+ }
+
+ foreach ( $data as $key => $item ) {
+ $context->pushDataPath( $key );
+ $error = $this->value->validate( $context );
+ $context->popDataPath();
+
+ if ( $error ) {
+ $errors[] = $error;
+ } else {
+ ++$valid;
+ }
+ }
+
+ if ( ! $isMinNull && $valid < $this->min ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'minContains',
+ 'At least {min} array items must match schema',
+ array(
+ 'min' => $this->min,
+ 'count' => $valid,
+ )
+ );
+ }
+
+ if ( ! $isMaxNull && $valid > $this->max ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'maxContains',
+ 'At most {max} array items must match schema',
+ array(
+ 'max' => $this->max,
+ 'count' => $valid,
+ )
+ );
+ }
+
+ if ( $valid ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'contains',
+ 'At least one array item must match schema',
+ array(),
+ $errors
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ContentEncodingKeyword.php b/src/opis/json-schema/src/Keywords/ContentEncodingKeyword.php
index ca74a628..94e6dd73 100644
--- a/src/opis/json-schema/src/Keywords/ContentEncodingKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ContentEncodingKeyword.php
@@ -1,5 +1,6 @@
name = $name;
- $this->resolver = $resolver;
- }
+ /** @var bool|null|callable|ContentEncoding */
+ protected $encoding = false;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if (!$this->resolver) {
- return null;
- }
+ /**
+ * @param string $name
+ * @param null|ContentEncodingResolver $resolver
+ */
+ public function __construct( string $name, $resolver = null ) {
+ $this->name = $name;
+ $this->resolver = $resolver;
+ }
- if ($this->encoding === false) {
- $this->encoding = $this->resolver->resolve($this->name);
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( ! $this->resolver ) {
+ return null;
+ }
- if ($this->encoding === null) {
- throw new UnresolvedContentEncodingException($this->name, $schema, $context);
- }
+ if ( $this->encoding === false ) {
+ $this->encoding = $this->resolver->resolve( $this->name );
+ }
- $result = $this->encoding instanceof ContentEncoding
- ? $this->encoding->decode($context->currentData(), $this->name)
- : ($this->encoding)($context->currentData(), $this->name);
+ if ( $this->encoding === null ) {
+ throw new UnresolvedContentEncodingException( $this->name, $schema, $context );
+ }
- if ($result === null) {
- return $this->error($schema, $context, 'contentEncoding', "The value must be encoded as '{encoding}'", [
- 'encoding' => $this->name,
- ]);
- }
+ $result = $this->encoding instanceof ContentEncoding
+ ? $this->encoding->decode( $context->currentData(), $this->name )
+ : ( $this->encoding )( $context->currentData(), $this->name );
- $context->setDecodedContent($result);
+ if ( $result === null ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'contentEncoding',
+ "The value must be encoded as '{encoding}'",
+ array(
+ 'encoding' => $this->name,
+ )
+ );
+ }
- return null;
- }
+ $context->setDecodedContent( $result );
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ContentMediaTypeKeyword.php b/src/opis/json-schema/src/Keywords/ContentMediaTypeKeyword.php
index 411e75b7..12e169b8 100644
--- a/src/opis/json-schema/src/Keywords/ContentMediaTypeKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ContentMediaTypeKeyword.php
@@ -1,5 +1,6 @@
name = $name;
- $this->resolver = $resolver;
- }
+ /**
+ * @var \Opis\JsonSchema\Resolvers\ContentMediaTypeResolver|null
+ */
+ protected $resolver;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if (!$this->resolver) {
- return null;
- }
+ /**
+ * @param string $name
+ * @param null|ContentMediaTypeResolver $resolver
+ */
+ public function __construct( string $name, $resolver ) {
+ $this->name = $name;
+ $this->resolver = $resolver;
+ }
- if ($this->media === false) {
- $this->media = $this->resolver->resolve($this->name);
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( ! $this->resolver ) {
+ return null;
+ }
- if ($this->media === null) {
- throw new UnresolvedContentMediaTypeException($this->name, $schema, $context);
- }
+ if ( $this->media === false ) {
+ $this->media = $this->resolver->resolve( $this->name );
+ }
- $data = $context->getDecodedContent();
+ if ( $this->media === null ) {
+ throw new UnresolvedContentMediaTypeException( $this->name, $schema, $context );
+ }
- $ok = $this->media instanceof ContentMediaType
- ? $this->media->validate($data, $this->name)
- : ($this->media)($data, $this->name);
- if ($ok) {
- return null;
- }
+ $data = $context->getDecodedContent();
- unset($data);
+ $ok = $this->media instanceof ContentMediaType
+ ? $this->media->validate( $data, $this->name )
+ : ( $this->media )( $data, $this->name );
+ if ( $ok ) {
+ return null;
+ }
- return $this->error($schema, $context, 'contentMediaType', "The media type of the data must be '{media}'", [
- 'media' => $this->name,
- ]);
- }
+ unset( $data );
+
+ return $this->error(
+ $schema,
+ $context,
+ 'contentMediaType',
+ "The media type of the data must be '{media}'",
+ array(
+ 'media' => $this->name,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ContentSchemaKeyword.php b/src/opis/json-schema/src/Keywords/ContentSchemaKeyword.php
index 2ee3abea..bed6ec24 100644
--- a/src/opis/json-schema/src/Keywords/ContentSchemaKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ContentSchemaKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
+ /** @var bool|object */
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $data = json_decode($context->getDecodedContent(), false);
+ /**
+ * @param object $value
+ */
+ public function __construct( $value ) {
+ $this->value = $value;
+ }
- if ($error = json_last_error() !== JSON_ERROR_NONE) {
- $message = json_last_error_msg();
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $data = json_decode( $context->getDecodedContent(), false );
- return $this->error($schema, $context, 'contentSchema', "Invalid JSON content: {message}", [
- 'error' => $error,
- 'message' => $message,
- ]);
- }
+ if ( $error = json_last_error() !== JSON_ERROR_NONE ) {
+ $message = json_last_error_msg();
- if (is_object($this->value) && !($this->value instanceof Schema)) {
- $this->value = $context->loader()->loadObjectSchema($this->value);
- }
+ return $this->error(
+ $schema,
+ $context,
+ 'contentSchema',
+ 'Invalid JSON content: {message}',
+ array(
+ 'error' => $error,
+ 'message' => $message,
+ )
+ );
+ }
- if ($error = $this->value->validate($context->newInstance($data, $schema))) {
- return $this->error($schema, $context, 'contentSchema', "The JSON content must match schema", [], $error);
- }
+ if ( is_object( $this->value ) && ! ( $this->value instanceof Schema ) ) {
+ $this->value = $context->loader()->loadObjectSchema( $this->value );
+ }
- return null;
- }
+ if ( $error = $this->value->validate( $context->newInstance( $data, $schema ) ) ) {
+ return $this->error( $schema, $context, 'contentSchema', 'The JSON content must match schema', array(), $error );
+ }
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/DefaultKeyword.php b/src/opis/json-schema/src/Keywords/DefaultKeyword.php
index 85cf6397..b6a8ce77 100644
--- a/src/opis/json-schema/src/Keywords/DefaultKeyword.php
+++ b/src/opis/json-schema/src/Keywords/DefaultKeyword.php
@@ -1,5 +1,6 @@
defaults = $defaults;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $data = $context->currentData();
-
- if (is_object($data)) {
- foreach ($this->defaults as $name => $value) {
- if (!property_exists($data, $name)) {
- $data->{$name} = Helper::cloneValue($value);
- }
- }
- }
-
- return null;
- }
+class DefaultKeyword implements Keyword {
+
+
+ /**
+ * @var mixed[]
+ */
+ protected $defaults;
+
+ /**
+ * @param array $defaults
+ */
+ public function __construct( array $defaults ) {
+ $this->defaults = $defaults;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $data = $context->currentData();
+
+ if ( is_object( $data ) ) {
+ foreach ( $this->defaults as $name => $value ) {
+ if ( ! property_exists( $data, $name ) ) {
+ $data->{$name} = Helper::cloneValue( $value );
+ }
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/DependenciesKeyword.php b/src/opis/json-schema/src/Keywords/DependenciesKeyword.php
index 82bc778b..98741b19 100644
--- a/src/opis/json-schema/src/Keywords/DependenciesKeyword.php
+++ b/src/opis/json-schema/src/Keywords/DependenciesKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
+ /** @var array|object[]|string[][] */
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $data = $context->currentData();
- $object = $this->createArrayObject($context);
+ /**
+ * @param object[]|string[][] $value
+ */
+ public function __construct( array $value ) {
+ $this->value = $value;
+ }
- foreach ($this->value as $name => $value) {
- if ($value === true || !property_exists($data, $name)) {
- continue;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $data = $context->currentData();
+ $object = $this->createArrayObject( $context );
- if ($value === false) {
- $this->addEvaluatedFromArrayObject($object, $context);
- return $this->error($schema, $context, 'dependencies', "Property '{property}' is not allowed", [
- 'property' => $name,
- ]);
- }
+ foreach ( $this->value as $name => $value ) {
+ if ( $value === true || ! property_exists( $data, $name ) ) {
+ continue;
+ }
- if (is_array($value)) {
- foreach ($value as $prop) {
- if (!property_exists($data, $prop)) {
- $this->addEvaluatedFromArrayObject($object, $context);
- return $this->error($schema, $context, 'dependencies',
- "Property '{missing}' property is required by property '{property}'", [
- 'property' => $name,
- 'missing' => $prop,
- ]);
- }
- }
+ if ( $value === false ) {
+ $this->addEvaluatedFromArrayObject( $object, $context );
+ return $this->error(
+ $schema,
+ $context,
+ 'dependencies',
+ "Property '{property}' is not allowed",
+ array(
+ 'property' => $name,
+ )
+ );
+ }
- continue;
- }
+ if ( is_array( $value ) ) {
+ foreach ( $value as $prop ) {
+ if ( ! property_exists( $data, $prop ) ) {
+ $this->addEvaluatedFromArrayObject( $object, $context );
+ return $this->error(
+ $schema,
+ $context,
+ 'dependencies',
+ "Property '{missing}' property is required by property '{property}'",
+ array(
+ 'property' => $name,
+ 'missing' => $prop,
+ )
+ );
+ }
+ }
- if (is_object($value) && !($value instanceof Schema)) {
- $value = $this->value[$name] = $context->loader()->loadObjectSchema($value);
- }
+ continue;
+ }
- if ($error = $context->validateSchemaWithoutEvaluated($value, null, false, $object)) {
- $this->addEvaluatedFromArrayObject($object, $context);
- return $this->error($schema, $context, 'dependencies',
- "The object must match dependency schema defined on property '{property}'", [
- 'property' => $name,
- ], $error);
- }
- }
+ if ( is_object( $value ) && ! ( $value instanceof Schema ) ) {
+ $value = $this->value[ $name ] = $context->loader()->loadObjectSchema( $value );
+ }
- $this->addEvaluatedFromArrayObject($object, $context);
+ if ( $error = $context->validateSchemaWithoutEvaluated( $value, null, false, $object ) ) {
+ $this->addEvaluatedFromArrayObject( $object, $context );
+ return $this->error(
+ $schema,
+ $context,
+ 'dependencies',
+ "The object must match dependency schema defined on property '{property}'",
+ array(
+ 'property' => $name,
+ ),
+ $error
+ );
+ }
+ }
- return null;
- }
+ $this->addEvaluatedFromArrayObject( $object, $context );
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/DependentRequiredKeyword.php b/src/opis/json-schema/src/Keywords/DependentRequiredKeyword.php
index 0b64822b..d3a02f51 100644
--- a/src/opis/json-schema/src/Keywords/DependentRequiredKeyword.php
+++ b/src/opis/json-schema/src/Keywords/DependentRequiredKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
+ /** @var string[][] */
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $data = $context->currentData();
+ /**
+ * @param string[][] $value
+ */
+ public function __construct( array $value ) {
+ $this->value = $value;
+ }
- foreach ($this->value as $name => $value) {
- if (!property_exists($data, $name)) {
- continue;
- }
- foreach ($value as $prop) {
- if (!property_exists($data, $prop)) {
- return $this->error($schema, $context, 'dependentRequired',
- "'{$prop}' property is required by '{$name}' property", [
- 'property' => $name,
- 'missing' => $prop,
- ]);
- }
- }
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $data = $context->currentData();
- return null;
- }
+ foreach ( $this->value as $name => $value ) {
+ if ( ! property_exists( $data, $name ) ) {
+ continue;
+ }
+ foreach ( $value as $prop ) {
+ if ( ! property_exists( $data, $prop ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'dependentRequired',
+ "'{$prop}' property is required by '{$name}' property",
+ array(
+ 'property' => $name,
+ 'missing' => $prop,
+ )
+ );
+ }
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/DependentSchemasKeyword.php b/src/opis/json-schema/src/Keywords/DependentSchemasKeyword.php
index 4d44b23b..caf0c042 100644
--- a/src/opis/json-schema/src/Keywords/DependentSchemasKeyword.php
+++ b/src/opis/json-schema/src/Keywords/DependentSchemasKeyword.php
@@ -1,5 +1,6 @@
value = (array)$value;
- }
+ /**
+ * @var mixed[]
+ */
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $data = $context->currentData();
- $object = $this->createArrayObject($context);
+ /**
+ * @param object $value
+ */
+ public function __construct( $value ) {
+ $this->value = (array) $value;
+ }
- foreach ($this->value as $name => $value) {
- if ($value === true || !property_exists($data, $name)) {
- continue;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $data = $context->currentData();
+ $object = $this->createArrayObject( $context );
- if ($value === false) {
- $this->addEvaluatedFromArrayObject($object, $context);
- return $this->error($schema, $context, 'dependentSchemas', "'{$name}' property is not allowed", [
- 'property' => $name,
- ]);
- }
+ foreach ( $this->value as $name => $value ) {
+ if ( $value === true || ! property_exists( $data, $name ) ) {
+ continue;
+ }
- if (is_object($value) && !($value instanceof Schema)) {
- $value = $this->value[$name] = $context->loader()->loadObjectSchema($value);
- }
+ if ( $value === false ) {
+ $this->addEvaluatedFromArrayObject( $object, $context );
+ return $this->error(
+ $schema,
+ $context,
+ 'dependentSchemas',
+ "'{$name}' property is not allowed",
+ array(
+ 'property' => $name,
+ )
+ );
+ }
- if ($error = $context->validateSchemaWithoutEvaluated($value, null, false, $object)) {
- $this->addEvaluatedFromArrayObject($object, $context);
- return $this->error($schema, $context, 'dependentSchemas',
- "The object must match dependency schema defined on property '{$name}'", [
- 'property' => $name,
- ], $error);
- }
- }
+ if ( is_object( $value ) && ! ( $value instanceof Schema ) ) {
+ $value = $this->value[ $name ] = $context->loader()->loadObjectSchema( $value );
+ }
- $this->addEvaluatedFromArrayObject($object, $context);
+ if ( $error = $context->validateSchemaWithoutEvaluated( $value, null, false, $object ) ) {
+ $this->addEvaluatedFromArrayObject( $object, $context );
+ return $this->error(
+ $schema,
+ $context,
+ 'dependentSchemas',
+ "The object must match dependency schema defined on property '{$name}'",
+ array(
+ 'property' => $name,
+ ),
+ $error
+ );
+ }
+ }
- return null;
- }
+ $this->addEvaluatedFromArrayObject( $object, $context );
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/EnumDataKeyword.php b/src/opis/json-schema/src/Keywords/EnumDataKeyword.php
index e5ec2e89..3a4375d5 100644
--- a/src/opis/json-schema/src/Keywords/EnumDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/EnumDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct([]);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $value = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
- if ($value === $this || !is_array($value) || empty($value)) {
- return $this->error($schema, $context, 'enum', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->enum = $this->listByType($value);
- $ret = parent::validate($context, $schema);
- $this->enum = null;
-
- return $ret;
- }
+class EnumDataKeyword extends EnumKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( array() );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $value = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+ if ( $value === $this || ! is_array( $value ) || empty( $value ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'enum',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->enum = $this->listByType( $value );
+ $ret = parent::validate( $context, $schema );
+ $this->enum = null;
+
+ return $ret;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/EnumKeyword.php b/src/opis/json-schema/src/Keywords/EnumKeyword.php
index c182cdce..1bfd9327 100644
--- a/src/opis/json-schema/src/Keywords/EnumKeyword.php
+++ b/src/opis/json-schema/src/Keywords/EnumKeyword.php
@@ -1,5 +1,6 @@
enum = $this->listByType($enum);
- }
+ /**
+ * @var mixed[]|null
+ */
+ protected $enum;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $type = $context->currentDataType();
- $data = $context->currentData();
+ /**
+ * @param array $enum
+ */
+ public function __construct( array $enum ) {
+ $this->enum = $this->listByType( $enum );
+ }
- if (isset($this->enum[$type])) {
- foreach ($this->enum[$type] as $value) {
- if (Helper::equals($value, $data)) {
- return null;
- }
- }
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $type = $context->currentDataType();
+ $data = $context->currentData();
- return $this->error($schema, $context, 'enum', 'The data should match one item from enum');
- }
+ if ( isset( $this->enum[ $type ] ) ) {
+ foreach ( $this->enum[ $type ] as $value ) {
+ if ( Helper::equals( $value, $data ) ) {
+ return null;
+ }
+ }
+ }
- /**
- * @param array $values
- * @return array
- */
- protected function listByType($values): array
- {
- $list = [];
+ return $this->error( $schema, $context, 'enum', 'The data should match one item from enum' );
+ }
- foreach ($values as $value) {
- $type = Helper::getJsonType($value);
- if (!isset($list[$type])) {
- $list[$type] = [];
- }
- $list[$type][] = $value;
- }
+ /**
+ * @param array $values
+ * @return array
+ */
+ protected function listByType( $values ): array {
+ $list = array();
- return $list;
- }
+ foreach ( $values as $value ) {
+ $type = Helper::getJsonType( $value );
+ if ( ! isset( $list[ $type ] ) ) {
+ $list[ $type ] = array();
+ }
+ $list[ $type ][] = $value;
+ }
+
+ return $list;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ErrorTrait.php b/src/opis/json-schema/src/Keywords/ErrorTrait.php
index d7ba5a91..aa5ef165 100644
--- a/src/opis/json-schema/src/Keywords/ErrorTrait.php
+++ b/src/opis/json-schema/src/Keywords/ErrorTrait.php
@@ -1,5 +1,6 @@
all();
- }
- }
+trait ErrorTrait {
- return new ValidationError($keyword, $schema, DataInfo::fromContext($context), $message, $args,
- is_array($errors) ? $errors : []);
- }
-}
\ No newline at end of file
+ /**
+ * @param Schema $schema
+ * @param ValidationContext $context
+ * @param string $keyword
+ * @param string $message
+ * @param array $args
+ * @param ErrorContainer|ValidationError|ValidationError[]|null $errors
+ * @return ValidationError
+ */
+ protected function error(
+ $schema,
+ $context,
+ $keyword,
+ $message,
+ $args = array(),
+ $errors = null
+ ): ValidationError {
+ if ( $errors ) {
+ if ( $errors instanceof ValidationError ) {
+ $errors = array( $errors );
+ } elseif ( $errors instanceof ErrorContainer ) {
+ $errors = $errors->all();
+ }
+ }
+
+ return new ValidationError(
+ $keyword,
+ $schema,
+ DataInfo::fromContext( $context ),
+ $message,
+ $args,
+ is_array( $errors ) ? $errors : array()
+ );
+ }
+}
diff --git a/src/opis/json-schema/src/Keywords/ExclusiveMaximumDataKeyword.php b/src/opis/json-schema/src/Keywords/ExclusiveMaximumDataKeyword.php
index 7912ec94..2e066da2 100644
--- a/src/opis/json-schema/src/Keywords/ExclusiveMaximumDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ExclusiveMaximumDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var float|int $number */
- $number = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($number === $this || !(is_float($number) || is_int($number))) {
- return $this->error($schema, $context, 'exclusiveMaximum', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->number = $number;
-
- return parent::validate($context, $schema);
- }
+class ExclusiveMaximumDataKeyword extends ExclusiveMaximumKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var float|int $number */
+ $number = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $number === $this || ! ( is_float( $number ) || is_int( $number ) ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'exclusiveMaximum',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->number = $number;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ExclusiveMaximumKeyword.php b/src/opis/json-schema/src/Keywords/ExclusiveMaximumKeyword.php
index 442dd407..76e5e402 100644
--- a/src/opis/json-schema/src/Keywords/ExclusiveMaximumKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ExclusiveMaximumKeyword.php
@@ -1,5 +1,6 @@
number = $number;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($context->currentData() < $this->number) {
- return null;
- }
-
- return $this->error($schema, $context, 'exclusiveMaximum', "Number must be lower than {max}", [
- 'max' => $this->number,
- ]);
- }
+class ExclusiveMaximumKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var float
+ */
+ protected $number;
+
+ /**
+ * @param float $number
+ */
+ public function __construct( float $number ) {
+ $this->number = $number;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $context->currentData() < $this->number ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'exclusiveMaximum',
+ 'Number must be lower than {max}',
+ array(
+ 'max' => $this->number,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ExclusiveMinimumDataKeyword.php b/src/opis/json-schema/src/Keywords/ExclusiveMinimumDataKeyword.php
index a27b853e..fab64cf1 100644
--- a/src/opis/json-schema/src/Keywords/ExclusiveMinimumDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ExclusiveMinimumDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var float|int $number */
- $number = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($number === $this || !(is_float($number) || is_int($number))) {
- return $this->error($schema, $context, 'exclusiveMinimum', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->number = $number;
-
- return parent::validate($context, $schema);
- }
+class ExclusiveMinimumDataKeyword extends ExclusiveMinimumKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var float|int $number */
+ $number = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $number === $this || ! ( is_float( $number ) || is_int( $number ) ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'exclusiveMinimum',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->number = $number;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ExclusiveMinimumKeyword.php b/src/opis/json-schema/src/Keywords/ExclusiveMinimumKeyword.php
index 2c123b05..11c64938 100644
--- a/src/opis/json-schema/src/Keywords/ExclusiveMinimumKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ExclusiveMinimumKeyword.php
@@ -1,5 +1,6 @@
number = $number;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($context->currentData() > $this->number) {
- return null;
- }
-
- return $this->error($schema, $context, 'exclusiveMinimum', "Number must be greater than {min}", [
- 'min' => $this->number,
- ]);
- }
+class ExclusiveMinimumKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var float
+ */
+ protected $number;
+
+ /**
+ * @param float $number
+ */
+ public function __construct( float $number ) {
+ $this->number = $number;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $context->currentData() > $this->number ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'exclusiveMinimum',
+ 'Number must be greater than {min}',
+ array(
+ 'min' => $this->number,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/FiltersKeyword.php b/src/opis/json-schema/src/Keywords/FiltersKeyword.php
index 8a39f5c9..3ffb8156 100644
--- a/src/opis/json-schema/src/Keywords/FiltersKeyword.php
+++ b/src/opis/json-schema/src/Keywords/FiltersKeyword.php
@@ -1,5 +1,6 @@
filters = $filters;
- }
+ /** @var array|object[] */
+ protected $filters;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $type = $context->currentDataType();
+ /**
+ * @param object[] $filters
+ */
+ public function __construct( array $filters ) {
+ $this->filters = $filters;
+ }
- foreach ($this->filters as $filter) {
- if (!isset($filter->types[$type])) {
- throw new UnresolvedFilterException($filter->name, $type, $schema, $context);
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $type = $context->currentDataType();
- $func = $filter->types[$type];
+ foreach ( $this->filters as $filter ) {
+ if ( ! isset( $filter->types[ $type ] ) ) {
+ throw new UnresolvedFilterException( $filter->name, $type, $schema, $context );
+ }
- if ($filter->args) {
- $args = (array)$filter->args->resolve($context->rootData(), $context->currentDataPath());
- $args += $context->globals();
- } else {
- $args = $context->globals();
- }
+ $func = $filter->types[ $type ];
- try {
- if ($func instanceof Filter) {
- $ok = $func->validate($context, $schema, $args);
- } else {
- $ok = $func($context->currentData(), $args);
- }
- } catch (CustomError $error) {
- return $this->error($schema, $context, '$filters', $error->getMessage(), $error->getArgs() + [
- 'filter' => $filter->name,
- 'type' => $type,
- 'args' => $args,
- ]);
- }
+ if ( $filter->args ) {
+ $args = (array) $filter->args->resolve( $context->rootData(), $context->currentDataPath() );
+ $args += $context->globals();
+ } else {
+ $args = $context->globals();
+ }
- if ($ok) {
- unset($func, $args, $ok);
- continue;
- }
+ try {
+ if ( $func instanceof Filter ) {
+ $ok = $func->validate( $context, $schema, $args );
+ } else {
+ $ok = $func( $context->currentData(), $args );
+ }
+ } catch ( CustomError $error ) {
+ return $this->error(
+ $schema,
+ $context,
+ '$filters',
+ $error->getMessage(),
+ $error->getArgs() + array(
+ 'filter' => $filter->name,
+ 'type' => $type,
+ 'args' => $args,
+ )
+ );
+ }
- return $this->error($schema, $context, '$filters', "Filter '{filter}' ({type}) was not passed", [
- 'filter' => $filter->name,
- 'type' => $type,
- 'args' => $args,
- ]);
- }
+ if ( $ok ) {
+ unset( $func, $args, $ok );
+ continue;
+ }
- return null;
- }
+ return $this->error(
+ $schema,
+ $context,
+ '$filters',
+ "Filter '{filter}' ({type}) was not passed",
+ array(
+ 'filter' => $filter->name,
+ 'type' => $type,
+ 'args' => $args,
+ )
+ );
+ }
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/FormatDataKeyword.php b/src/opis/json-schema/src/Keywords/FormatDataKeyword.php
index 8adf8922..e87b6e8e 100644
--- a/src/opis/json-schema/src/Keywords/FormatDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/FormatDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- $this->resolver = $resolver;
- parent::__construct('', []);
- }
+ /**
+ * @var \Opis\JsonSchema\Resolvers\FormatResolver
+ */
+ protected $resolver;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $value = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
- if ($value === $this || !is_string($value)) {
- return $this->error($schema, $context, 'format', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
+ /**
+ * @param JsonPointer $value
+ * @param FormatResolver $resolver
+ */
+ public function __construct( JsonPointer $value, FormatResolver $resolver ) {
+ $this->value = $value;
+ $this->resolver = $resolver;
+ parent::__construct( '', array() );
+ }
- /** @var string $value */
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $value = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+ if ( $value === $this || ! is_string( $value ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'format',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
- $type = $context->currentDataType();
+ /** @var string $value */
- $types = [
- $type => $this->resolver->resolve($value, $type),
- ];
+ $type = $context->currentDataType();
- if (!$types[$type] && ($super = Helper::getJsonSuperType($type))) {
- $types[$super] = $this->resolver->resolve($value, $super);
- unset($super);
- }
+ $types = array(
+ $type => $this->resolver->resolve( $value, $type ),
+ );
- unset($type);
+ if ( ! $types[ $type ] && ( $super = Helper::getJsonSuperType( $type ) ) ) {
+ $types[ $super ] = $this->resolver->resolve( $value, $super );
+ unset( $super );
+ }
- $this->name = $value;
- $this->types = $types;
- $ret = parent::validate($context, $schema);
- $this->name = $this->types = null;
+ unset( $type );
- return $ret;
- }
+ $this->name = $value;
+ $this->types = $types;
+ $ret = parent::validate( $context, $schema );
+ $this->name = $this->types = null;
+
+ return $ret;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/FormatKeyword.php b/src/opis/json-schema/src/Keywords/FormatKeyword.php
index 93f8c168..1ce65b2d 100644
--- a/src/opis/json-schema/src/Keywords/FormatKeyword.php
+++ b/src/opis/json-schema/src/Keywords/FormatKeyword.php
@@ -1,5 +1,6 @@
name = $name;
- $this->types = $types;
- }
+ /** @var callable[]|Format[] */
+ protected $types;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $type = $context->currentDataType();
+ /**
+ * @param string $name
+ * @param callable[]|Format[] $types
+ */
+ public function __construct( string $name, array $types ) {
+ $this->name = $name;
+ $this->types = $types;
+ }
- if (!isset($this->types[$type])) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $type = $context->currentDataType();
- $format = $this->types[$type];
+ if ( ! isset( $this->types[ $type ] ) ) {
+ return null;
+ }
- try {
- if ($format instanceof Format) {
- $ok = $format->validate($context->currentData());
- } else {
- $ok = $format($context->currentData());
- }
- } catch (CustomError $error) {
- return $this->error($schema, $context, 'format', $error->getMessage(), $error->getArgs() + [
- 'format' => $this->name,
- 'type' => $type,
- ]);
- }
+ $format = $this->types[ $type ];
- if ($ok) {
- return null;
- }
+ try {
+ if ( $format instanceof Format ) {
+ $ok = $format->validate( $context->currentData() );
+ } else {
+ $ok = $format( $context->currentData() );
+ }
+ } catch ( CustomError $error ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'format',
+ $error->getMessage(),
+ $error->getArgs() + array(
+ 'format' => $this->name,
+ 'type' => $type,
+ )
+ );
+ }
- return $this->error($schema, $context, 'format', "The data must match the '{format}' format", [
- 'format' => $this->name,
- 'type' => $type,
- ]);
- }
+ if ( $ok ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'format',
+ "The data must match the '{format}' format",
+ array(
+ 'format' => $this->name,
+ 'type' => $type,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/IfThenElseKeyword.php b/src/opis/json-schema/src/Keywords/IfThenElseKeyword.php
index ef3650fa..f744a35a 100644
--- a/src/opis/json-schema/src/Keywords/IfThenElseKeyword.php
+++ b/src/opis/json-schema/src/Keywords/IfThenElseKeyword.php
@@ -1,5 +1,6 @@
if = $if;
- $this->then = $then;
- $this->else = $else;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($this->if === true) {
- return $this->validateBranch('then', $context, $schema);
- } elseif ($this->if === false) {
- return $this->validateBranch('else', $context, $schema);
- }
-
- if (is_object($this->if) && !($this->if instanceof Schema)) {
- $this->if = $context->loader()->loadObjectSchema($this->if);
- }
-
- if ($context->validateSchemaWithoutEvaluated($this->if, null, true)) {
- return $this->validateBranch('else', $context, $schema);
- }
-
- return $this->validateBranch('then', $context, $schema);
- }
-
- /**
- * @param string $branch
- * @param ValidationContext $context
- * @param Schema $schema
- * @return ValidationError|null
- */
- protected function validateBranch($branch, $context, $schema)
- {
- $value = $this->{$branch};
-
- if ($value === true) {
- return null;
- } elseif ($value === false) {
- return $this->error($schema, $context, $branch, "The data is never valid on '{branch}' branch", [
- 'branch' => $branch,
- ]);
- }
-
- if (is_object($value) && !($value instanceof Schema)) {
- $value = $this->{$branch} = $context->loader()->loadObjectSchema($value);
- }
-
- if ($error = $value->validate($context)) {
- return $this->error($schema, $context, $branch, "The data is not valid on '{branch}' branch", [
- 'branch' => $branch,
- ], $error);
- }
-
- return null;
- }
+class IfThenElseKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /** @var bool|object */
+ protected $if;
+
+ /** @var bool|object */
+ protected $then;
+
+ /** @var bool|object */
+ protected $else;
+
+ /**
+ * @param bool|object $if
+ * @param bool|object $then
+ * @param bool|object $else
+ */
+ public function __construct( $if, $then, $else ) {
+ $this->if = $if;
+ $this->then = $then;
+ $this->else = $else;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $this->if === true ) {
+ return $this->validateBranch( 'then', $context, $schema );
+ } elseif ( $this->if === false ) {
+ return $this->validateBranch( 'else', $context, $schema );
+ }
+
+ if ( is_object( $this->if ) && ! ( $this->if instanceof Schema ) ) {
+ $this->if = $context->loader()->loadObjectSchema( $this->if );
+ }
+
+ if ( $context->validateSchemaWithoutEvaluated( $this->if, null, true ) ) {
+ return $this->validateBranch( 'else', $context, $schema );
+ }
+
+ return $this->validateBranch( 'then', $context, $schema );
+ }
+
+ /**
+ * @param string $branch
+ * @param ValidationContext $context
+ * @param Schema $schema
+ * @return ValidationError|null
+ */
+ protected function validateBranch( $branch, $context, $schema ) {
+ $value = $this->{$branch};
+
+ if ( $value === true ) {
+ return null;
+ } elseif ( $value === false ) {
+ return $this->error(
+ $schema,
+ $context,
+ $branch,
+ "The data is never valid on '{branch}' branch",
+ array(
+ 'branch' => $branch,
+ )
+ );
+ }
+
+ if ( is_object( $value ) && ! ( $value instanceof Schema ) ) {
+ $value = $this->{$branch} = $context->loader()->loadObjectSchema( $value );
+ }
+
+ if ( $error = $value->validate( $context ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ $branch,
+ "The data is not valid on '{branch}' branch",
+ array(
+ 'branch' => $branch,
+ ),
+ $error
+ );
+ }
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/ItemsKeyword.php b/src/opis/json-schema/src/Keywords/ItemsKeyword.php
index ce4bc32e..7dac10dc 100644
--- a/src/opis/json-schema/src/Keywords/ItemsKeyword.php
+++ b/src/opis/json-schema/src/Keywords/ItemsKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- $this->alwaysValid = $alwaysValid;
-
- if (is_array($value)) {
- $this->count = count($value);
- }
-
- $this->keyword = $keyword;
- $this->startIndex = $startIndex;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($this->alwaysValid || $this->value === true) {
- if ($this->count === -1) {
- $context->markAllAsEvaluatedItems();
- } else {
- $context->markCountAsEvaluatedItems($this->count);
- }
- return null;
- }
-
- $count = count($context->currentData());
-
- if ($this->startIndex >= $count) {
- // Already validated by other keyword
- return null;
- }
-
- if ($this->value === false) {
- if ($count === 0) {
- return null;
- }
-
- return $this->error($schema, $context, $this->keyword, 'Array must be empty');
- }
-
- if ($this->count >= 0) {
-
- $errors = $this->errorContainer($context->maxErrors());
- $max = min($count, $this->count);
- $evaluated = [];
-
- for ($i = $this->startIndex; $i < $max; $i++) {
- if ($this->value[$i] === true) {
- $evaluated[] = $i;
- continue;
- }
-
- if ($this->value[$i] === false) {
- $context->addEvaluatedItems($evaluated);
- return $this->error($schema, $context, $this->keyword, "Array item at index {index} is not allowed", [
- 'index' => $i,
- ]);
- }
-
- if (is_object($this->value[$i]) && !($this->value[$i] instanceof Schema)) {
- $this->value[$i] = $context->loader()->loadObjectSchema($this->value[$i]);
- }
-
- $context->pushDataPath($i);
- $error = $this->value[$i]->validate($context);
- $context->popDataPath();
-
- if ($error) {
- $errors->add($error);
- if ($errors->isFull()) {
- break;
- }
- } else {
- $evaluated[] = $i;
- }
- }
-
- $context->addEvaluatedItems($evaluated);
-
- if ($errors->isEmpty()) {
- return null;
- }
-
- return $this->error($schema, $context, $this->keyword, 'Array items must match corresponding schemas', [],
- $errors);
- }
-
- if (is_object($this->value) && !($this->value instanceof Schema)) {
- $this->value = $context->loader()->loadObjectSchema($this->value);
- }
-
- $object = $this->createArrayObject($context);
-
- $error = $this->validateIterableData($schema, $this->value, $context, $this->indexes($this->startIndex, $count),
- $this->keyword, 'All array items must match schema', [], $object);
-
- if ($object && $object->count()) {
- $context->addEvaluatedItems($object->getArrayCopy());
- }
-
- return $error;
- }
-
- /**
- * @param int $start
- * @param int $max
- * @return iterable|int[]
- */
- protected function indexes($start, $max)
- {
- for ($i = $start; $i < $max; $i++) {
- yield $i;
- }
- }
+class ItemsKeyword implements Keyword {
+
+ use OfTrait;
+ use IterableDataValidationTrait;
+
+ /** @var bool|object|Schema|bool[]|object[]|Schema[] */
+ protected $value;
+
+ /**
+ * @var int
+ */
+ protected $count = -1;
+ /**
+ * @var bool
+ */
+ protected $alwaysValid;
+ /**
+ * @var string
+ */
+ protected $keyword;
+ /**
+ * @var int
+ */
+ protected $startIndex;
+
+ /**
+ * @param bool|object|Schema|bool[]|object[]|Schema[] $value
+ * @param bool $alwaysValid
+ * @param string $keyword
+ * @param int $startIndex
+ */
+ public function __construct( $value, bool $alwaysValid = false, string $keyword = 'items', int $startIndex = 0 ) {
+ $this->value = $value;
+ $this->alwaysValid = $alwaysValid;
+
+ if ( is_array( $value ) ) {
+ $this->count = count( $value );
+ }
+
+ $this->keyword = $keyword;
+ $this->startIndex = $startIndex;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $this->alwaysValid || $this->value === true ) {
+ if ( $this->count === -1 ) {
+ $context->markAllAsEvaluatedItems();
+ } else {
+ $context->markCountAsEvaluatedItems( $this->count );
+ }
+ return null;
+ }
+
+ $count = count( $context->currentData() );
+
+ if ( $this->startIndex >= $count ) {
+ // Already validated by other keyword
+ return null;
+ }
+
+ if ( $this->value === false ) {
+ if ( $count === 0 ) {
+ return null;
+ }
+
+ return $this->error( $schema, $context, $this->keyword, 'Array must be empty' );
+ }
+
+ if ( $this->count >= 0 ) {
+
+ $errors = $this->errorContainer( $context->maxErrors() );
+ $max = min( $count, $this->count );
+ $evaluated = array();
+
+ for ( $i = $this->startIndex; $i < $max; $i++ ) {
+ if ( $this->value[ $i ] === true ) {
+ $evaluated[] = $i;
+ continue;
+ }
+
+ if ( $this->value[ $i ] === false ) {
+ $context->addEvaluatedItems( $evaluated );
+ return $this->error(
+ $schema,
+ $context,
+ $this->keyword,
+ 'Array item at index {index} is not allowed',
+ array(
+ 'index' => $i,
+ )
+ );
+ }
+
+ if ( is_object( $this->value[ $i ] ) && ! ( $this->value[ $i ] instanceof Schema ) ) {
+ $this->value[ $i ] = $context->loader()->loadObjectSchema( $this->value[ $i ] );
+ }
+
+ $context->pushDataPath( $i );
+ $error = $this->value[ $i ]->validate( $context );
+ $context->popDataPath();
+
+ if ( $error ) {
+ $errors->add( $error );
+ if ( $errors->isFull() ) {
+ break;
+ }
+ } else {
+ $evaluated[] = $i;
+ }
+ }
+
+ $context->addEvaluatedItems( $evaluated );
+
+ if ( $errors->isEmpty() ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ $this->keyword,
+ 'Array items must match corresponding schemas',
+ array(),
+ $errors
+ );
+ }
+
+ if ( is_object( $this->value ) && ! ( $this->value instanceof Schema ) ) {
+ $this->value = $context->loader()->loadObjectSchema( $this->value );
+ }
+
+ $object = $this->createArrayObject( $context );
+
+ $error = $this->validateIterableData(
+ $schema,
+ $this->value,
+ $context,
+ $this->indexes( $this->startIndex, $count ),
+ $this->keyword,
+ 'All array items must match schema',
+ array(),
+ $object
+ );
+
+ if ( $object && $object->count() ) {
+ $context->addEvaluatedItems( $object->getArrayCopy() );
+ }
+
+ return $error;
+ }
+
+ /**
+ * @param int $start
+ * @param int $max
+ * @return iterable|int[]
+ */
+ protected function indexes( $start, $max ) {
+ for ( $i = $start; $i < $max; $i++ ) {
+ yield $i;
+ }
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/IterableDataValidationTrait.php b/src/opis/json-schema/src/Keywords/IterableDataValidationTrait.php
index d9f4780e..a9ae4c4f 100644
--- a/src/opis/json-schema/src/Keywords/IterableDataValidationTrait.php
+++ b/src/opis/json-schema/src/Keywords/IterableDataValidationTrait.php
@@ -1,5 +1,6 @@
errorContainer($context->maxErrors());
+ /**
+ * @param int $maxErrors
+ * @return ErrorContainer
+ */
+ protected function errorContainer( $maxErrors = 1 ): ErrorContainer {
+ return new ErrorContainer( $maxErrors );
+ }
- if ($keys) {
- foreach ($iterator as $key) {
- $context->pushDataPath($key);
- $error = $schema->validate($context);
- $context->popDataPath();
+ /**
+ * @param Schema $schema
+ * @param ValidationContext $context
+ * @param iterable $iterator
+ * @param ArrayObject|null $keys
+ * @return ErrorContainer
+ */
+ protected function iterateAndValidate(
+ $schema,
+ $context,
+ $iterator,
+ $keys = null
+ ): ErrorContainer {
+ $container = $this->errorContainer( $context->maxErrors() );
- if ($error) {
- if (!$container->isFull()) {
- $container->add($error);
- }
- } else {
- $keys[] = $key;
- }
- }
- } else {
- foreach ($iterator as $key) {
- $context->pushDataPath($key);
- $error = $schema->validate($context);
- $context->popDataPath();
+ if ( $keys ) {
+ foreach ( $iterator as $key ) {
+ $context->pushDataPath( $key );
+ $error = $schema->validate( $context );
+ $context->popDataPath();
- if ($error && $container->add($error)->isFull()) {
- break;
- }
- }
- }
+ if ( $error ) {
+ if ( ! $container->isFull() ) {
+ $container->add( $error );
+ }
+ } else {
+ $keys[] = $key;
+ }
+ }
+ } else {
+ foreach ( $iterator as $key ) {
+ $context->pushDataPath( $key );
+ $error = $schema->validate( $context );
+ $context->popDataPath();
- return $container;
- }
+ if ( $error && $container->add( $error )->isFull() ) {
+ break;
+ }
+ }
+ }
- /**
- * @param Schema $parentSchema
- * @param Schema $schema
- * @param ValidationContext $context
- * @param iterable $iterator
- * @param string $keyword
- * @param string $message
- * @param array $args
- * @param ArrayObject|null $visited_keys
- * @return ValidationError|null
- */
- protected function validateIterableData(
- $parentSchema,
- $schema,
- $context,
- $iterator,
- $keyword,
- $message,
- $args = [],
- $visited_keys = null
- ) {
- $errors = $this->iterateAndValidate($schema, $context, $iterator, $visited_keys);
+ return $container;
+ }
- if ($errors->isEmpty()) {
- return null;
- }
+ /**
+ * @param Schema $parentSchema
+ * @param Schema $schema
+ * @param ValidationContext $context
+ * @param iterable $iterator
+ * @param string $keyword
+ * @param string $message
+ * @param array $args
+ * @param ArrayObject|null $visited_keys
+ * @return ValidationError|null
+ */
+ protected function validateIterableData(
+ $parentSchema,
+ $schema,
+ $context,
+ $iterator,
+ $keyword,
+ $message,
+ $args = array(),
+ $visited_keys = null
+ ) {
+ $errors = $this->iterateAndValidate( $schema, $context, $iterator, $visited_keys );
- return $this->error($parentSchema, $context, $keyword, $message, $args, $errors);
- }
+ if ( $errors->isEmpty() ) {
+ return null;
+ }
+
+ return $this->error( $parentSchema, $context, $keyword, $message, $args, $errors );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MaxItemsDataKeyword.php b/src/opis/json-schema/src/Keywords/MaxItemsDataKeyword.php
index f846fdba..5c98c13f 100644
--- a/src/opis/json-schema/src/Keywords/MaxItemsDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MaxItemsDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var int $count */
- $count = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($count === $this || !is_int($count) || $count < 0) {
- return $this->error($schema, $context, 'maxItems', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->count = $count;
-
- return parent::validate($context, $schema);
- }
+class MaxItemsDataKeyword extends MaxItemsKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var int $count */
+ $count = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $count === $this || ! is_int( $count ) || $count < 0 ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'maxItems',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->count = $count;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MaxItemsKeyword.php b/src/opis/json-schema/src/Keywords/MaxItemsKeyword.php
index feb3fce0..3f7f0b04 100644
--- a/src/opis/json-schema/src/Keywords/MaxItemsKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MaxItemsKeyword.php
@@ -1,5 +1,6 @@
count = $count;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $count = count($context->currentData());
-
- if ($count <= $this->count) {
- return null;
- }
-
- return $this->error($schema, $context, "maxItems",
- "Array should have at most {max} items, {count} found", [
- 'max' => $this->count,
- 'count' => $count,
- ]);
- }
+class MaxItemsKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var int
+ */
+ protected $count;
+
+ /**
+ * @param int $count
+ */
+ public function __construct( int $count ) {
+ $this->count = $count;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $count = count( $context->currentData() );
+
+ if ( $count <= $this->count ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'maxItems',
+ 'Array should have at most {max} items, {count} found',
+ array(
+ 'max' => $this->count,
+ 'count' => $count,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MaxLengthDataKeyword.php b/src/opis/json-schema/src/Keywords/MaxLengthDataKeyword.php
index acf42128..fbf5734d 100644
--- a/src/opis/json-schema/src/Keywords/MaxLengthDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MaxLengthDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var int $length */
- $length = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($length === $this || !is_int($length) || $length < 0) {
- return $this->error($schema, $context, 'maxLength', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->length = $length;
-
- return parent::validate($context, $schema);
- }
+class MaxLengthDataKeyword extends MaxLengthKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var int $length */
+ $length = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $length === $this || ! is_int( $length ) || $length < 0 ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'maxLength',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->length = $length;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MaxLengthKeyword.php b/src/opis/json-schema/src/Keywords/MaxLengthKeyword.php
index b1978559..72777a99 100644
--- a/src/opis/json-schema/src/Keywords/MaxLengthKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MaxLengthKeyword.php
@@ -1,5 +1,6 @@
length = $length;
- }
+ /**
+ * @var int
+ */
+ protected $length;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($this->length === 0) {
- return null;
- }
+ /**
+ * @param int $length
+ */
+ public function __construct( int $length ) {
+ $this->length = $length;
+ }
- $length = $context->getStringLength();
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $this->length === 0 ) {
+ return null;
+ }
- if ($length <= $this->length) {
- return null;
- }
+ $length = $context->getStringLength();
- return $this->error($schema, $context, 'maxLength', "Maximum string length is {max}, found {length}",
- [
- 'max' => $this->length,
- 'length' => $length,
- ]);
- }
+ if ( $length <= $this->length ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'maxLength',
+ 'Maximum string length is {max}, found {length}',
+ array(
+ 'max' => $this->length,
+ 'length' => $length,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MaxPropertiesDataKeyword.php b/src/opis/json-schema/src/Keywords/MaxPropertiesDataKeyword.php
index 14ea37dd..1f31f44c 100644
--- a/src/opis/json-schema/src/Keywords/MaxPropertiesDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MaxPropertiesDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var int $count */
- $count = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($count === $this || !is_int($count) || $count < 0) {
- return $this->error($schema, $context, 'maxProperties', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->count = $count;
-
- return parent::validate($context, $schema);
- }
+class MaxPropertiesDataKeyword extends MaxPropertiesKeywords {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @inheritDoc
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var int $count */
+ $count = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $count === $this || ! is_int( $count ) || $count < 0 ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'maxProperties',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->count = $count;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MaxPropertiesKeywords.php b/src/opis/json-schema/src/Keywords/MaxPropertiesKeywords.php
index e9f948a3..14674529 100644
--- a/src/opis/json-schema/src/Keywords/MaxPropertiesKeywords.php
+++ b/src/opis/json-schema/src/Keywords/MaxPropertiesKeywords.php
@@ -1,5 +1,6 @@
count = $count;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $count = count($context->getObjectProperties());
-
- if ($count <= $this->count) {
- return null;
- }
-
- return $this->error($schema, $context, 'maxProperties',
- "Object must have at most {max} properties, {count} found", [
- 'max' => $this->count,
- 'count' => $count,
- ]);
- }
+class MaxPropertiesKeywords implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var int
+ */
+ protected $count;
+
+ /**
+ * @param int $count
+ */
+ public function __construct( int $count ) {
+ $this->count = $count;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $count = count( $context->getObjectProperties() );
+
+ if ( $count <= $this->count ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'maxProperties',
+ 'Object must have at most {max} properties, {count} found',
+ array(
+ 'max' => $this->count,
+ 'count' => $count,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MaximumDataKeyword.php b/src/opis/json-schema/src/Keywords/MaximumDataKeyword.php
index 6cb7dd16..550d696d 100644
--- a/src/opis/json-schema/src/Keywords/MaximumDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MaximumDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var float|int $number */
- $number = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($number === $this || !(is_float($number) || is_int($number))) {
- return $this->error($schema, $context, 'maximum', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->number = $number;
-
- return parent::validate($context, $schema);
- }
+class MaximumDataKeyword extends MaximumKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var float|int $number */
+ $number = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $number === $this || ! ( is_float( $number ) || is_int( $number ) ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'maximum',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->number = $number;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MaximumKeyword.php b/src/opis/json-schema/src/Keywords/MaximumKeyword.php
index a0ab6c4f..7d583931 100644
--- a/src/opis/json-schema/src/Keywords/MaximumKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MaximumKeyword.php
@@ -1,5 +1,6 @@
number = $number;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($context->currentData() <= $this->number) {
- return null;
- }
-
- return $this->error($schema, $context, 'maximum', "Number must be lower than or equal to {max}", [
- 'max' => $this->number,
- ]);
- }
+class MaximumKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var float
+ */
+ protected $number;
+
+ /**
+ * @param float $number
+ */
+ public function __construct( float $number ) {
+ $this->number = $number;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $context->currentData() <= $this->number ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'maximum',
+ 'Number must be lower than or equal to {max}',
+ array(
+ 'max' => $this->number,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MinItemsDataKeyword.php b/src/opis/json-schema/src/Keywords/MinItemsDataKeyword.php
index c175c9c1..f37f950b 100644
--- a/src/opis/json-schema/src/Keywords/MinItemsDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MinItemsDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var int $count */
- $count = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($count === $this || !is_int($count) || $count < 0) {
- return $this->error($schema, $context, 'minItems', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->count = $count;
-
- return parent::validate($context, $schema);
- }
+class MinItemsDataKeyword extends MinItemsKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var int $count */
+ $count = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $count === $this || ! is_int( $count ) || $count < 0 ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'minItems',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->count = $count;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MinItemsKeyword.php b/src/opis/json-schema/src/Keywords/MinItemsKeyword.php
index 60a86e6f..a690e52e 100644
--- a/src/opis/json-schema/src/Keywords/MinItemsKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MinItemsKeyword.php
@@ -1,5 +1,6 @@
count = $count;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $count = count($context->currentData());
-
- if ($count >= $this->count) {
- return null;
- }
-
- return $this->error($schema, $context, "minItems",
- "Array should have at least {min} items, {count} found", [
- 'min' => $this->count,
- 'count' => $count,
- ]);
- }
+class MinItemsKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var int
+ */
+ protected $count;
+
+ /**
+ * @param int $count
+ */
+ public function __construct( int $count ) {
+ $this->count = $count;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $count = count( $context->currentData() );
+
+ if ( $count >= $this->count ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'minItems',
+ 'Array should have at least {min} items, {count} found',
+ array(
+ 'min' => $this->count,
+ 'count' => $count,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MinLengthDataKeyword.php b/src/opis/json-schema/src/Keywords/MinLengthDataKeyword.php
index c579ba07..3eb0acb6 100644
--- a/src/opis/json-schema/src/Keywords/MinLengthDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MinLengthDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var int $length */
- $length = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($length === $this || !is_int($length) || $length < 0) {
- return $this->error($schema, $context, 'minLength', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->length = $length;
-
- return parent::validate($context, $schema);
- }
+class MinLengthDataKeyword extends MinLengthKeyword {
+
+ /** @var JsonPointer */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var int $length */
+ $length = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $length === $this || ! is_int( $length ) || $length < 0 ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'minLength',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->length = $length;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MinLengthKeyword.php b/src/opis/json-schema/src/Keywords/MinLengthKeyword.php
index 6e0b1596..cb5a0a94 100644
--- a/src/opis/json-schema/src/Keywords/MinLengthKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MinLengthKeyword.php
@@ -1,5 +1,6 @@
length = $length;
- }
+ /**
+ * @var int
+ */
+ protected $length;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($this->length === 0) {
- return null;
- }
+ /**
+ * @param int $length
+ */
+ public function __construct( int $length ) {
+ $this->length = $length;
+ }
- $length = $context->getStringLength();
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $this->length === 0 ) {
+ return null;
+ }
- if ($length >= $this->length) {
- return null;
- }
+ $length = $context->getStringLength();
- return $this->error($schema, $context, 'minLength', "Minimum string length is {min}, found {length}", [
- 'min' => $this->length,
- 'length' => $length,
- ]);
- }
+ if ( $length >= $this->length ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'minLength',
+ 'Minimum string length is {min}, found {length}',
+ array(
+ 'min' => $this->length,
+ 'length' => $length,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MinPropertiesDataKeyword.php b/src/opis/json-schema/src/Keywords/MinPropertiesDataKeyword.php
index b1f06cfe..cd53bfdd 100644
--- a/src/opis/json-schema/src/Keywords/MinPropertiesDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MinPropertiesDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var int $count */
- $count = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($count === $this || !is_int($count) || $count < 0) {
- return $this->error($schema, $context, 'minProperties', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->count = $count;
-
- return parent::validate($context, $schema);
- }
+class MinPropertiesDataKeyword extends MinPropertiesKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var int $count */
+ $count = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $count === $this || ! is_int( $count ) || $count < 0 ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'minProperties',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->count = $count;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MinPropertiesKeyword.php b/src/opis/json-schema/src/Keywords/MinPropertiesKeyword.php
index 0a9eb1e1..8082e133 100644
--- a/src/opis/json-schema/src/Keywords/MinPropertiesKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MinPropertiesKeyword.php
@@ -1,5 +1,6 @@
count = $count;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $count = count($context->getObjectProperties());
-
- if ($this->count <= $count) {
- return null;
- }
-
- return $this->error($schema, $context, 'minProperties',
- "Object must have at least {min} properties, {count} found", [
- 'min' => $this->count,
- 'count' => $count,
- ]);
- }
+class MinPropertiesKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var int
+ */
+ protected $count;
+
+ /**
+ * @param int $count
+ */
+ public function __construct( int $count ) {
+ $this->count = $count;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $count = count( $context->getObjectProperties() );
+
+ if ( $this->count <= $count ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'minProperties',
+ 'Object must have at least {min} properties, {count} found',
+ array(
+ 'min' => $this->count,
+ 'count' => $count,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MinimumDataKeyword.php b/src/opis/json-schema/src/Keywords/MinimumDataKeyword.php
index 77335dd1..48d56654 100644
--- a/src/opis/json-schema/src/Keywords/MinimumDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MinimumDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var float|int $number */
- $number = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($number === $this || !(is_float($number) || is_int($number))) {
- return $this->error($schema, $context, 'minimum', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->number = $number;
-
- return parent::validate($context, $schema);
- }
+class MinimumDataKeyword extends MinimumKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var float|int $number */
+ $number = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $number === $this || ! ( is_float( $number ) || is_int( $number ) ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'minimum',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->number = $number;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MinimumKeyword.php b/src/opis/json-schema/src/Keywords/MinimumKeyword.php
index 99c67ffb..bd4cc412 100644
--- a/src/opis/json-schema/src/Keywords/MinimumKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MinimumKeyword.php
@@ -1,5 +1,6 @@
number = $number;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($context->currentData() >= $this->number) {
- return null;
- }
-
- return $this->error($schema, $context, 'minimum', "Number must be greater than or equal to {min}", [
- 'min' => $this->number,
- ]);
- }
+class MinimumKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var float
+ */
+ protected $number;
+
+ /**
+ * @param float $number
+ */
+ public function __construct( float $number ) {
+ $this->number = $number;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $context->currentData() >= $this->number ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'minimum',
+ 'Number must be greater than or equal to {min}',
+ array(
+ 'min' => $this->number,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MultipleOfDataKeyword.php b/src/opis/json-schema/src/Keywords/MultipleOfDataKeyword.php
index a32df2b0..87d61b4b 100644
--- a/src/opis/json-schema/src/Keywords/MultipleOfDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MultipleOfDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct(0);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- /** @var float|int $number */
- $number = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($number === $this || !(is_float($number) || is_int($number)) || $number <= 0) {
- return $this->error($schema, $context, 'multipleOf', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->number = $number;
-
- return parent::validate($context, $schema);
- }
+class MultipleOfDataKeyword extends MultipleOfKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( 0 );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ /** @var float|int $number */
+ $number = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $number === $this || ! ( is_float( $number ) || is_int( $number ) ) || $number <= 0 ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'multipleOf',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->number = $number;
+
+ return parent::validate( $context, $schema );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/MultipleOfKeyword.php b/src/opis/json-schema/src/Keywords/MultipleOfKeyword.php
index be324434..734062b7 100644
--- a/src/opis/json-schema/src/Keywords/MultipleOfKeyword.php
+++ b/src/opis/json-schema/src/Keywords/MultipleOfKeyword.php
@@ -1,5 +1,6 @@
number = $number;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if (Helper::isMultipleOf($context->currentData(), $this->number)) {
- return null;
- }
-
- return $this->error($schema, $context, 'multipleOf', "Number must be a multiple of {divisor}", [
- 'divisor' => $this->number,
- ]);
- }
+class MultipleOfKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var float
+ */
+ protected $number;
+
+ /**
+ * @param float $number
+ */
+ public function __construct( float $number ) {
+ $this->number = $number;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( Helper::isMultipleOf( $context->currentData(), $this->number ) ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'multipleOf',
+ 'Number must be a multiple of {divisor}',
+ array(
+ 'divisor' => $this->number,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/NotKeyword.php b/src/opis/json-schema/src/Keywords/NotKeyword.php
index 39dc7751..fbe7958b 100644
--- a/src/opis/json-schema/src/Keywords/NotKeyword.php
+++ b/src/opis/json-schema/src/Keywords/NotKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
+ /** @var bool|object|Schema */
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($this->value === false) {
- return null;
- }
- if ($this->value === true) {
- return $this->error($schema, $context, 'not', "The data is never valid");
- }
+ /**
+ * @param bool|object $value
+ */
+ public function __construct( $value ) {
+ $this->value = $value;
+ }
- if (is_object($this->value) && !($this->value instanceof Schema)) {
- $this->value = $context->loader()->loadObjectSchema($this->value);
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $this->value === false ) {
+ return null;
+ }
+ if ( $this->value === true ) {
+ return $this->error( $schema, $context, 'not', 'The data is never valid' );
+ }
- $error = $context->validateSchemaWithoutEvaluated($this->value, 1);
+ if ( is_object( $this->value ) && ! ( $this->value instanceof Schema ) ) {
+ $this->value = $context->loader()->loadObjectSchema( $this->value );
+ }
- if ($error) {
- return null;
- }
+ $error = $context->validateSchemaWithoutEvaluated( $this->value, 1 );
- return $this->error($schema, $context, 'not', 'The data must not match schema');
- }
+ if ( $error ) {
+ return null;
+ }
+
+ return $this->error( $schema, $context, 'not', 'The data must not match schema' );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/OfTrait.php b/src/opis/json-schema/src/Keywords/OfTrait.php
index 2cef55b1..a0c1e81b 100644
--- a/src/opis/json-schema/src/Keywords/OfTrait.php
+++ b/src/opis/json-schema/src/Keywords/OfTrait.php
@@ -1,5 +1,6 @@
trackUnevaluated() ? new ArrayObject() : null;
- }
+trait OfTrait {
- /**
- * @param \ArrayObject|null $object
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- protected function addEvaluatedFromArrayObject($object, $context)
- {
- if (!$object || !$object->count()) {
- return;
- }
+ /**
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ protected function createArrayObject( $context ) {
+ return $context->trackUnevaluated() ? new ArrayObject() : null;
+ }
- foreach ($object as $value) {
- if (isset($value['properties'])) {
- $context->addEvaluatedProperties($value['properties']);
- }
- if (isset($value['items'])) {
- $context->addEvaluatedItems($value['items']);
- }
- }
- }
+ /**
+ * @param \ArrayObject|null $object
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ protected function addEvaluatedFromArrayObject( $object, $context ) {
+ if ( ! $object || ! $object->count() ) {
+ return;
+ }
+
+ foreach ( $object as $value ) {
+ if ( isset( $value['properties'] ) ) {
+ $context->addEvaluatedProperties( $value['properties'] );
+ }
+ if ( isset( $value['items'] ) ) {
+ $context->addEvaluatedItems( $value['items'] );
+ }
+ }
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/OneOfKeyword.php b/src/opis/json-schema/src/Keywords/OneOfKeyword.php
index fdbed540..1f7aca2b 100644
--- a/src/opis/json-schema/src/Keywords/OneOfKeyword.php
+++ b/src/opis/json-schema/src/Keywords/OneOfKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
+ /** @var bool[]|object[] */
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $count = 0;
- $matchedIndex = -1;
- $object = $this->createArrayObject($context);
- $errors = [];
+ /**
+ * @param bool[]|object[] $value
+ */
+ public function __construct( array $value ) {
+ $this->value = $value;
+ }
- foreach ($this->value as $index => $value) {
- if ($value === false) {
- continue;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $count = 0;
+ $matchedIndex = -1;
+ $object = $this->createArrayObject( $context );
+ $errors = array();
- if ($value === true) {
- if (++$count > 1) {
- $this->addEvaluatedFromArrayObject($object, $context);
- return $this->error($schema, $context, 'oneOf', 'The data should match exactly one schema', [
- 'matched' => [$matchedIndex, $index],
- ]);
- }
+ foreach ( $this->value as $index => $value ) {
+ if ( $value === false ) {
+ continue;
+ }
- $matchedIndex = $index;
- continue;
- }
+ if ( $value === true ) {
+ if ( ++$count > 1 ) {
+ $this->addEvaluatedFromArrayObject( $object, $context );
+ return $this->error(
+ $schema,
+ $context,
+ 'oneOf',
+ 'The data should match exactly one schema',
+ array(
+ 'matched' => array( $matchedIndex, $index ),
+ )
+ );
+ }
- if (is_object($value) && !($value instanceof Schema)) {
- $value = $this->value[$index] = $context->loader()->loadObjectSchema($value);
- }
+ $matchedIndex = $index;
+ continue;
+ }
- $error = $context->validateSchemaWithoutEvaluated($value, null, false, $object);
- if ($error) {
- $errors[] = $error;
- } else {
- if (++$count > 1) {
- $this->addEvaluatedFromArrayObject($object, $context);
- return $this->error($schema, $context, 'oneOf', 'The data should match exactly one schema', [
- 'matched' => [$matchedIndex, $index],
- ]);
- }
- $matchedIndex = $index;
- }
- }
+ if ( is_object( $value ) && ! ( $value instanceof Schema ) ) {
+ $value = $this->value[ $index ] = $context->loader()->loadObjectSchema( $value );
+ }
- $this->addEvaluatedFromArrayObject($object, $context);
+ $error = $context->validateSchemaWithoutEvaluated( $value, null, false, $object );
+ if ( $error ) {
+ $errors[] = $error;
+ } else {
+ if ( ++$count > 1 ) {
+ $this->addEvaluatedFromArrayObject( $object, $context );
+ return $this->error(
+ $schema,
+ $context,
+ 'oneOf',
+ 'The data should match exactly one schema',
+ array(
+ 'matched' => array( $matchedIndex, $index ),
+ )
+ );
+ }
+ $matchedIndex = $index;
+ }
+ }
- if ($count === 1) {
- return null;
- }
+ $this->addEvaluatedFromArrayObject( $object, $context );
- return $this->error($schema, $context, 'oneOf', 'The data should match exactly one schema', [
- 'matched' => [],
- ], $errors);
- }
+ if ( $count === 1 ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'oneOf',
+ 'The data should match exactly one schema',
+ array(
+ 'matched' => array(),
+ ),
+ $errors
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/PatternDataKeyword.php b/src/opis/json-schema/src/Keywords/PatternDataKeyword.php
index a64592d0..be2ff775 100644
--- a/src/opis/json-schema/src/Keywords/PatternDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/PatternDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- parent::__construct('');
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $pattern = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
- if ($pattern === $this || !is_string($pattern) || !Helper::isValidPattern($pattern)) {
- return $this->error($schema, $context, 'pattern', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- $this->pattern = $pattern;
- $this->regex = Helper::patternToRegex($pattern);
- $ret = parent::validate($context, $schema);
- $this->pattern = $this->regex = null;
-
- return $ret;
- }
+class PatternDataKeyword extends PatternKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ parent::__construct( '' );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $pattern = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+ if ( $pattern === $this || ! is_string( $pattern ) || ! Helper::isValidPattern( $pattern ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'pattern',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ $this->pattern = $pattern;
+ $this->regex = Helper::patternToRegex( $pattern );
+ $ret = parent::validate( $context, $schema );
+ $this->pattern = $this->regex = null;
+
+ return $ret;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/PatternKeyword.php b/src/opis/json-schema/src/Keywords/PatternKeyword.php
index cb50a622..1f59303d 100644
--- a/src/opis/json-schema/src/Keywords/PatternKeyword.php
+++ b/src/opis/json-schema/src/Keywords/PatternKeyword.php
@@ -1,5 +1,6 @@
pattern = $pattern;
- $this->regex = Helper::patternToRegex($pattern);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if (preg_match($this->regex, $context->currentData())) {
- return null;
- }
-
- return $this->error($schema, $context, 'pattern', "The string should match pattern: {pattern}", [
- 'pattern' => $this->pattern,
- ]);
- }
+class PatternKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @var string|null
+ */
+ protected $pattern;
+
+ /**
+ * @var string|null
+ */
+ protected $regex;
+
+ /**
+ * @param string $pattern
+ */
+ public function __construct( string $pattern ) {
+ $this->pattern = $pattern;
+ $this->regex = Helper::patternToRegex( $pattern );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( preg_match( $this->regex, $context->currentData() ) ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'pattern',
+ 'The string should match pattern: {pattern}',
+ array(
+ 'pattern' => $this->pattern,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/PatternPropertiesKeyword.php b/src/opis/json-schema/src/Keywords/PatternPropertiesKeyword.php
index d1f90580..1ed852d1 100644
--- a/src/opis/json-schema/src/Keywords/PatternPropertiesKeyword.php
+++ b/src/opis/json-schema/src/Keywords/PatternPropertiesKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $props = $context->getObjectProperties();
-
- if (!$props) {
- return null;
- }
-
- $checked = [];
-
- foreach ($this->value as $pattern => $value) {
- if ($value === true) {
- iterator_to_array($this->matchedProperties($pattern, $props, $checked));
- continue;
- }
-
- if ($value === false) {
- $list = iterator_to_array($this->matchedProperties($pattern, $props, $checked));
-
- if ($list) {
- if ($context->trackUnevaluated()) {
- $context->addEvaluatedProperties(array_diff(array_keys($checked), $list));
- }
- return $this->error($schema, $context, 'patternProperties', "Object properties that match pattern '{pattern}' are not allowed", [
- 'pattern' => $pattern,
- 'forbidden' => $list,
- ]);
- }
-
- unset($list);
- continue;
- }
-
- if (is_object($value) && !($value instanceof Schema)) {
- $value = $this->value[$pattern] = $context->loader()->loadObjectSchema($value);
- }
-
- $subErrors = $this->iterateAndValidate($value, $context, $this->matchedProperties($pattern, $props, $checked));
-
- if (!$subErrors->isEmpty()) {
- if ($context->trackUnevaluated()) {
- $context->addEvaluatedProperties(array_keys($checked));
- }
- return $this->error($schema, $context, 'patternProperties', "Object properties that match pattern '{pattern}' must also match pattern's schema", [
- 'pattern' => $pattern,
- ], $subErrors);
- }
-
- unset($subErrors);
- }
-
- if ($checked) {
- $checked = array_keys($checked);
- $context->addCheckedProperties($checked);
- $context->addEvaluatedProperties($checked);
- }
-
- return null;
- }
-
- /**
- * @param string $pattern
- * @param array $props
- * @param array $checked
- * @return Traversable|string[]
- */
- protected function matchedProperties($pattern, $props, &$checked): Traversable
- {
- $pattern = Helper::patternToRegex($pattern);
-
- foreach ($props as $prop) {
- if (preg_match($pattern, (string)$prop)) {
- $checked[$prop] = true;
- yield $prop;
- }
- }
- }
+class PatternPropertiesKeyword implements Keyword {
+
+ use IterableDataValidationTrait;
+
+ /** @var bool[]|object[] */
+ protected $value;
+
+ /**
+ * @param bool[]|object[] $value
+ */
+ public function __construct( array $value ) {
+ $this->value = $value;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $props = $context->getObjectProperties();
+
+ if ( ! $props ) {
+ return null;
+ }
+
+ $checked = array();
+
+ foreach ( $this->value as $pattern => $value ) {
+ if ( $value === true ) {
+ iterator_to_array( $this->matchedProperties( $pattern, $props, $checked ) );
+ continue;
+ }
+
+ if ( $value === false ) {
+ $list = iterator_to_array( $this->matchedProperties( $pattern, $props, $checked ) );
+
+ if ( $list ) {
+ if ( $context->trackUnevaluated() ) {
+ $context->addEvaluatedProperties( array_diff( array_keys( $checked ), $list ) );
+ }
+ return $this->error(
+ $schema,
+ $context,
+ 'patternProperties',
+ "Object properties that match pattern '{pattern}' are not allowed",
+ array(
+ 'pattern' => $pattern,
+ 'forbidden' => $list,
+ )
+ );
+ }
+
+ unset( $list );
+ continue;
+ }
+
+ if ( is_object( $value ) && ! ( $value instanceof Schema ) ) {
+ $value = $this->value[ $pattern ] = $context->loader()->loadObjectSchema( $value );
+ }
+
+ $subErrors = $this->iterateAndValidate( $value, $context, $this->matchedProperties( $pattern, $props, $checked ) );
+
+ if ( ! $subErrors->isEmpty() ) {
+ if ( $context->trackUnevaluated() ) {
+ $context->addEvaluatedProperties( array_keys( $checked ) );
+ }
+ return $this->error(
+ $schema,
+ $context,
+ 'patternProperties',
+ "Object properties that match pattern '{pattern}' must also match pattern's schema",
+ array(
+ 'pattern' => $pattern,
+ ),
+ $subErrors
+ );
+ }
+
+ unset( $subErrors );
+ }
+
+ if ( $checked ) {
+ $checked = array_keys( $checked );
+ $context->addCheckedProperties( $checked );
+ $context->addEvaluatedProperties( $checked );
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $pattern
+ * @param array $props
+ * @param array $checked
+ * @return Traversable|string[]
+ */
+ protected function matchedProperties( $pattern, $props, &$checked ): Traversable {
+ $pattern = Helper::patternToRegex( $pattern );
+
+ foreach ( $props as $prop ) {
+ if ( preg_match( $pattern, (string) $prop ) ) {
+ $checked[ $prop ] = true;
+ yield $prop;
+ }
+ }
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/PointerRefKeyword.php b/src/opis/json-schema/src/Keywords/PointerRefKeyword.php
index c3396366..2f393548 100644
--- a/src/opis/json-schema/src/Keywords/PointerRefKeyword.php
+++ b/src/opis/json-schema/src/Keywords/PointerRefKeyword.php
@@ -1,5 +1,6 @@
pointer = $pointer;
- }
-
- /**
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- protected function doValidate($context, $schema)
- {
- if ($this->resolved === false) {
- $info = $schema->info();
- $this->resolved = $this->resolvePointer($context->loader(), $this->pointer, $info->idBaseRoot(), $info->path());
- }
-
- if ($this->resolved === null) {
- throw new UnresolvedReferenceException((string)$this->pointer, $schema, $context);
- }
-
- return $this->resolved->validate($this->createContext($context, $schema));
- }
+class PointerRefKeyword extends AbstractRefKeyword {
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $pointer;
+ /** @var bool|null|Schema */
+ protected $resolved = false;
+
+ public function __construct(
+ JsonPointer $pointer,
+ $mapper,
+ $globals,
+ $slots = null,
+ string $keyword = '$ref'
+ ) {
+ parent::__construct( $mapper, $globals, $slots, $keyword );
+ $this->pointer = $pointer;
+ }
+
+ /**
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ protected function doValidate( $context, $schema ) {
+ if ( $this->resolved === false ) {
+ $info = $schema->info();
+ $this->resolved = $this->resolvePointer( $context->loader(), $this->pointer, $info->idBaseRoot(), $info->path() );
+ }
+
+ if ( $this->resolved === null ) {
+ throw new UnresolvedReferenceException( (string) $this->pointer, $schema, $context );
+ }
+
+ return $this->resolved->validate( $this->createContext( $context, $schema ) );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/PropertiesKeyword.php b/src/opis/json-schema/src/Keywords/PropertiesKeyword.php
index 28ad31e8..a7e40c8a 100644
--- a/src/opis/json-schema/src/Keywords/PropertiesKeyword.php
+++ b/src/opis/json-schema/src/Keywords/PropertiesKeyword.php
@@ -1,5 +1,6 @@
properties = $properties;
- $this->propertyKeys = array_keys($properties);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if (!$this->properties) {
- return null;
- }
-
- $checked = [];
- $evaluated = [];
-
- $data = $context->currentData();
-
- $errors = $this->errorContainer($context->maxErrors());
-
- foreach ($this->properties as $name => $prop) {
- if (!property_exists($data, $name)) {
- continue;
- }
-
- $checked[] = $name;
-
- if ($prop === true) {
- $evaluated[] = $name;
- continue;
- }
-
- if ($prop === false) {
- $context->addEvaluatedProperties($evaluated);
- return $this->error($schema, $context, 'properties', "Property '{property}' is not allowed", [
- 'property' => $name,
- ]);
- }
-
- if (is_object($prop) && !($prop instanceof Schema)) {
- $prop = $this->properties[$name] = $context->loader()->loadObjectSchema($prop);
- }
-
- $context->pushDataPath($name);
- $error = $prop->validate($context);
- $context->popDataPath();
-
- if ($error) {
- $errors->add($error);
- if ($errors->isFull()) {
- break;
- }
- } else {
- $evaluated[] = $name;
- }
- }
-
- $context->addEvaluatedProperties($evaluated);
-
- if (!$errors->isEmpty()) {
- return $this->error($schema, $context, 'properties', "The properties must match schema: {properties}", [
- 'properties' => array_values(array_diff($checked, $evaluated))
- ], $errors);
- }
- unset($errors);
-
- $context->addCheckedProperties($checked);
-
- return null;
- }
+class PropertiesKeyword implements Keyword {
+
+ use IterableDataValidationTrait;
+
+ /**
+ * @var mixed[]
+ */
+ protected $properties;
+ /**
+ * @var mixed[]
+ */
+ protected $propertyKeys;
+
+ /**
+ * @param array $properties
+ */
+ public function __construct( array $properties ) {
+ $this->properties = $properties;
+ $this->propertyKeys = array_keys( $properties );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( ! $this->properties ) {
+ return null;
+ }
+
+ $checked = array();
+ $evaluated = array();
+
+ $data = $context->currentData();
+
+ $errors = $this->errorContainer( $context->maxErrors() );
+
+ foreach ( $this->properties as $name => $prop ) {
+ if ( ! property_exists( $data, $name ) ) {
+ continue;
+ }
+
+ $checked[] = $name;
+
+ if ( $prop === true ) {
+ $evaluated[] = $name;
+ continue;
+ }
+
+ if ( $prop === false ) {
+ $context->addEvaluatedProperties( $evaluated );
+ return $this->error(
+ $schema,
+ $context,
+ 'properties',
+ "Property '{property}' is not allowed",
+ array(
+ 'property' => $name,
+ )
+ );
+ }
+
+ if ( is_object( $prop ) && ! ( $prop instanceof Schema ) ) {
+ $prop = $this->properties[ $name ] = $context->loader()->loadObjectSchema( $prop );
+ }
+
+ $context->pushDataPath( $name );
+ $error = $prop->validate( $context );
+ $context->popDataPath();
+
+ if ( $error ) {
+ $errors->add( $error );
+ if ( $errors->isFull() ) {
+ break;
+ }
+ } else {
+ $evaluated[] = $name;
+ }
+ }
+
+ $context->addEvaluatedProperties( $evaluated );
+
+ if ( ! $errors->isEmpty() ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'properties',
+ 'The properties must match schema: {properties}',
+ array(
+ 'properties' => array_values( array_diff( $checked, $evaluated ) ),
+ ),
+ $errors
+ );
+ }
+ unset( $errors );
+
+ $context->addCheckedProperties( $checked );
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/PropertyNamesKeyword.php b/src/opis/json-schema/src/Keywords/PropertyNamesKeyword.php
index 6ba547fe..99c1d081 100644
--- a/src/opis/json-schema/src/Keywords/PropertyNamesKeyword.php
+++ b/src/opis/json-schema/src/Keywords/PropertyNamesKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
+ /** @var bool|object */
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- if ($this->value === true) {
- return null;
- }
+ /**
+ * @param bool|object $value
+ */
+ public function __construct( $value ) {
+ $this->value = $value;
+ }
- $props = $context->getObjectProperties();
- if (!$props) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ if ( $this->value === true ) {
+ return null;
+ }
- if ($this->value === false) {
- return $this->error($schema, $context, 'propertyNames', "No properties are allowed");
- }
+ $props = $context->getObjectProperties();
+ if ( ! $props ) {
+ return null;
+ }
- if (is_object($this->value) && !($this->value instanceof Schema)) {
- $this->value = $context->loader()->loadObjectSchema($this->value);
- }
+ if ( $this->value === false ) {
+ return $this->error( $schema, $context, 'propertyNames', 'No properties are allowed' );
+ }
- foreach ($props as $prop) {
- if ($error = $this->value->validate($context->newInstance($prop, $schema))) {
- return $this->error($schema, $context, 'propertyNames', "Property '{property}' must match schema", [
- 'property' => $prop,
- ], $error);
- }
- }
+ if ( is_object( $this->value ) && ! ( $this->value instanceof Schema ) ) {
+ $this->value = $context->loader()->loadObjectSchema( $this->value );
+ }
- return null;
- }
+ foreach ( $props as $prop ) {
+ if ( $error = $this->value->validate( $context->newInstance( $prop, $schema ) ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'propertyNames',
+ "Property '{property}' must match schema",
+ array(
+ 'property' => $prop,
+ ),
+ $error
+ );
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/RecursiveRefKeyword.php b/src/opis/json-schema/src/Keywords/RecursiveRefKeyword.php
index 25a6610d..a2913899 100644
--- a/src/opis/json-schema/src/Keywords/RecursiveRefKeyword.php
+++ b/src/opis/json-schema/src/Keywords/RecursiveRefKeyword.php
@@ -1,5 +1,6 @@
uri = $uri;
- $this->anchor = $anchor;
- $this->anchorValue = $anchorValue;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function doValidate($context, $schema)
- {
- if ($this->resolved === false) {
- $this->resolved = $context->loader()->loadSchemaById($this->uri);
- }
-
- if ($this->resolved === null) {
- throw new UnresolvedReferenceException((string)$this->uri, $schema, $context);
- }
-
- $new_context = $this->createContext($context, $schema);
-
- if (!$this->hasRecursiveAnchor($this->resolved)) {
- $this->setLastRefSchema($this->resolved);
- return $this->resolved->validate($new_context);
- }
-
- $ok_sender = $this->resolveSchema($context);
-
- if (!$ok_sender) {
- $this->setLastRefSchema($this->resolved);
- return $this->resolved->validate($new_context);
- }
-
- $this->setLastRefSchema($ok_sender);
-
- return $ok_sender->validate($new_context);
- }
-
- /**
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- protected function resolveSchema($context)
- {
- $ok = null;
- $loader = $context->loader();
-
- while ($context) {
- $sender = $context->sender();
-
- if (!$sender) {
- break;
- }
-
- if (!$this->hasRecursiveAnchor($sender)) {
- if ($sender->info()->id()) {
- // id without recursiveAnchor
- break;
- }
-
- $sender = $loader->loadSchemaById($sender->info()->root());
- if (!$sender || !$this->hasRecursiveAnchor($sender)) {
- // root without recursiveAnchor
- break;
- }
- }
-
- if ($sender->info()->id()) {
- // id with recursiveAnchor
- $ok = $sender;
- } else {
- // root with recursiveAnchor
- $ok = $loader->loadSchemaById($sender->info()->root());
- }
-
- $context = $context->parent();
- }
-
- return $ok;
- }
-
- /**
- * @param \Opis\JsonSchema\Schema|null $schema
- */
- protected function hasRecursiveAnchor($schema): bool
- {
- if (!$schema) {
- return false;
- }
-
- $info = $schema->info();
-
- if (!$info->isObject()) {
- return false;
- }
-
- $data = $info->data();
-
- if (!property_exists($data, $this->anchor)) {
- return false;
- }
-
- return $data->{$this->anchor} === $this->anchorValue;
- }
+class RecursiveRefKeyword extends AbstractRefKeyword {
+
+ /**
+ * @var \Opis\JsonSchema\Uri
+ */
+ protected $uri;
+ /** @var bool|null|Schema */
+ protected $resolved = false;
+ /**
+ * @var string
+ */
+ protected $anchor;
+ protected $anchorValue;
+
+ public function __construct(
+ Uri $uri,
+ $mapper,
+ $globals,
+ $slots = null,
+ string $keyword = '$recursiveRef',
+ string $anchor = '$recursiveAnchor',
+ $anchorValue = true
+ ) {
+ parent::__construct( $mapper, $globals, $slots, $keyword );
+ $this->uri = $uri;
+ $this->anchor = $anchor;
+ $this->anchorValue = $anchorValue;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function doValidate( $context, $schema ) {
+ if ( $this->resolved === false ) {
+ $this->resolved = $context->loader()->loadSchemaById( $this->uri );
+ }
+
+ if ( $this->resolved === null ) {
+ throw new UnresolvedReferenceException( (string) $this->uri, $schema, $context );
+ }
+
+ $new_context = $this->createContext( $context, $schema );
+
+ if ( ! $this->hasRecursiveAnchor( $this->resolved ) ) {
+ $this->setLastRefSchema( $this->resolved );
+ return $this->resolved->validate( $new_context );
+ }
+
+ $ok_sender = $this->resolveSchema( $context );
+
+ if ( ! $ok_sender ) {
+ $this->setLastRefSchema( $this->resolved );
+ return $this->resolved->validate( $new_context );
+ }
+
+ $this->setLastRefSchema( $ok_sender );
+
+ return $ok_sender->validate( $new_context );
+ }
+
+ /**
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ protected function resolveSchema( $context ) {
+ $ok = null;
+ $loader = $context->loader();
+
+ while ( $context ) {
+ $sender = $context->sender();
+
+ if ( ! $sender ) {
+ break;
+ }
+
+ if ( ! $this->hasRecursiveAnchor( $sender ) ) {
+ if ( $sender->info()->id() ) {
+ // id without recursiveAnchor
+ break;
+ }
+
+ $sender = $loader->loadSchemaById( $sender->info()->root() );
+ if ( ! $sender || ! $this->hasRecursiveAnchor( $sender ) ) {
+ // root without recursiveAnchor
+ break;
+ }
+ }
+
+ if ( $sender->info()->id() ) {
+ // id with recursiveAnchor
+ $ok = $sender;
+ } else {
+ // root with recursiveAnchor
+ $ok = $loader->loadSchemaById( $sender->info()->root() );
+ }
+
+ $context = $context->parent();
+ }
+
+ return $ok;
+ }
+
+ /**
+ * @param \Opis\JsonSchema\Schema|null $schema
+ */
+ protected function hasRecursiveAnchor( $schema ): bool {
+ if ( ! $schema ) {
+ return false;
+ }
+
+ $info = $schema->info();
+
+ if ( ! $info->isObject() ) {
+ return false;
+ }
+
+ $data = $info->data();
+
+ if ( ! property_exists( $data, $this->anchor ) ) {
+ return false;
+ }
+
+ return $data->{$this->anchor} === $this->anchorValue;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/RequiredDataKeyword.php b/src/opis/json-schema/src/Keywords/RequiredDataKeyword.php
index 672be71d..5606c813 100644
--- a/src/opis/json-schema/src/Keywords/RequiredDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/RequiredDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- $this->filter = $filter;
- parent::__construct([]);
- }
+ /** @var callable|null */
+ protected $filter;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $required = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
- if ($required === $this || !is_array($required) || !$this->requiredPropsAreValid($required)) {
- return $this->error($schema, $context, 'required', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
+ /**
+ * @param JsonPointer $value
+ * @param callable|null $filter
+ */
+ public function __construct( JsonPointer $value, $filter = null ) {
+ $this->value = $value;
+ $this->filter = $filter;
+ parent::__construct( array() );
+ }
- $required = array_unique($required);
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $required = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+ if ( $required === $this || ! is_array( $required ) || ! $this->requiredPropsAreValid( $required ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'required',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
- if ($this->filter) {
- $required = array_filter($required, $this->filter === null ? function ($value, $key) : bool {
- return !empty($value);
- } : $this->filter, $this->filter === null ? ARRAY_FILTER_USE_BOTH : 0);
- }
+ $required = array_unique( $required );
- if (!$required) {
- return null;
- }
+ if ( $this->filter ) {
+ $required = array_filter(
+ $required,
+ $this->filter === null ? function ( $value, $key ): bool {
+ return ! empty( $value );
+ } : $this->filter,
+ $this->filter === null ? ARRAY_FILTER_USE_BOTH : 0
+ );
+ }
- $this->required = $required;
- $ret = parent::validate($context, $schema);
- $this->required = null;
+ if ( ! $required ) {
+ return null;
+ }
- return $ret;
- }
+ $this->required = $required;
+ $ret = parent::validate( $context, $schema );
+ $this->required = null;
- /**
- * @param array $props
- * @return bool
- */
- protected function requiredPropsAreValid($props): bool
- {
- foreach ($props as $prop) {
- if (!is_string($prop)) {
- return false;
- }
- }
+ return $ret;
+ }
- return true;
- }
+ /**
+ * @param array $props
+ * @return bool
+ */
+ protected function requiredPropsAreValid( $props ): bool {
+ foreach ( $props as $prop ) {
+ if ( ! is_string( $prop ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/RequiredKeyword.php b/src/opis/json-schema/src/Keywords/RequiredKeyword.php
index ed10c5a7..6d0c7ce2 100644
--- a/src/opis/json-schema/src/Keywords/RequiredKeyword.php
+++ b/src/opis/json-schema/src/Keywords/RequiredKeyword.php
@@ -1,5 +1,6 @@
required = $required;
- }
+ /** @var string[] */
+ protected $required;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $data = $context->currentData();
- $max = $context->maxErrors();
- $list = [];
+ /**
+ * @param string[] $required
+ */
+ public function __construct( array $required ) {
+ $this->required = $required;
+ }
- foreach ($this->required as $name) {
- if (!property_exists($data, $name)) {
- $list[] = $name;
- if (--$max <= 0) {
- break;
- }
- }
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $data = $context->currentData();
+ $max = $context->maxErrors();
+ $list = array();
- if (!$list) {
- return null;
- }
+ foreach ( $this->required as $name ) {
+ if ( ! property_exists( $data, $name ) ) {
+ $list[] = $name;
+ if ( --$max <= 0 ) {
+ break;
+ }
+ }
+ }
- return $this->error($schema, $context, 'required', 'The required properties ({missing}) are missing', [
- 'missing' => $list,
- ]);
- }
+ if ( ! $list ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'required',
+ 'The required properties ({missing}) are missing',
+ array(
+ 'missing' => $list,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/SlotsKeyword.php b/src/opis/json-schema/src/Keywords/SlotsKeyword.php
index 2b27fef8..ed0f208c 100644
--- a/src/opis/json-schema/src/Keywords/SlotsKeyword.php
+++ b/src/opis/json-schema/src/Keywords/SlotsKeyword.php
@@ -1,5 +1,6 @@
slots = $slots;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $newContext = $context->newInstance($context->currentData(), $schema);
-
- foreach ($this->slots as $name => $fallback) {
- $slot = $this->resolveSlotSchema($name, $context);
-
- if ($slot === null) {
- $save = true;
- if (is_string($fallback)) {
- $save = false;
- $fallback = $this->resolveSlot($fallback, $context);
- }
-
- if ($fallback === true) {
- continue;
- }
-
- if ($fallback === false) {
- return $this->error($schema, $context, '$slots', "Required slot '{slot}' is missing", [
- 'slot' => $name,
- ]);
- }
-
- if (is_object($fallback) && !($fallback instanceof Schema)) {
- $fallback = $context->loader()->loadObjectSchema($fallback);
- if ($save) {
- $this->slots[$name] = $fallback;
- }
- }
-
- $slot = $fallback;
- }
-
- if ($error = $slot->validate($newContext)) {
- return $this->error($schema, $context,'$slots', "Schema for slot '{slot}' was not matched", [
- 'slot' => $name,
- ], $error);
- }
- }
-
- return null;
- }
-
- /**
- * @param string $name
- * @param ValidationContext $context
- * @return Schema|null
- */
- protected function resolveSlotSchema($name, $context)
- {
- do {
- $slot = $context->slot($name);
- } while ($slot === null && $context = $context->parent());
-
- return $slot;
- }
-
- /**
- * @param string $name
- * @param ValidationContext $context
- * @return bool|Schema
- */
- protected function resolveSlot($name, $context)
- {
- $slot = $this->resolveSlotSchema($name, $context);
-
- if ($slot !== null) {
- return $slot;
- }
-
- if (!isset($this->slots[$name])) {
- return false;
- }
-
- $slot = $this->slots[$name];
-
- if (is_bool($slot)) {
- return $slot;
- }
-
- if (is_object($slot)) {
- if ($slot instanceof Schema) {
- return $slot;
- }
-
- $slot = $context->loader()->loadObjectSchema($slot);
- $this->slots[$name] = $slot;
- return $slot;
- }
-
- if (!is_string($slot)) {
- // Looks like the slot is missing
- return false;
- }
-
- if (in_array($slot, $this->stack)) {
- // Recursive
- return false;
- }
-
- $this->stack[] = $slot;
- $slot = $this->resolveSlot($slot, $context);
- array_pop($this->stack);
-
- return $slot;
- }
+class SlotsKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /** @var bool[]|Schema[]|object[]|string[] */
+ protected $slots;
+
+ /** @var string[] */
+ protected $stack = array();
+
+ /**
+ * @param string[]|bool[]|object[]|Schema[] $slots
+ */
+ public function __construct( array $slots ) {
+ $this->slots = $slots;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $newContext = $context->newInstance( $context->currentData(), $schema );
+
+ foreach ( $this->slots as $name => $fallback ) {
+ $slot = $this->resolveSlotSchema( $name, $context );
+
+ if ( $slot === null ) {
+ $save = true;
+ if ( is_string( $fallback ) ) {
+ $save = false;
+ $fallback = $this->resolveSlot( $fallback, $context );
+ }
+
+ if ( $fallback === true ) {
+ continue;
+ }
+
+ if ( $fallback === false ) {
+ return $this->error(
+ $schema,
+ $context,
+ '$slots',
+ "Required slot '{slot}' is missing",
+ array(
+ 'slot' => $name,
+ )
+ );
+ }
+
+ if ( is_object( $fallback ) && ! ( $fallback instanceof Schema ) ) {
+ $fallback = $context->loader()->loadObjectSchema( $fallback );
+ if ( $save ) {
+ $this->slots[ $name ] = $fallback;
+ }
+ }
+
+ $slot = $fallback;
+ }
+
+ if ( $error = $slot->validate( $newContext ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ '$slots',
+ "Schema for slot '{slot}' was not matched",
+ array(
+ 'slot' => $name,
+ ),
+ $error
+ );
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $name
+ * @param ValidationContext $context
+ * @return Schema|null
+ */
+ protected function resolveSlotSchema( $name, $context ) {
+ do {
+ $slot = $context->slot( $name );
+ } while ( $slot === null && $context = $context->parent() );
+
+ return $slot;
+ }
+
+ /**
+ * @param string $name
+ * @param ValidationContext $context
+ * @return bool|Schema
+ */
+ protected function resolveSlot( $name, $context ) {
+ $slot = $this->resolveSlotSchema( $name, $context );
+
+ if ( $slot !== null ) {
+ return $slot;
+ }
+
+ if ( ! isset( $this->slots[ $name ] ) ) {
+ return false;
+ }
+
+ $slot = $this->slots[ $name ];
+
+ if ( is_bool( $slot ) ) {
+ return $slot;
+ }
+
+ if ( is_object( $slot ) ) {
+ if ( $slot instanceof Schema ) {
+ return $slot;
+ }
+
+ $slot = $context->loader()->loadObjectSchema( $slot );
+ $this->slots[ $name ] = $slot;
+ return $slot;
+ }
+
+ if ( ! is_string( $slot ) ) {
+ // Looks like the slot is missing
+ return false;
+ }
+
+ if ( in_array( $slot, $this->stack ) ) {
+ // Recursive
+ return false;
+ }
+
+ $this->stack[] = $slot;
+ $slot = $this->resolveSlot( $slot, $context );
+ array_pop( $this->stack );
+
+ return $slot;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/TemplateRefKeyword.php b/src/opis/json-schema/src/Keywords/TemplateRefKeyword.php
index 3ba07048..5414da10 100644
--- a/src/opis/json-schema/src/Keywords/TemplateRefKeyword.php
+++ b/src/opis/json-schema/src/Keywords/TemplateRefKeyword.php
@@ -1,5 +1,6 @@
template = $template;
- $this->vars = $vars;
- $this->allowRelativeJsonPointerInRef = $allowRelativeJsonPointerInRef;
- }
-
- /**
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- protected function doValidate($context, $schema)
- {
- if ($this->vars) {
- $vars = $this->vars->resolve($context->rootData(), $context->currentDataPath());
- if (!is_array($vars)) {
- $vars = (array)$vars;
- }
- $vars += $context->globals();
- } else {
- $vars = $context->globals();
- }
-
- $ref = $this->template->resolve($vars);
-
- $key = isset($ref[32]) ? md5($ref) : $ref;
-
- if (!array_key_exists($key, $this->cached)) {
- $this->cached[$key] = $this->resolveRef($ref, $context->loader(), $schema);
- }
-
- $resolved = $this->cached[$key];
- unset($key);
-
- if (!$resolved) {
- throw new UnresolvedReferenceException($ref, $schema, $context);
- }
-
- return $resolved->validate($this->createContext($context, $schema));
- }
-
- /**
- * @param string $ref
- * @param SchemaLoader $repo
- * @param Schema $schema
- * @return null|Schema
- */
- protected function resolveRef($ref, $repo, $schema)
- {
- if ($ref === '') {
- return null;
- }
-
- $baseUri = $schema->info()->idBaseRoot();
-
- if ($ref === '#') {
- return $repo->loadSchemaById($baseUri);
- }
-
- // Check if is pointer
- if ($ref[0] === '#') {
- if ($pointer = JsonPointer::parse(substr($ref, 1))) {
- if ($pointer->isAbsolute()) {
- return $this->resolvePointer($repo, $pointer, $baseUri);
- }
- unset($pointer);
- }
- } elseif ($this->allowRelativeJsonPointerInRef && ($pointer = JsonPointer::parse($ref))) {
- if ($pointer->isRelative()) {
- return $this->resolvePointer($repo, $pointer, $baseUri, $schema->info()->path());
- }
- unset($pointer);
- }
-
- $ref = Uri::merge($ref, $baseUri, true);
-
- if ($ref === null || !$ref->isAbsolute()) {
- return null;
- }
-
- return $repo->loadSchemaById($ref);
- }
+class TemplateRefKeyword extends AbstractRefKeyword {
+
+ /**
+ * @var \Opis\Uri\UriTemplate
+ */
+ protected $template;
+ /**
+ * @var \Opis\JsonSchema\Variables|null
+ */
+ protected $vars;
+ /** @var Schema[]|null[] */
+ protected $cached = array();
+ /**
+ * @var bool
+ */
+ protected $allowRelativeJsonPointerInRef;
+
+ public function __construct(
+ UriTemplate $template,
+ $vars,
+ $mapper = null,
+ $globals = null,
+ $slots = null,
+ string $keyword = '$ref',
+ bool $allowRelativeJsonPointerInRef = true
+ ) {
+ parent::__construct( $mapper, $globals, $slots, $keyword );
+ $this->template = $template;
+ $this->vars = $vars;
+ $this->allowRelativeJsonPointerInRef = $allowRelativeJsonPointerInRef;
+ }
+
+ /**
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ protected function doValidate( $context, $schema ) {
+ if ( $this->vars ) {
+ $vars = $this->vars->resolve( $context->rootData(), $context->currentDataPath() );
+ if ( ! is_array( $vars ) ) {
+ $vars = (array) $vars;
+ }
+ $vars += $context->globals();
+ } else {
+ $vars = $context->globals();
+ }
+
+ $ref = $this->template->resolve( $vars );
+
+ $key = isset( $ref[32] ) ? md5( $ref ) : $ref;
+
+ if ( ! array_key_exists( $key, $this->cached ) ) {
+ $this->cached[ $key ] = $this->resolveRef( $ref, $context->loader(), $schema );
+ }
+
+ $resolved = $this->cached[ $key ];
+ unset( $key );
+
+ if ( ! $resolved ) {
+ throw new UnresolvedReferenceException( $ref, $schema, $context );
+ }
+
+ return $resolved->validate( $this->createContext( $context, $schema ) );
+ }
+
+ /**
+ * @param string $ref
+ * @param SchemaLoader $repo
+ * @param Schema $schema
+ * @return null|Schema
+ */
+ protected function resolveRef( $ref, $repo, $schema ) {
+ if ( $ref === '' ) {
+ return null;
+ }
+
+ $baseUri = $schema->info()->idBaseRoot();
+
+ if ( $ref === '#' ) {
+ return $repo->loadSchemaById( $baseUri );
+ }
+
+ // Check if is pointer
+ if ( $ref[0] === '#' ) {
+ if ( $pointer = JsonPointer::parse( substr( $ref, 1 ) ) ) {
+ if ( $pointer->isAbsolute() ) {
+ return $this->resolvePointer( $repo, $pointer, $baseUri );
+ }
+ unset( $pointer );
+ }
+ } elseif ( $this->allowRelativeJsonPointerInRef && ( $pointer = JsonPointer::parse( $ref ) ) ) {
+ if ( $pointer->isRelative() ) {
+ return $this->resolvePointer( $repo, $pointer, $baseUri, $schema->info()->path() );
+ }
+ unset( $pointer );
+ }
+
+ $ref = Uri::merge( $ref, $baseUri, true );
+
+ if ( $ref === null || ! $ref->isAbsolute() ) {
+ return null;
+ }
+
+ return $repo->loadSchemaById( $ref );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/TypeKeyword.php b/src/opis/json-schema/src/Keywords/TypeKeyword.php
index 999f5bd8..58f8b5ac 100644
--- a/src/opis/json-schema/src/Keywords/TypeKeyword.php
+++ b/src/opis/json-schema/src/Keywords/TypeKeyword.php
@@ -1,5 +1,6 @@
type = $type;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $type = $context->currentDataType();
- if ($type && Helper::jsonTypeMatches($type, $this->type)) {
- return null;
- }
-
- return $this->error($schema, $context, 'type', 'The data ({type}) must match the type: {expected}', [
- 'expected' => $this->type,
- 'type' => $type,
- ]);
- }
+class TypeKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /** @var string|string[] */
+ protected $type;
+
+ /**
+ * @param string|string[] $type
+ */
+ public function __construct( $type ) {
+ $this->type = $type;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $type = $context->currentDataType();
+ if ( $type && Helper::jsonTypeMatches( $type, $this->type ) ) {
+ return null;
+ }
+
+ return $this->error(
+ $schema,
+ $context,
+ 'type',
+ 'The data ({type}) must match the type: {expected}',
+ array(
+ 'expected' => $this->type,
+ 'type' => $type,
+ )
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/URIRefKeyword.php b/src/opis/json-schema/src/Keywords/URIRefKeyword.php
index 32126f5e..6ff41364 100644
--- a/src/opis/json-schema/src/Keywords/URIRefKeyword.php
+++ b/src/opis/json-schema/src/Keywords/URIRefKeyword.php
@@ -1,5 +1,6 @@
uri = $uri;
- }
-
- /**
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- protected function doValidate($context, $schema)
- {
- if ($this->resolved === false) {
- $this->resolved = $context->loader()->loadSchemaById($this->uri);
- }
-
- if ($this->resolved === null) {
- throw new UnresolvedReferenceException((string)$this->uri, $schema, $context);
- }
-
- $this->setLastRefSchema($this->resolved);
-
- return $this->resolved->validate($this->createContext($context, $schema));
- }
+class URIRefKeyword extends AbstractRefKeyword {
+
+ /**
+ * @var \Opis\JsonSchema\Uri
+ */
+ protected $uri;
+ /** @var bool|null|Schema */
+ protected $resolved = false;
+
+ public function __construct(
+ Uri $uri,
+ $mapper,
+ $globals,
+ $slots = null,
+ string $keyword = '$ref'
+ ) {
+ parent::__construct( $mapper, $globals, $slots, $keyword );
+ $this->uri = $uri;
+ }
+
+ /**
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ protected function doValidate( $context, $schema ) {
+ if ( $this->resolved === false ) {
+ $this->resolved = $context->loader()->loadSchemaById( $this->uri );
+ }
+
+ if ( $this->resolved === null ) {
+ throw new UnresolvedReferenceException( (string) $this->uri, $schema, $context );
+ }
+
+ $this->setLastRefSchema( $this->resolved );
+
+ return $this->resolved->validate( $this->createContext( $context, $schema ) );
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/UnevaluatedItemsKeyword.php b/src/opis/json-schema/src/Keywords/UnevaluatedItemsKeyword.php
index c5db7abd..c238e688 100644
--- a/src/opis/json-schema/src/Keywords/UnevaluatedItemsKeyword.php
+++ b/src/opis/json-schema/src/Keywords/UnevaluatedItemsKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $unevaluated = $context->getUnevaluatedItems();
+ public function __construct( $value ) {
+ $this->value = $value;
+ }
- if (!$unevaluated) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $unevaluated = $context->getUnevaluatedItems();
- if ($this->value === true) {
- $context->addEvaluatedItems($unevaluated);
- return null;
- }
+ if ( ! $unevaluated ) {
+ return null;
+ }
- if ($this->value === false) {
- return $this->error($schema, $context, 'unevaluatedItems',
- 'Unevaluated array items are not allowed: {indexes}', [
- 'indexes' => $unevaluated,
- ]);
- }
+ if ( $this->value === true ) {
+ $context->addEvaluatedItems( $unevaluated );
+ return null;
+ }
- if (is_object($this->value) && !($this->value instanceof Schema)) {
- $this->value = $context->loader()->loadObjectSchema($this->value);
- }
+ if ( $this->value === false ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'unevaluatedItems',
+ 'Unevaluated array items are not allowed: {indexes}',
+ array(
+ 'indexes' => $unevaluated,
+ )
+ );
+ }
- $object = $this->createArrayObject($context);
+ if ( is_object( $this->value ) && ! ( $this->value instanceof Schema ) ) {
+ $this->value = $context->loader()->loadObjectSchema( $this->value );
+ }
- $error = $this->validateIterableData($schema, $this->value, $context, $unevaluated,
- 'unevaluatedItems', 'All unevaluated array items must match schema: {indexes}', [
- 'indexes' => $unevaluated,
- ], $object);
+ $object = $this->createArrayObject( $context );
- if ($object && $object->count()) {
- $context->addEvaluatedItems($object->getArrayCopy());
- }
+ $error = $this->validateIterableData(
+ $schema,
+ $this->value,
+ $context,
+ $unevaluated,
+ 'unevaluatedItems',
+ 'All unevaluated array items must match schema: {indexes}',
+ array(
+ 'indexes' => $unevaluated,
+ ),
+ $object
+ );
- return $error;
- }
+ if ( $object && $object->count() ) {
+ $context->addEvaluatedItems( $object->getArrayCopy() );
+ }
+
+ return $error;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/UnevaluatedPropertiesKeyword.php b/src/opis/json-schema/src/Keywords/UnevaluatedPropertiesKeyword.php
index 2cc192c0..9f2f148b 100644
--- a/src/opis/json-schema/src/Keywords/UnevaluatedPropertiesKeyword.php
+++ b/src/opis/json-schema/src/Keywords/UnevaluatedPropertiesKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
+ /** @var bool|object|Schema */
+ protected $value;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $unevaluated = $context->getUnevaluatedProperties();
+ public function __construct( $value ) {
+ $this->value = $value;
+ }
- if (!$unevaluated) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $unevaluated = $context->getUnevaluatedProperties();
- if ($this->value === true) {
- $context->addEvaluatedProperties($unevaluated);
- return null;
- }
+ if ( ! $unevaluated ) {
+ return null;
+ }
- if ($this->value === false) {
- return $this->error($schema, $context, 'unevaluatedProperties',
- 'Unevaluated object properties not allowed: {properties}', [
- 'properties' => $unevaluated,
- ]);
- }
+ if ( $this->value === true ) {
+ $context->addEvaluatedProperties( $unevaluated );
+ return null;
+ }
- if (is_object($this->value) && !($this->value instanceof Schema)) {
- $this->value = $context->loader()->loadObjectSchema($this->value);
- }
+ if ( $this->value === false ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'unevaluatedProperties',
+ 'Unevaluated object properties not allowed: {properties}',
+ array(
+ 'properties' => $unevaluated,
+ )
+ );
+ }
- $object = $this->createArrayObject($context);
+ if ( is_object( $this->value ) && ! ( $this->value instanceof Schema ) ) {
+ $this->value = $context->loader()->loadObjectSchema( $this->value );
+ }
- $error = $this->validateIterableData($schema, $this->value, $context, $unevaluated,
- 'unevaluatedProperties', 'All unevaluated object properties must match schema: {properties}', [
- 'properties' => $unevaluated,
- ], $object);
+ $object = $this->createArrayObject( $context );
+ $error = $this->validateIterableData(
+ $schema,
+ $this->value,
+ $context,
+ $unevaluated,
+ 'unevaluatedProperties',
+ 'All unevaluated object properties must match schema: {properties}',
+ array(
+ 'properties' => $unevaluated,
+ ),
+ $object
+ );
- if ($object && $object->count()) {
- $context->addEvaluatedProperties($object->getArrayCopy());
- }
+ if ( $object && $object->count() ) {
+ $context->addEvaluatedProperties( $object->getArrayCopy() );
+ }
- return $error;
- }
+ return $error;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/UniqueItemsDataKeyword.php b/src/opis/json-schema/src/Keywords/UniqueItemsDataKeyword.php
index 79cb925f..c08214bb 100644
--- a/src/opis/json-schema/src/Keywords/UniqueItemsDataKeyword.php
+++ b/src/opis/json-schema/src/Keywords/UniqueItemsDataKeyword.php
@@ -1,5 +1,6 @@
value = $value;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- * @param \Opis\JsonSchema\Schema $schema
- */
- public function validate($context, $schema)
- {
- $value = $this->value->data($context->rootData(), $context->currentDataPath(), $this);
-
- if ($value === $this || !is_bool($value)) {
- return $this->error($schema, $context, 'uniqueItems', 'Invalid $data', [
- 'pointer' => (string)$this->value,
- ]);
- }
-
- return $value ? parent::validate($context, $schema) : null;
- }
+class UniqueItemsDataKeyword extends UniqueItemsKeyword {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ protected $value;
+
+ /**
+ * @param JsonPointer $value
+ */
+ public function __construct( JsonPointer $value ) {
+ $this->value = $value;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $value = $this->value->data( $context->rootData(), $context->currentDataPath(), $this );
+
+ if ( $value === $this || ! is_bool( $value ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'uniqueItems',
+ 'Invalid $data',
+ array(
+ 'pointer' => (string) $this->value,
+ )
+ );
+ }
+
+ return $value ? parent::validate( $context, $schema ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Keywords/UniqueItemsKeyword.php b/src/opis/json-schema/src/Keywords/UniqueItemsKeyword.php
index 8582eddb..b787645c 100644
--- a/src/opis/json-schema/src/Keywords/UniqueItemsKeyword.php
+++ b/src/opis/json-schema/src/Keywords/UniqueItemsKeyword.php
@@ -1,5 +1,6 @@
currentData();
- if (!$data) {
- return null;
- }
-
- $count = count($data);
-
- for ($i = 0; $i < $count - 1; $i++) {
- for ($j = $i + 1; $j < $count; $j++) {
- if (Helper::equals($data[$i], $data[$j])) {
- return $this->error($schema, $context, 'uniqueItems', 'Array must have unique items', [
- 'duplicate' => $data[$i],
- 'indexes' => [$i, $j],
- ]);
- }
- }
- }
-
- return null;
- }
+class UniqueItemsKeyword implements Keyword {
+
+ use ErrorTrait;
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ * @param \Opis\JsonSchema\Schema $schema
+ */
+ public function validate( $context, $schema ) {
+ $data = $context->currentData();
+ if ( ! $data ) {
+ return null;
+ }
+
+ $count = count( $data );
+
+ for ( $i = 0; $i < $count - 1; $i++ ) {
+ for ( $j = $i + 1; $j < $count; $j++ ) {
+ if ( Helper::equals( $data[ $i ], $data[ $j ] ) ) {
+ return $this->error(
+ $schema,
+ $context,
+ 'uniqueItems',
+ 'Array must have unique items',
+ array(
+ 'duplicate' => $data[ $i ],
+ 'indexes' => array( $i, $j ),
+ )
+ );
+ }
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/DataKeywordTrait.php b/src/opis/json-schema/src/Parsers/DataKeywordTrait.php
index 5e43ae1d..8f6ab4eb 100644
--- a/src/opis/json-schema/src/Parsers/DataKeywordTrait.php
+++ b/src/opis/json-schema/src/Parsers/DataKeywordTrait.php
@@ -1,5 +1,6 @@
{'$data'}) || count(get_object_vars($value)) !== 1) {
- return null;
- }
-
- return JsonPointer::parse($value->{'$data'});
- }
-
- /**
- * @param SchemaParser $parser
- * @param string|null $keyword
- * @return bool
- */
- protected function isDataKeywordAllowed($parser, $keyword = null): bool
- {
- if (!($enabled = $parser->option('allowDataKeyword'))) {
- return false;
- }
-
- if ($enabled === true) {
- return true;
- }
-
- if ($keyword === null) {
- return false;
- }
-
- return is_array($enabled) && in_array($keyword, $enabled);
- }
+trait DataKeywordTrait {
+
+ /**
+ * @param $value
+ * @return JsonPointer|null
+ */
+ protected function getDataKeywordPointer( $value ) {
+ if ( ! is_object( $value ) || ! property_exists( $value, '$data' ) ||
+ ! is_string( $value->{'$data'} ) || count( get_object_vars( $value ) ) !== 1 ) {
+ return null;
+ }
+
+ return JsonPointer::parse( $value->{'$data'} );
+ }
+
+ /**
+ * @param SchemaParser $parser
+ * @param string|null $keyword
+ * @return bool
+ */
+ protected function isDataKeywordAllowed( $parser, $keyword = null ): bool {
+ if ( ! ( $enabled = $parser->option( 'allowDataKeyword' ) ) ) {
+ return false;
+ }
+
+ if ( $enabled === true ) {
+ return true;
+ }
+
+ if ( $keyword === null ) {
+ return false;
+ }
+
+ return is_array( $enabled ) && in_array( $keyword, $enabled );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/DefaultVocabulary.php b/src/opis/json-schema/src/Parsers/DefaultVocabulary.php
index d05d4280..8349fe21 100644
--- a/src/opis/json-schema/src/Parsers/DefaultVocabulary.php
+++ b/src/opis/json-schema/src/Parsers/DefaultVocabulary.php
@@ -1,5 +1,6 @@
getKeywordParsers();
- $keywordValidators = $this->getKeywordValidatorParsers();
- $pragmas = $this->getPragmaParsers();
+abstract class Draft extends Vocabulary {
- if ($extraVocabulary) {
- $keywords = array_merge($keywords, $extraVocabulary->keywords());
- $keywordValidators = array_merge($keywordValidators, $extraVocabulary->keywordValidators());
- $pragmas = array_merge($pragmas, $extraVocabulary->pragmas());
- }
+ /**
+ * @param Vocabulary|null $extraVocabulary
+ */
+ public function __construct( $extraVocabulary = null ) {
+ $keywords = $this->getKeywordParsers();
+ $keywordValidators = $this->getKeywordValidatorParsers();
+ $pragmas = $this->getPragmaParsers();
- array_unshift($keywords, $this->getRefKeywordParser());
+ if ( $extraVocabulary ) {
+ $keywords = array_merge( $keywords, $extraVocabulary->keywords() );
+ $keywordValidators = array_merge( $keywordValidators, $extraVocabulary->keywordValidators() );
+ $pragmas = array_merge( $pragmas, $extraVocabulary->pragmas() );
+ }
- parent::__construct($keywords, $keywordValidators, $pragmas);
- }
+ array_unshift( $keywords, $this->getRefKeywordParser() );
- /**
- * @return string
- */
- abstract public function version(): string;
+ parent::__construct( $keywords, $keywordValidators, $pragmas );
+ }
- /**
- * @return bool
- */
- abstract public function allowKeywordsAlongsideRef(): bool;
+ /**
+ * @return string
+ */
+ abstract public function version(): string;
- /**
- * @return bool
- */
- abstract public function supportsAnchorId(): bool;
+ /**
+ * @return bool
+ */
+ abstract public function allowKeywordsAlongsideRef(): bool;
- /**
- * @return KeywordParser
- */
- abstract protected function getRefKeywordParser(): KeywordParser;
+ /**
+ * @return bool
+ */
+ abstract public function supportsAnchorId(): bool;
- /**
- * @return KeywordParser[]
- */
- abstract protected function getKeywordParsers(): array;
+ /**
+ * @return KeywordParser
+ */
+ abstract protected function getRefKeywordParser(): KeywordParser;
- /**
- * @return KeywordValidatorParser[]
- */
- protected function getKeywordValidatorParsers(): array
- {
- return [];
- }
+ /**
+ * @return KeywordParser[]
+ */
+ abstract protected function getKeywordParsers(): array;
- /**
- * @return PragmaParser[]
- */
- protected function getPragmaParsers(): array
- {
- return [];
- }
+ /**
+ * @return KeywordValidatorParser[]
+ */
+ protected function getKeywordValidatorParsers(): array {
+ return array();
+ }
+
+ /**
+ * @return PragmaParser[]
+ */
+ protected function getPragmaParsers(): array {
+ return array();
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/DraftOptionTrait.php b/src/opis/json-schema/src/Parsers/DraftOptionTrait.php
index 22e28153..6511fa1b 100644
--- a/src/opis/json-schema/src/Parsers/DraftOptionTrait.php
+++ b/src/opis/json-schema/src/Parsers/DraftOptionTrait.php
@@ -1,5 +1,6 @@
option($option);
-
- if (!$value) {
- return false;
- }
-
- if ($value === true) {
- return true;
- }
-
- if (is_array($value)) {
- return in_array($info->draft(), $value);
- }
-
- return $value === $info->draft();
- }
-}
\ No newline at end of file
+trait DraftOptionTrait {
+
+ /**
+ * @param string $option
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ */
+ protected function optionAllowedForDraft( $option, $info, $parser ): bool {
+ $value = $parser->option( $option );
+
+ if ( ! $value ) {
+ return false;
+ }
+
+ if ( $value === true ) {
+ return true;
+ }
+
+ if ( is_array( $value ) ) {
+ return in_array( $info->draft(), $value );
+ }
+
+ return $value === $info->draft();
+ }
+}
diff --git a/src/opis/json-schema/src/Parsers/Drafts/Draft06.php b/src/opis/json-schema/src/Parsers/Drafts/Draft06.php
index f8a48343..4ee16951 100644
--- a/src/opis/json-schema/src/Parsers/Drafts/Draft06.php
+++ b/src/opis/json-schema/src/Parsers/Drafts/Draft06.php
@@ -1,5 +1,6 @@
'$recursiveRef', 'anchor' => '$recursiveAnchor', 'fragment' => false],
- ]);
- }
+ /**
+ * @inheritDoc
+ */
+ public function supportsAnchorId(): bool {
+ return true;
+ }
- /**
- * @inheritDoc
- */
- protected function getKeywordParsers(): array
- {
- return [
- // Generic
- new TypeKeywordParser('type'),
- new ConstKeywordParser('const'),
- new EnumKeywordParser('enum'),
- new FormatKeywordParser('format'),
+ /**
+ * @inheritDoc
+ */
+ protected function getRefKeywordParser(): KeywordParser {
+ return new RefKeywordParser(
+ '$ref',
+ array(
+ array(
+ 'ref' => '$recursiveRef',
+ 'anchor' => '$recursiveAnchor',
+ 'fragment' => false,
+ ),
+ )
+ );
+ }
- // String
- new MinLengthKeywordParser('minLength'),
- new MaxLengthKeywordParser('maxLength'),
- new PatternKeywordParser("pattern"),
- new ContentEncodingKeywordParser('contentEncoding'),
- new ContentMediaTypeKeywordParser('contentMediaType'),
- new ContentSchemaKeywordParser('contentSchema'),
+ /**
+ * @inheritDoc
+ */
+ protected function getKeywordParsers(): array {
+ return array(
+ // Generic
+ new TypeKeywordParser( 'type' ),
+ new ConstKeywordParser( 'const' ),
+ new EnumKeywordParser( 'enum' ),
+ new FormatKeywordParser( 'format' ),
- // Number
- new MinimumKeywordParser('minimum', 'exclusiveMinimum'),
- new MaximumKeywordParser('maximum', 'exclusiveMaximum'),
- new ExclusiveMinimumKeywordParser('exclusiveMinimum'),
- new ExclusiveMaximumKeywordParser('exclusiveMaximum'),
- new MultipleOfKeywordParser('multipleOf'),
+ // String
+ new MinLengthKeywordParser( 'minLength' ),
+ new MaxLengthKeywordParser( 'maxLength' ),
+ new PatternKeywordParser( 'pattern' ),
+ new ContentEncodingKeywordParser( 'contentEncoding' ),
+ new ContentMediaTypeKeywordParser( 'contentMediaType' ),
+ new ContentSchemaKeywordParser( 'contentSchema' ),
- // Array
- new MinItemsKeywordParser('minItems'),
- new MaxItemsKeywordParser('maxItems'),
- new UniqueItemsKeywordParser('uniqueItems'),
- new ContainsKeywordParser('contains', 'minContains', 'maxContains'),
- new ItemsKeywordParser('items'),
- new AdditionalItemsKeywordParser('additionalItems'),
+ // Number
+ new MinimumKeywordParser( 'minimum', 'exclusiveMinimum' ),
+ new MaximumKeywordParser( 'maximum', 'exclusiveMaximum' ),
+ new ExclusiveMinimumKeywordParser( 'exclusiveMinimum' ),
+ new ExclusiveMaximumKeywordParser( 'exclusiveMaximum' ),
+ new MultipleOfKeywordParser( 'multipleOf' ),
- // Object
- new MinPropertiesKeywordParser('minProperties'),
- new MaxPropertiesKeywordParser('maxProperties'),
- new RequiredKeywordParser('required'),
- new DependenciesKeywordParser('dependencies'), // keep for draft-07 compatibility
- new DependentRequiredKeywordParser('dependentRequired'),
- new DependentSchemasKeywordParser('dependentSchemas'),
- new PropertyNamesKeywordParser('propertyNames'),
- new PropertiesKeywordParser('properties'),
- new PatternPropertiesKeywordParser('patternProperties'),
- new AdditionalPropertiesKeywordParser('additionalProperties'),
+ // Array
+ new MinItemsKeywordParser( 'minItems' ),
+ new MaxItemsKeywordParser( 'maxItems' ),
+ new UniqueItemsKeywordParser( 'uniqueItems' ),
+ new ContainsKeywordParser( 'contains', 'minContains', 'maxContains' ),
+ new ItemsKeywordParser( 'items' ),
+ new AdditionalItemsKeywordParser( 'additionalItems' ),
- // Conditionals
- new IfThenElseKeywordParser('if', 'then', 'else'),
- new AnyOfKeywordParser('anyOf'),
- new AllOfKeywordParser('allOf'),
- new OneOfKeywordParser('oneOf'),
- new NotKeywordParser('not'),
+ // Object
+ new MinPropertiesKeywordParser( 'minProperties' ),
+ new MaxPropertiesKeywordParser( 'maxProperties' ),
+ new RequiredKeywordParser( 'required' ),
+ new DependenciesKeywordParser( 'dependencies' ), // keep for draft-07 compatibility
+ new DependentRequiredKeywordParser( 'dependentRequired' ),
+ new DependentSchemasKeywordParser( 'dependentSchemas' ),
+ new PropertyNamesKeywordParser( 'propertyNames' ),
+ new PropertiesKeywordParser( 'properties' ),
+ new PatternPropertiesKeywordParser( 'patternProperties' ),
+ new AdditionalPropertiesKeywordParser( 'additionalProperties' ),
- // Unevaluated
- new UnevaluatedPropertiesKeywordParser('unevaluatedProperties'),
- new UnevaluatedItemsKeywordParser('unevaluatedItems'),
+ // Conditionals
+ new IfThenElseKeywordParser( 'if', 'then', 'else' ),
+ new AnyOfKeywordParser( 'anyOf' ),
+ new AllOfKeywordParser( 'allOf' ),
+ new OneOfKeywordParser( 'oneOf' ),
+ new NotKeywordParser( 'not' ),
- // Optional
- new DefaultKeywordParser('default'),
- ];
- }
+ // Unevaluated
+ new UnevaluatedPropertiesKeywordParser( 'unevaluatedProperties' ),
+ new UnevaluatedItemsKeywordParser( 'unevaluatedItems' ),
-}
\ No newline at end of file
+ // Optional
+ new DefaultKeywordParser( 'default' ),
+ );
+ }
+}
diff --git a/src/opis/json-schema/src/Parsers/Drafts/Draft202012.php b/src/opis/json-schema/src/Parsers/Drafts/Draft202012.php
index b4e960ff..d6fa72f0 100644
--- a/src/opis/json-schema/src/Parsers/Drafts/Draft202012.php
+++ b/src/opis/json-schema/src/Parsers/Drafts/Draft202012.php
@@ -1,5 +1,6 @@
'$dynamicRef', 'anchor' => '$dynamicAnchor', 'fragment' => true],
- ['ref' => '$recursiveRef', 'anchor' => '$recursiveAnchor', 'fragment' => false],
- ]);
- }
+ /**
+ * @inheritDoc
+ */
+ public function supportsAnchorId(): bool {
+ return true;
+ }
- /**
- * @inheritDoc
- */
- protected function getKeywordParsers(): array
- {
- return [
- // Generic
- new TypeKeywordParser('type'),
- new ConstKeywordParser('const'),
- new EnumKeywordParser('enum'),
- new FormatKeywordParser('format'),
+ /**
+ * @inheritDoc
+ */
+ protected function getRefKeywordParser(): KeywordParser {
+ return new RefKeywordParser(
+ '$ref',
+ array(
+ array(
+ 'ref' => '$dynamicRef',
+ 'anchor' => '$dynamicAnchor',
+ 'fragment' => true,
+ ),
+ array(
+ 'ref' => '$recursiveRef',
+ 'anchor' => '$recursiveAnchor',
+ 'fragment' => false,
+ ),
+ )
+ );
+ }
- // String
- new MinLengthKeywordParser('minLength'),
- new MaxLengthKeywordParser('maxLength'),
- new PatternKeywordParser("pattern"),
- new ContentEncodingKeywordParser('contentEncoding'),
- new ContentMediaTypeKeywordParser('contentMediaType'),
- new ContentSchemaKeywordParser('contentSchema'),
+ /**
+ * @inheritDoc
+ */
+ protected function getKeywordParsers(): array {
+ return array(
+ // Generic
+ new TypeKeywordParser( 'type' ),
+ new ConstKeywordParser( 'const' ),
+ new EnumKeywordParser( 'enum' ),
+ new FormatKeywordParser( 'format' ),
- // Number
- new MinimumKeywordParser('minimum', 'exclusiveMinimum'),
- new MaximumKeywordParser('maximum', 'exclusiveMaximum'),
- new ExclusiveMinimumKeywordParser('exclusiveMinimum'),
- new ExclusiveMaximumKeywordParser('exclusiveMaximum'),
- new MultipleOfKeywordParser('multipleOf'),
+ // String
+ new MinLengthKeywordParser( 'minLength' ),
+ new MaxLengthKeywordParser( 'maxLength' ),
+ new PatternKeywordParser( 'pattern' ),
+ new ContentEncodingKeywordParser( 'contentEncoding' ),
+ new ContentMediaTypeKeywordParser( 'contentMediaType' ),
+ new ContentSchemaKeywordParser( 'contentSchema' ),
- // Array
- new MinItemsKeywordParser('minItems'),
- new MaxItemsKeywordParser('maxItems'),
- new UniqueItemsKeywordParser('uniqueItems'),
- new ContainsKeywordParser('contains', 'minContains', 'maxContains'),
- new ItemsKeywordParser('prefixItems', ItemsKeywordParser::ONLY_ARRAY),
- new ItemsKeywordParser('items', ItemsKeywordParser::ONLY_SCHEMA, 'prefixItems'),
- // keep for draft-2019-09 compatibility
- new AdditionalItemsKeywordParser('additionalItems'),
+ // Number
+ new MinimumKeywordParser( 'minimum', 'exclusiveMinimum' ),
+ new MaximumKeywordParser( 'maximum', 'exclusiveMaximum' ),
+ new ExclusiveMinimumKeywordParser( 'exclusiveMinimum' ),
+ new ExclusiveMaximumKeywordParser( 'exclusiveMaximum' ),
+ new MultipleOfKeywordParser( 'multipleOf' ),
- // Object
- new MinPropertiesKeywordParser('minProperties'),
- new MaxPropertiesKeywordParser('maxProperties'),
- new RequiredKeywordParser('required'),
- new DependenciesKeywordParser('dependencies'), // keep for draft-07 compatibility
- new DependentRequiredKeywordParser('dependentRequired'),
- new DependentSchemasKeywordParser('dependentSchemas'),
- new PropertyNamesKeywordParser('propertyNames'),
- new PropertiesKeywordParser('properties'),
- new PatternPropertiesKeywordParser('patternProperties'),
- new AdditionalPropertiesKeywordParser('additionalProperties'),
+ // Array
+ new MinItemsKeywordParser( 'minItems' ),
+ new MaxItemsKeywordParser( 'maxItems' ),
+ new UniqueItemsKeywordParser( 'uniqueItems' ),
+ new ContainsKeywordParser( 'contains', 'minContains', 'maxContains' ),
+ new ItemsKeywordParser( 'prefixItems', ItemsKeywordParser::ONLY_ARRAY ),
+ new ItemsKeywordParser( 'items', ItemsKeywordParser::ONLY_SCHEMA, 'prefixItems' ),
+ // keep for draft-2019-09 compatibility
+ new AdditionalItemsKeywordParser( 'additionalItems' ),
- // Conditionals
- new IfThenElseKeywordParser('if', 'then', 'else'),
- new AnyOfKeywordParser('anyOf'),
- new AllOfKeywordParser('allOf'),
- new OneOfKeywordParser('oneOf'),
- new NotKeywordParser('not'),
+ // Object
+ new MinPropertiesKeywordParser( 'minProperties' ),
+ new MaxPropertiesKeywordParser( 'maxProperties' ),
+ new RequiredKeywordParser( 'required' ),
+ new DependenciesKeywordParser( 'dependencies' ), // keep for draft-07 compatibility
+ new DependentRequiredKeywordParser( 'dependentRequired' ),
+ new DependentSchemasKeywordParser( 'dependentSchemas' ),
+ new PropertyNamesKeywordParser( 'propertyNames' ),
+ new PropertiesKeywordParser( 'properties' ),
+ new PatternPropertiesKeywordParser( 'patternProperties' ),
+ new AdditionalPropertiesKeywordParser( 'additionalProperties' ),
- // Unevaluated
- new UnevaluatedPropertiesKeywordParser('unevaluatedProperties'),
- new UnevaluatedItemsKeywordParser('unevaluatedItems'),
+ // Conditionals
+ new IfThenElseKeywordParser( 'if', 'then', 'else' ),
+ new AnyOfKeywordParser( 'anyOf' ),
+ new AllOfKeywordParser( 'allOf' ),
+ new OneOfKeywordParser( 'oneOf' ),
+ new NotKeywordParser( 'not' ),
- // Optional
- new DefaultKeywordParser('default'),
- ];
- }
+ // Unevaluated
+ new UnevaluatedPropertiesKeywordParser( 'unevaluatedProperties' ),
+ new UnevaluatedItemsKeywordParser( 'unevaluatedItems' ),
-}
\ No newline at end of file
+ // Optional
+ new DefaultKeywordParser( 'default' ),
+ );
+ }
+}
diff --git a/src/opis/json-schema/src/Parsers/KeywordParser.php b/src/opis/json-schema/src/Parsers/KeywordParser.php
index 0a8fad91..a111d1fb 100644
--- a/src/opis/json-schema/src/Parsers/KeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/KeywordParser.php
@@ -1,5 +1,6 @@
draft();
- return $draft !== '06' && $draft !== '07';
- }
+abstract class KeywordParser {
+
+ const TYPE_PREPEND = '_prepend';
+ const TYPE_BEFORE = '_before';
+ const TYPE_AFTER = '_after';
+ const TYPE_APPEND = '_append';
+
+ const TYPE_AFTER_REF = '_after_ref';
+
+ const TYPE_STRING = 'string';
+ const TYPE_NUMBER = 'number';
+ const TYPE_ARRAY = 'array';
+ const TYPE_OBJECT = 'object';
+
+ use KeywordParserTrait;
+
+ /**
+ * The keyword type, can be one of the TYPE_* const
+ *
+ * @return string
+ */
+ abstract public function type(): string;
+
+ /**
+ * @param SchemaInfo $info
+ * @param SchemaParser $parser
+ * @param object $shared
+ * @return Keyword|null
+ */
+ abstract public function parse( $info, $parser, $shared );
+
+ /**
+ * @param SchemaInfo $info
+ * @return bool
+ */
+ protected function trackEvaluated( $info ): bool {
+ $draft = $info->draft();
+ return $draft !== '06' && $draft !== '07';
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/KeywordParserTrait.php b/src/opis/json-schema/src/Parsers/KeywordParserTrait.php
index 939b7886..2fa9b200 100644
--- a/src/opis/json-schema/src/Parsers/KeywordParserTrait.php
+++ b/src/opis/json-schema/src/Parsers/KeywordParserTrait.php
@@ -1,5 +1,6 @@
keyword = $keyword;
- }
+ /** @var string */
+ protected $keyword;
- /**
- * @param object|SchemaInfo $schema
- * @param string|null $keyword
- * @return bool
- */
- protected function keywordExists($schema, $keyword = null): bool
- {
- if ($schema instanceof SchemaInfo) {
- $schema = $schema->data();
- }
+ /**
+ * @param string $keyword
+ */
+ public function __construct( string $keyword ) {
+ $this->keyword = $keyword;
+ }
- return property_exists($schema, $keyword ?? $this->keyword);
- }
+ /**
+ * @param object|SchemaInfo $schema
+ * @param string|null $keyword
+ * @return bool
+ */
+ protected function keywordExists( $schema, $keyword = null ): bool {
+ if ( $schema instanceof SchemaInfo ) {
+ $schema = $schema->data();
+ }
- /**
- * @param object|SchemaInfo $schema
- * @param string|null $keyword
- * @return mixed
- */
- protected function keywordValue($schema, $keyword = null)
- {
- if ($schema instanceof SchemaInfo) {
- $schema = $schema->data();
- }
+ return property_exists( $schema, $keyword ?? $this->keyword );
+ }
- return $schema->{$keyword ?? $this->keyword};
- }
+ /**
+ * @param object|SchemaInfo $schema
+ * @param string|null $keyword
+ * @return mixed
+ */
+ protected function keywordValue( $schema, $keyword = null ) {
+ if ( $schema instanceof SchemaInfo ) {
+ $schema = $schema->data();
+ }
- /**
- * @param string $message
- * @param SchemaInfo $info
- * @param string|null $keyword
- * @return InvalidKeywordException
- */
- protected function keywordException($message, $info, $keyword = null): InvalidKeywordException
- {
- $keyword = $keyword ?? $this->keyword;
+ return $schema->{$keyword ?? $this->keyword};
+ }
- return new InvalidKeywordException(str_replace('{keyword}', $keyword, $message), $keyword, $info);
- }
-}
\ No newline at end of file
+ /**
+ * @param string $message
+ * @param SchemaInfo $info
+ * @param string|null $keyword
+ * @return InvalidKeywordException
+ */
+ protected function keywordException( $message, $info, $keyword = null ): InvalidKeywordException {
+ $keyword = $keyword ?? $this->keyword;
+
+ return new InvalidKeywordException( str_replace( '{keyword}', $keyword, $message ), $keyword, $info );
+ }
+}
diff --git a/src/opis/json-schema/src/Parsers/KeywordValidatorParser.php b/src/opis/json-schema/src/Parsers/KeywordValidatorParser.php
index a1c049fe..c60a9e22 100644
--- a/src/opis/json-schema/src/Parsers/KeywordValidatorParser.php
+++ b/src/opis/json-schema/src/Parsers/KeywordValidatorParser.php
@@ -1,5 +1,6 @@
option('allowPragmas') || !$this->keywordExists($info)) {
- return null;
- }
-
- $value = $this->keywordValue($info);
-
- if (!is_object($value)) {
- throw $this->keywordException('{keyword} must be an object', $info);
- }
-
- $list = [];
-
- $draft = $info->draft() ?? $parser->defaultDraftVersion();
-
- $pragmaInfo = new SchemaInfo($value, null, $info->id() ?? $info->base(), $info->root(),
- array_merge($info->path(), [$this->keyword]), $draft);
-
- foreach ($parser->draft($draft)->pragmas() as $pragma) {
- if ($handler = $pragma->parse($pragmaInfo, $parser, $shared)) {
- $list[] = $handler;
- }
- }
-
- return $list ? new PragmaKeywordValidator($list) : null;
- }
+class PragmaKeywordValidatorParser extends KeywordValidatorParser {
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ if ( ! $parser->option( 'allowPragmas' ) || ! $this->keywordExists( $info ) ) {
+ return null;
+ }
+
+ $value = $this->keywordValue( $info );
+
+ if ( ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be an object', $info );
+ }
+
+ $list = array();
+
+ $draft = $info->draft() ?? $parser->defaultDraftVersion();
+
+ $pragmaInfo = new SchemaInfo(
+ $value,
+ null,
+ $info->id() ?? $info->base(),
+ $info->root(),
+ array_merge( $info->path(), array( $this->keyword ) ),
+ $draft
+ );
+
+ foreach ( $parser->draft( $draft )->pragmas() as $pragma ) {
+ if ( $handler = $pragma->parse( $pragmaInfo, $parser, $shared ) ) {
+ $list[] = $handler;
+ }
+ }
+
+ return $list ? new PragmaKeywordValidator( $list ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/AdditionalItemsKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/AdditionalItemsKeywordParser.php
index 3f527daf..e6bf59ba 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/AdditionalItemsKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/AdditionalItemsKeywordParser.php
@@ -1,5 +1,6 @@
option('keepAdditionalItemsKeyword') && $info->draft() === '2020-12') {
- return null;
- }
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_ARRAY;
+ }
- $schema = $info->data();
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ if ( ! $parser->option( 'keepAdditionalItemsKeyword' ) && $info->draft() === '2020-12' ) {
+ return null;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ $schema = $info->data();
- if (!property_exists($schema, 'items') || !is_array($schema->items)) {
- // Ignore additionalItems
- return null;
- }
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- $value = $this->keywordValue($schema);
+ if ( ! property_exists( $schema, 'items' ) || ! is_array( $schema->items ) ) {
+ // Ignore additionalItems
+ return null;
+ }
- if (!is_bool($value) && !is_object($value)) {
- throw $this->keywordException("{keyword} must be a json schema (object or boolean)", $info);
- }
+ $value = $this->keywordValue( $schema );
- return new AdditionalItemsKeyword($value, count($schema->items));
- }
+ if ( ! is_bool( $value ) && ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a json schema (object or boolean)', $info );
+ }
+
+ return new AdditionalItemsKeyword( $value, count( $schema->items ) );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/AdditionalPropertiesKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/AdditionalPropertiesKeywordParser.php
index bc889504..203bd665 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/AdditionalPropertiesKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/AdditionalPropertiesKeywordParser.php
@@ -1,5 +1,6 @@
data();
-
- if (!$this->keywordExists($schema)) {
- return null;
- }
-
- $value = $this->keywordValue($schema);
-
- if (!is_bool($value) && !is_object($value)) {
- throw $this->keywordException("{keyword} must be a json schema (object or boolean)", $info);
- }
-
- return new AdditionalPropertiesKeyword($value);
- }
+class AdditionalPropertiesKeywordParser extends KeywordParser {
+
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_OBJECT;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
+
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
+
+ $value = $this->keywordValue( $schema );
+
+ if ( ! is_bool( $value ) && ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a json schema (object or boolean)', $info );
+ }
+
+ return new AdditionalPropertiesKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/AllOfKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/AllOfKeywordParser.php
index 808b9f6a..3ae8f3be 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/AllOfKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/AllOfKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_AFTER;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (!is_array($value)) {
- throw $this->keywordException("{keyword} should be an array of json schemas", $info);
- }
+ $value = $this->keywordValue( $schema );
- if (!$value) {
- throw $this->keywordException("{keyword} must have at least one element", $info);
- }
+ if ( ! is_array( $value ) ) {
+ throw $this->keywordException( '{keyword} should be an array of json schemas', $info );
+ }
- $valid = 0;
+ if ( ! $value ) {
+ throw $this->keywordException( '{keyword} must have at least one element', $info );
+ }
- foreach ($value as $index => $item) {
- if ($item === false) {
- throw $this->keywordException("{keyword} contains false schema", $info);
- }
- if ($item === true) {
- $valid++;
- continue;
- }
- if (!is_object($item)) {
- throw $this->keywordException("{keyword}[{$index}] must be a json schema", $info);
- } elseif (!count(get_object_vars($item))) {
- $valid++;
- }
- }
+ $valid = 0;
- return $valid !== count($value) ? new AllOfKeyword($value) : null;
- }
+ foreach ( $value as $index => $item ) {
+ if ( $item === false ) {
+ throw $this->keywordException( '{keyword} contains false schema', $info );
+ }
+ if ( $item === true ) {
+ ++$valid;
+ continue;
+ }
+ if ( ! is_object( $item ) ) {
+ throw $this->keywordException( "{keyword}[{$index}] must be a json schema", $info );
+ } elseif ( ! count( get_object_vars( $item ) ) ) {
+ ++$valid;
+ }
+ }
+
+ return $valid !== count( $value ) ? new AllOfKeyword( $value ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/AnyOfKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/AnyOfKeywordParser.php
index 21458985..79db5019 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/AnyOfKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/AnyOfKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_AFTER;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (!is_array($value)) {
- throw $this->keywordException("{keyword} should be an array of json schemas", $info);
- }
+ $value = $this->keywordValue( $schema );
- if (!$value) {
- throw $this->keywordException("{keyword} must have at least one element", $info);
- }
+ if ( ! is_array( $value ) ) {
+ throw $this->keywordException( '{keyword} should be an array of json schemas', $info );
+ }
- $alwaysValid = false;
+ if ( ! $value ) {
+ throw $this->keywordException( '{keyword} must have at least one element', $info );
+ }
- foreach ($value as $index => $item) {
- if ($item === true) {
- $alwaysValid = true;
- continue;
- }
- if ($item === false) {
- continue;
- }
- if (!is_object($item)) {
- throw $this->keywordException("{keyword}[{$index}] must be a json schema", $info);
- } elseif (!count(get_object_vars($item))) {
- $alwaysValid = true;
- }
- }
+ $alwaysValid = false;
- return new AnyOfKeyword($value, $alwaysValid);
- }
+ foreach ( $value as $index => $item ) {
+ if ( $item === true ) {
+ $alwaysValid = true;
+ continue;
+ }
+ if ( $item === false ) {
+ continue;
+ }
+ if ( ! is_object( $item ) ) {
+ throw $this->keywordException( "{keyword}[{$index}] must be a json schema", $info );
+ } elseif ( ! count( get_object_vars( $item ) ) ) {
+ $alwaysValid = true;
+ }
+ }
+
+ return new AnyOfKeyword( $value, $alwaysValid );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/ConstKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/ConstKeywordParser.php
index 8ac34a90..5a198d1e 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/ConstKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/ConstKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_BEFORE;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new ConstDataKeyword($pointer);
- }
- }
+ $value = $this->keywordValue( $schema );
- $type = Helper::getJsonType($value);
- if ($type === null) {
- throw $this->keywordException("{keyword} contains unknown json data type", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new ConstDataKeyword( $pointer );
+ }
+ }
- if (isset($shared->types)) {
- if (!Helper::jsonTypeMatches($type, $shared->types)) {
- throw $this->keywordException("{keyword} contains a value that doesn't match the type keyword", $info);
- }
- } else {
- $shared->types = [$type];
- }
+ $type = Helper::getJsonType( $value );
+ if ( $type === null ) {
+ throw $this->keywordException( '{keyword} contains unknown json data type', $info );
+ }
- return new ConstKeyword($value);
- }
+ if ( isset( $shared->types ) ) {
+ if ( ! Helper::jsonTypeMatches( $type, $shared->types ) ) {
+ throw $this->keywordException( "{keyword} contains a value that doesn't match the type keyword", $info );
+ }
+ } else {
+ $shared->types = array( $type );
+ }
+ return new ConstKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/ContainsKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/ContainsKeywordParser.php
index 37e1de77..e5131eff 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/ContainsKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/ContainsKeywordParser.php
@@ -1,5 +1,6 @@
minContains = $minContains;
- $this->maxContains = $maxContains;
- }
+ /**
+ * @var string|null
+ */
+ protected $minContains;
+ /**
+ * @var string|null
+ */
+ protected $maxContains;
- /**
- * @inheritDoc
- */
- public function type(): string
- {
- return self::TYPE_ARRAY;
- }
+ public function __construct( string $keyword, $minContains = null, $maxContains = null ) {
+ parent::__construct( $keyword );
+ $this->minContains = $minContains;
+ $this->maxContains = $maxContains;
+ }
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\Info\SchemaInfo $info
- * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
- * @param object $shared
- */
- public function parse($info, $parser, $shared)
- {
- $schema = $info->data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_ARRAY;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (!is_bool($value) && !is_object($value)) {
- throw $this->keywordException("{keyword} must be a json schema (object or boolean)", $info);
- }
+ $value = $this->keywordValue( $schema );
- $min = $max = null;
+ if ( ! is_bool( $value ) && ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a json schema (object or boolean)', $info );
+ }
- if ($this->minContains && $this->keywordExists($schema, $this->minContains)) {
- $min = $this->keywordValue($schema, $this->minContains);
- if (!is_int($min) || $min < 0) {
- throw $this->keywordException("{keyword} must be a non-negative integer", $info, $this->minContains);
- }
- }
+ $min = $max = null;
- if ($this->maxContains && $this->keywordExists($schema, $this->maxContains)) {
- $max = $this->keywordValue($schema, $this->maxContains);
- if (!is_int($max) || $max < 0) {
- throw $this->keywordException("{keyword} must be a non-negative integer", $info, $this->maxContains);
- }
- if ($min !== null && $max < $min) {
- throw $this->keywordException("{keyword} must be greater than {$this->minContains}", $info, $this->maxContains);
- }
- } elseif ($min === 0) {
- return null;
- }
+ if ( $this->minContains && $this->keywordExists( $schema, $this->minContains ) ) {
+ $min = $this->keywordValue( $schema, $this->minContains );
+ if ( ! is_int( $min ) || $min < 0 ) {
+ throw $this->keywordException( '{keyword} must be a non-negative integer', $info, $this->minContains );
+ }
+ }
- return new ContainsKeyword($value, $min, $max);
- }
+ if ( $this->maxContains && $this->keywordExists( $schema, $this->maxContains ) ) {
+ $max = $this->keywordValue( $schema, $this->maxContains );
+ if ( ! is_int( $max ) || $max < 0 ) {
+ throw $this->keywordException( '{keyword} must be a non-negative integer', $info, $this->maxContains );
+ }
+ if ( $min !== null && $max < $min ) {
+ throw $this->keywordException( "{keyword} must be greater than {$this->minContains}", $info, $this->maxContains );
+ }
+ } elseif ( $min === 0 ) {
+ return null;
+ }
+
+ return new ContainsKeyword( $value, $min, $max );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/ContentEncodingKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/ContentEncodingKeywordParser.php
index 4f55e062..4bf58c23 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/ContentEncodingKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/ContentEncodingKeywordParser.php
@@ -1,5 +1,6 @@
optionAllowedForDraft('decodeContent', $info, $parser)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_STRING;
+ }
- $schema = $info->data();
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ if ( ! $this->optionAllowedForDraft( 'decodeContent', $info, $parser ) ) {
+ return null;
+ }
- $resolver = $parser->getContentEncodingResolver();
+ $schema = $info->data();
- if (!$resolver || !$this->keywordExists($schema)) {
- return null;
- }
+ $resolver = $parser->getContentEncodingResolver();
- $value = $this->keywordValue($schema);
+ if ( ! $resolver || ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (!is_string($value)) {
- throw $this->keywordException("{keyword} must be a string", $info);
- }
+ $value = $this->keywordValue( $schema );
- return new ContentEncodingKeyword(strtolower($value), $resolver);
- }
+ if ( ! is_string( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a string', $info );
+ }
+
+ return new ContentEncodingKeyword( strtolower( $value ), $resolver );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/ContentMediaTypeKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/ContentMediaTypeKeywordParser.php
index 82a7d8f9..c835b140 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/ContentMediaTypeKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/ContentMediaTypeKeywordParser.php
@@ -1,5 +1,6 @@
optionAllowedForDraft('decodeContent', $info, $parser)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_STRING;
+ }
- $schema = $info->data();
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ if ( ! $this->optionAllowedForDraft( 'decodeContent', $info, $parser ) ) {
+ return null;
+ }
- $resolver = $parser->getMediaTypeResolver();
+ $schema = $info->data();
- if (!$resolver || !$this->keywordExists($schema)) {
- return null;
- }
+ $resolver = $parser->getMediaTypeResolver();
- $value = $this->keywordValue($schema);
+ if ( ! $resolver || ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (!is_string($value)) {
- throw $this->keywordException("{keyword} must be a string", $info);
- }
+ $value = $this->keywordValue( $schema );
- return new ContentMediaTypeKeyword($value, $resolver);
- }
+ if ( ! is_string( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a string', $info );
+ }
+
+ return new ContentMediaTypeKeyword( $value, $resolver );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/ContentSchemaKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/ContentSchemaKeywordParser.php
index 08c1c1e9..eecaba2c 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/ContentSchemaKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/ContentSchemaKeywordParser.php
@@ -1,5 +1,6 @@
optionAllowedForDraft('decodeContent', $info, $parser)) {
- return null;
- }
-
- $schema = $info->data();
-
- if (!$this->keywordExists($schema)) {
- return null;
- }
-
- $value = $this->keywordValue($schema);
-
- if (!is_object($value)) {
- throw $this->keywordException("{keyword} must be a valid json schema object", $info);
- }
-
- return new ContentSchemaKeyword($value);
- }
+class ContentSchemaKeywordParser extends KeywordParser {
+
+ use DraftOptionTrait;
+
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_STRING;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ if ( ! $this->optionAllowedForDraft( 'decodeContent', $info, $parser ) ) {
+ return null;
+ }
+
+ $schema = $info->data();
+
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
+
+ $value = $this->keywordValue( $schema );
+
+ if ( ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a valid json schema object', $info );
+ }
+
+ return new ContentSchemaKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/DefaultKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/DefaultKeywordParser.php
index 99f1dcd3..35b3c57f 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/DefaultKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/DefaultKeywordParser.php
@@ -1,5 +1,6 @@
properties = $properties;
- }
+ /**
+ * @var string|null
+ */
+ protected $properties;
- /**
- * @inheritDoc
- */
- public function type(): string
- {
- return self::TYPE_APPEND;
- }
+ /**
+ * @inheritDoc
+ */
+ public function __construct( string $keyword, $properties = 'properties' ) {
+ parent::__construct( $keyword );
+ $this->properties = $properties;
+ }
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\Info\SchemaInfo $info
- * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
- * @param object $shared
- */
- public function parse($info, $parser, $shared)
- {
- $schema = $info->data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_APPEND;
+ }
- if (!$parser->option('allowDefaults')) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $defaults = null;
+ if ( ! $parser->option( 'allowDefaults' ) ) {
+ return null;
+ }
- if ($this->keywordExists($schema)) {
- $defaults = $this->keywordValue($schema);
+ $defaults = null;
- if (is_object($defaults)) {
- $defaults = (array)Helper::cloneValue($defaults);
- } else {
- $defaults = null;
- }
- }
+ if ( $this->keywordExists( $schema ) ) {
+ $defaults = $this->keywordValue( $schema );
- if ($this->properties !== null && property_exists($schema, $this->properties)
- && is_object($schema->{$this->properties})) {
- foreach ($schema->{$this->properties} as $name => $value) {
- if (is_object($value) && property_exists($value, $this->keyword)) {
- $defaults[$name] = $value->{$this->keyword};
- }
- }
- }
+ if ( is_object( $defaults ) ) {
+ $defaults = (array) Helper::cloneValue( $defaults );
+ } else {
+ $defaults = null;
+ }
+ }
- if (!$defaults) {
- return null;
- }
+ if ( $this->properties !== null && property_exists( $schema, $this->properties )
+ && is_object( $schema->{$this->properties} ) ) {
+ foreach ( $schema->{$this->properties} as $name => $value ) {
+ if ( is_object( $value ) && property_exists( $value, $this->keyword ) ) {
+ $defaults[ $name ] = $value->{$this->keyword};
+ }
+ }
+ }
- return new DefaultKeyword($defaults);
- }
+ if ( ! $defaults ) {
+ return null;
+ }
+
+ return new DefaultKeyword( $defaults );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/DependenciesKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/DependenciesKeywordParser.php
index ca3cc507..bd19dee0 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/DependenciesKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/DependenciesKeywordParser.php
@@ -1,5 +1,6 @@
option('keepDependenciesKeyword') && !in_array($info->draft(), ['06', '07'])) {
- return null;
- }
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_OBJECT;
+ }
- $schema = $info->data();
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ if ( ! $parser->option( 'keepDependenciesKeyword' ) && ! in_array( $info->draft(), array( '06', '07' ) ) ) {
+ return null;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
- if (!is_object($value)) {
- throw $this->keywordException("{keyword} must be an object", $info);
- }
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- $list = get_object_vars($value);
+ $value = $this->keywordValue( $schema );
+ if ( ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be an object', $info );
+ }
- foreach ($list as $name => $s) {
- if (is_array($s)) {
- if (!$s) {
- unset($list[$name]);
- continue;
- }
- foreach ($s as $p) {
- if (!is_string($p)) {
- throw $this->keywordException("{keyword} must be an object containing json schemas or arrays of property names", $info);
- }
- }
- $list[$name] = array_unique($s);
- } elseif (is_bool($s)) {
- if ($s) {
- unset($list[$name]);
- }
- } elseif (!is_object($s)) {
- throw $this->keywordException("{keyword} must be an object containing json schemas or arrays of property names", $info);
- }
- }
+ $list = get_object_vars( $value );
- return $list ? new DependenciesKeyword($list) : null;
- }
+ foreach ( $list as $name => $s ) {
+ if ( is_array( $s ) ) {
+ if ( ! $s ) {
+ unset( $list[ $name ] );
+ continue;
+ }
+ foreach ( $s as $p ) {
+ if ( ! is_string( $p ) ) {
+ throw $this->keywordException( '{keyword} must be an object containing json schemas or arrays of property names', $info );
+ }
+ }
+ $list[ $name ] = array_unique( $s );
+ } elseif ( is_bool( $s ) ) {
+ if ( $s ) {
+ unset( $list[ $name ] );
+ }
+ } elseif ( ! is_object( $s ) ) {
+ throw $this->keywordException( '{keyword} must be an object containing json schemas or arrays of property names', $info );
+ }
+ }
+
+ return $list ? new DependenciesKeyword( $list ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/DependentRequiredKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/DependentRequiredKeywordParser.php
index da237989..9b9cf6d0 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/DependentRequiredKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/DependentRequiredKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_OBJECT;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
- if (!is_object($value)) {
- throw $this->keywordException("{keyword} must be an object", $info);
- }
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- $list = [];
- foreach ($value as $name => $s) {
- if (!is_array($s)) {
- throw $this->keywordException("{keyword} must be an object containing json schemas or arrays of property names", $info);
- }
- if (!$s) {
- // Empty array
- continue;
- }
- foreach ($s as $p) {
- if (!is_string($p)) {
- throw $this->keywordException("{keyword} must be an object containing arrays of property names", $info);
- }
- }
- $list[$name] = array_unique($s);
- }
+ $value = $this->keywordValue( $schema );
+ if ( ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be an object', $info );
+ }
- return $list ? new DependentRequiredKeyword($list) : null;
- }
+ $list = array();
+ foreach ( $value as $name => $s ) {
+ if ( ! is_array( $s ) ) {
+ throw $this->keywordException( '{keyword} must be an object containing json schemas or arrays of property names', $info );
+ }
+ if ( ! $s ) {
+ // Empty array
+ continue;
+ }
+ foreach ( $s as $p ) {
+ if ( ! is_string( $p ) ) {
+ throw $this->keywordException( '{keyword} must be an object containing arrays of property names', $info );
+ }
+ }
+ $list[ $name ] = array_unique( $s );
+ }
+
+ return $list ? new DependentRequiredKeyword( $list ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/DependentSchemasKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/DependentSchemasKeywordParser.php
index f77f980a..69c91a25 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/DependentSchemasKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/DependentSchemasKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_OBJECT;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
- if (!is_object($value)) {
- throw $this->keywordException("{keyword} must be an object", $info);
- }
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- $valid = 0;
- $total = 0;
+ $value = $this->keywordValue( $schema );
+ if ( ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be an object', $info );
+ }
- foreach ($value as $name => $s) {
- $total++;
- if (is_bool($s)) {
- if ($s) {
- $valid++;
- }
- } elseif (!is_object($s)) {
- throw $this->keywordException("{keyword} must be an object containing json schemas", $info);
- } elseif (!count(get_object_vars($s))) {
- $valid++;
- }
- }
+ $valid = 0;
+ $total = 0;
- if (!$total) {
- return null;
- }
+ foreach ( $value as $name => $s ) {
+ ++$total;
+ if ( is_bool( $s ) ) {
+ if ( $s ) {
+ ++$valid;
+ }
+ } elseif ( ! is_object( $s ) ) {
+ throw $this->keywordException( '{keyword} must be an object containing json schemas', $info );
+ } elseif ( ! count( get_object_vars( $s ) ) ) {
+ ++$valid;
+ }
+ }
- return $valid !== $total ? new DependentSchemasKeyword($value) : null;
- }
+ if ( ! $total ) {
+ return null;
+ }
+
+ return $valid !== $total ? new DependentSchemasKeyword( $value ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/EnumKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/EnumKeywordParser.php
index 2aa6465f..c1c85034 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/EnumKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/EnumKeywordParser.php
@@ -1,5 +1,6 @@
data();
-
- if (!$this->keywordExists($schema)) {
- return null;
- }
-
- $value = $this->keywordValue($schema);
-
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new EnumDataKeyword($pointer);
- }
- }
-
- if (!is_array($value) || !$value) {
- throw $this->keywordException("{keyword} must be a non-empty array", $info);
- }
-
- $hasConst = property_exists($schema, 'const');
- $constMatched = false;
-
- $allowedTypes = isset($shared->types) ? $shared->types : null;
- $foundTypes = [];
- $list = [];
- foreach ($value as $item) {
- $type = Helper::getJsonType($item);
- if ($type === null) {
- throw $this->keywordException("{keyword} contains invalid json data type", $info);
- }
-
- if ($allowedTypes && !Helper::jsonTypeMatches($type, $allowedTypes)) {
- continue;
- }
-
- if ($hasConst && Helper::equals($item, $schema->const)) {
- $constMatched = true;
- break;
- }
-
- if (!in_array($type, $foundTypes)) {
- $foundTypes[] = $type;
- }
-
- $list[] = $item;
- }
-
- if ($hasConst) {
- if ($constMatched) {
- return null;
- }
- throw $this->keywordException("{keyword} does not contain the value of const keyword", $info);
- }
-
- if ($foundTypes) {
- if ($allowedTypes === null) {
- $shared->types = $foundTypes;
- } else {
- $shared->types = array_unique(array_merge($shared->types, $foundTypes));
- }
- }
-
- return new EnumKeyword($list);
- }
+class EnumKeywordParser extends KeywordParser {
+
+ use DataKeywordTrait;
+
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_BEFORE;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
+
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
+
+ $value = $this->keywordValue( $schema );
+
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new EnumDataKeyword( $pointer );
+ }
+ }
+
+ if ( ! is_array( $value ) || ! $value ) {
+ throw $this->keywordException( '{keyword} must be a non-empty array', $info );
+ }
+
+ $hasConst = property_exists( $schema, 'const' );
+ $constMatched = false;
+
+ $allowedTypes = isset( $shared->types ) ? $shared->types : null;
+ $foundTypes = array();
+ $list = array();
+ foreach ( $value as $item ) {
+ $type = Helper::getJsonType( $item );
+ if ( $type === null ) {
+ throw $this->keywordException( '{keyword} contains invalid json data type', $info );
+ }
+
+ if ( $allowedTypes && ! Helper::jsonTypeMatches( $type, $allowedTypes ) ) {
+ continue;
+ }
+
+ if ( $hasConst && Helper::equals( $item, $schema->const ) ) {
+ $constMatched = true;
+ break;
+ }
+
+ if ( ! in_array( $type, $foundTypes ) ) {
+ $foundTypes[] = $type;
+ }
+
+ $list[] = $item;
+ }
+
+ if ( $hasConst ) {
+ if ( $constMatched ) {
+ return null;
+ }
+ throw $this->keywordException( '{keyword} does not contain the value of const keyword', $info );
+ }
+
+ if ( $foundTypes ) {
+ if ( $allowedTypes === null ) {
+ $shared->types = $foundTypes;
+ } else {
+ $shared->types = array_unique( array_merge( $shared->types, $foundTypes ) );
+ }
+ }
+
+ return new EnumKeyword( $list );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/ExclusiveMaximumKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/ExclusiveMaximumKeywordParser.php
index 8f3cc97e..c51ce4d4 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/ExclusiveMaximumKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/ExclusiveMaximumKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_NUMBER;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (is_bool($value) && $parser->option('allowExclusiveMinMaxAsBool')) {
- return null;
- }
+ $value = $this->keywordValue( $schema );
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new ExclusiveMaximumDataKeyword($pointer);
- }
- }
+ if ( is_bool( $value ) && $parser->option( 'allowExclusiveMinMaxAsBool' ) ) {
+ return null;
+ }
- if (!is_int($value) && !is_float($value) || is_nan($value) || !is_finite($value)) {
- throw $this->keywordException('{keyword} must contain a valid number', $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new ExclusiveMaximumDataKeyword( $pointer );
+ }
+ }
- return new ExclusiveMaximumKeyword($value);
- }
+ if ( ! is_int( $value ) && ! is_float( $value ) || is_nan( $value ) || ! is_finite( $value ) ) {
+ throw $this->keywordException( '{keyword} must contain a valid number', $info );
+ }
+
+ return new ExclusiveMaximumKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/ExclusiveMinimumKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/ExclusiveMinimumKeywordParser.php
index 0f3ab97b..ce861634 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/ExclusiveMinimumKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/ExclusiveMinimumKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_NUMBER;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (is_bool($value) && $parser->option('allowExclusiveMinMaxAsBool')) {
- return null;
- }
+ $value = $this->keywordValue( $schema );
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new ExclusiveMinimumDataKeyword($pointer);
- }
- }
+ if ( is_bool( $value ) && $parser->option( 'allowExclusiveMinMaxAsBool' ) ) {
+ return null;
+ }
- if (!is_int($value) && !is_float($value) || is_nan($value) || !is_finite($value)) {
- throw $this->keywordException('{keyword} must contain a valid number', $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new ExclusiveMinimumDataKeyword( $pointer );
+ }
+ }
- return new ExclusiveMinimumKeyword($value);
- }
+ if ( ! is_int( $value ) && ! is_float( $value ) || is_nan( $value ) || ! is_finite( $value ) ) {
+ throw $this->keywordException( '{keyword} must contain a valid number', $info );
+ }
+
+ return new ExclusiveMinimumKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/FiltersKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/FiltersKeywordParser.php
index 477c6591..ad905e94 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/FiltersKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/FiltersKeywordParser.php
@@ -1,5 +1,6 @@
data();
-
- if (!$parser->option('allowFilters')) {
- return null;
- }
-
- $resolver = $parser->getFilterResolver();
-
- if (!$resolver || !$this->keywordExists($schema)) {
- return null;
- }
-
- $filters = $this->parseFilters($parser, $resolver, $this->keywordValue($schema), $info);
- if (!$filters) {
- return null;
- }
-
- return new FiltersKeyword($filters);
- }
-
- /**
- * @param SchemaParser $parser
- * @param FilterResolver $filterResolver
- * @param mixed $filters
- * @param SchemaInfo $info
- * @return array|null
- */
- protected function parseFilters(
- $parser,
- $filterResolver,
- $filters,
- $info
- )
- {
- if (is_string($filters)) {
- if ($filters = $this->parseFilter($parser, $filterResolver, $filters, $info)) {
- return [$filters];
- }
-
- return null;
- }
-
- if (is_object($filters)) {
- if ($filter = $this->parseFilter($parser, $filterResolver, $filters, $info)) {
- return [$filter];
- }
-
- return null;
- }
-
- if (is_array($filters)) {
- if (!$filters) {
- return null;
- }
- $list = [];
- foreach ($filters as $filter) {
- if ($filter = $this->parseFilter($parser, $filterResolver, $filter, $info)) {
- $list[] = $filter;
- }
- }
-
- return $list ?: null;
- }
-
- throw $this->keywordException('{keyword} can be a non-empty string, an object or an array of string and objects', $info);
- }
-
- /**
- * @param SchemaParser $parser
- * @param FilterResolver $resolver
- * @param $filter
- * @param SchemaInfo $info
- * @return object|null
- */
- protected function parseFilter(
- $parser,
- $resolver,
- $filter,
- $info
- )
- {
- $vars = null;
- if (is_object($filter)) {
- if (!property_exists($filter, '$func') || !is_string($filter->{'$func'}) || $filter->{'$func'} === '') {
- throw $this->keywordException('$func (for {keyword}) must be a non-empty string', $info);
- }
-
- $vars = get_object_vars($filter);
- unset($vars['$func']);
-
- if (property_exists($filter, '$vars')) {
- if (!is_object($filter->{'$vars'})) {
- throw $this->keywordException('$vars (for {keyword}) must be a string', $info);
- }
- unset($vars['$vars']);
- $vars = get_object_vars($filter->{'$vars'}) + $vars;
- }
-
- $filter = $filter->{'$func'};
- } elseif (!is_string($filter) || $filter === '') {
- throw $this->keywordException('{keyword} can be a non-empty string, an object or an array of string and objects', $info);
- }
-
- $list = $resolver->resolveAll($filter);
- if (!$list) {
- throw $this->keywordException("{keyword}: {$filter} doesn't exists", $info);
- }
-
- $list = $this->resolveSubTypes($list);
-
- return (object)[
- 'name' => $filter,
- 'args' => $vars ? $this->createVariables($parser, $vars) : null,
- 'types' => $list,
- ];
- }
+ ResolverTrait, VariablesTrait};
+
+class FiltersKeywordParser extends KeywordParser {
+
+ use ResolverTrait;
+ use VariablesTrait;
+
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_APPEND;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
+
+ if ( ! $parser->option( 'allowFilters' ) ) {
+ return null;
+ }
+
+ $resolver = $parser->getFilterResolver();
+
+ if ( ! $resolver || ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
+
+ $filters = $this->parseFilters( $parser, $resolver, $this->keywordValue( $schema ), $info );
+ if ( ! $filters ) {
+ return null;
+ }
+
+ return new FiltersKeyword( $filters );
+ }
+
+ /**
+ * @param SchemaParser $parser
+ * @param FilterResolver $filterResolver
+ * @param mixed $filters
+ * @param SchemaInfo $info
+ * @return array|null
+ */
+ protected function parseFilters(
+ $parser,
+ $filterResolver,
+ $filters,
+ $info
+ ) {
+ if ( is_string( $filters ) ) {
+ if ( $filters = $this->parseFilter( $parser, $filterResolver, $filters, $info ) ) {
+ return array( $filters );
+ }
+
+ return null;
+ }
+
+ if ( is_object( $filters ) ) {
+ if ( $filter = $this->parseFilter( $parser, $filterResolver, $filters, $info ) ) {
+ return array( $filter );
+ }
+
+ return null;
+ }
+
+ if ( is_array( $filters ) ) {
+ if ( ! $filters ) {
+ return null;
+ }
+ $list = array();
+ foreach ( $filters as $filter ) {
+ if ( $filter = $this->parseFilter( $parser, $filterResolver, $filter, $info ) ) {
+ $list[] = $filter;
+ }
+ }
+
+ return $list ?: null;
+ }
+
+ throw $this->keywordException( '{keyword} can be a non-empty string, an object or an array of string and objects', $info );
+ }
+
+ /**
+ * @param SchemaParser $parser
+ * @param FilterResolver $resolver
+ * @param $filter
+ * @param SchemaInfo $info
+ * @return object|null
+ */
+ protected function parseFilter(
+ $parser,
+ $resolver,
+ $filter,
+ $info
+ ) {
+ $vars = null;
+ if ( is_object( $filter ) ) {
+ if ( ! property_exists( $filter, '$func' ) || ! is_string( $filter->{'$func'} ) || $filter->{'$func'} === '' ) {
+ throw $this->keywordException( '$func (for {keyword}) must be a non-empty string', $info );
+ }
+
+ $vars = get_object_vars( $filter );
+ unset( $vars['$func'] );
+
+ if ( property_exists( $filter, '$vars' ) ) {
+ if ( ! is_object( $filter->{'$vars'} ) ) {
+ throw $this->keywordException( '$vars (for {keyword}) must be a string', $info );
+ }
+ unset( $vars['$vars'] );
+ $vars = get_object_vars( $filter->{'$vars'} ) + $vars;
+ }
+
+ $filter = $filter->{'$func'};
+ } elseif ( ! is_string( $filter ) || $filter === '' ) {
+ throw $this->keywordException( '{keyword} can be a non-empty string, an object or an array of string and objects', $info );
+ }
+
+ $list = $resolver->resolveAll( $filter );
+ if ( ! $list ) {
+ throw $this->keywordException( "{keyword}: {$filter} doesn't exists", $info );
+ }
+
+ $list = $this->resolveSubTypes( $list );
+
+ return (object) array(
+ 'name' => $filter,
+ 'args' => $vars ? $this->createVariables( $parser, $vars ) : null,
+ 'types' => $list,
+ );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/FormatKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/FormatKeywordParser.php
index 4791e05f..b2ce30ad 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/FormatKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/FormatKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_BEFORE;
+ }
- $resolver = $parser->getFormatResolver();
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- if (!$resolver || !$parser->option('allowFormats') || !$this->keywordExists($schema)) {
- return null;
- }
+ $resolver = $parser->getFormatResolver();
- $value = $this->keywordValue($schema);
+ if ( ! $resolver || ! $parser->option( 'allowFormats' ) || ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new FormatDataKeyword($pointer, $resolver);
- }
- }
+ $value = $this->keywordValue( $schema );
- if (!is_string($value)) {
- throw $this->keywordException("{keyword} must be a string", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new FormatDataKeyword( $pointer, $resolver );
+ }
+ }
- $list = $resolver->resolveAll($value);
+ if ( ! is_string( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a string', $info );
+ }
- if (!$list) {
- return null;
- }
+ $list = $resolver->resolveAll( $value );
- return new FormatKeyword($value, $this->resolveSubTypes($list));
- }
+ if ( ! $list ) {
+ return null;
+ }
+
+ return new FormatKeyword( $value, $this->resolveSubTypes( $list ) );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/IfThenElseKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/IfThenElseKeywordParser.php
index df8862ba..38ac7f80 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/IfThenElseKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/IfThenElseKeywordParser.php
@@ -1,5 +1,6 @@
then = $then;
- $this->else = $else;
- }
-
- /**
- * @inheritDoc
- */
- public function type(): string
- {
- return self::TYPE_AFTER;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\Info\SchemaInfo $info
- * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
- * @param object $shared
- */
- public function parse($info, $parser, $shared)
- {
- $schema = $info->data();
-
- if (!$this->keywordExists($schema)) {
- return null;
- }
-
- $if = $this->keywordValue($schema);
- if (!$this->isJsonSchema($if)) {
- throw $this->keywordException("{keyword} keyword must be a json schema", $info);
- }
-
- $then = true;
- if (property_exists($schema, $this->then)) {
- $then = $schema->{$this->then};
- }
- if (!$this->isJsonSchema($then)) {
- throw $this->keywordException("{keyword} keyword must be a json schema", $info, $this->then);
- }
-
- $else = true;
- if (property_exists($schema, $this->else)) {
- $else = $schema->{$this->else};
- }
- if (!$this->isJsonSchema($else)) {
- throw $this->keywordException("{keyword} keyword must be a json schema", $info, $this->else);
- }
-
- if ($if === true) {
- if ($then === true) {
- return null;
- }
- $else = true;
- } elseif ($if === false) {
- if ($else === true) {
- return null;
- }
- $then = true;
- } elseif ($then === true && $else === true) {
- return null;
- }
-
- return new IfThenElseKeyword($if, $then, $else);
- }
-
- /**
- * @param $value
- * @return bool
- */
- protected function isJsonSchema($value): bool
- {
- return is_bool($value) || is_object($value);
- }
+class IfThenElseKeywordParser extends KeywordParser {
+
+
+ /**
+ * @var string
+ */
+ protected $then;
+
+ /**
+ * @var string
+ */
+ protected $else;
+
+ /**
+ * @param string $if
+ * @param string $then
+ * @param string $else
+ */
+ public function __construct( string $if, string $then, string $else ) {
+ parent::__construct( $if );
+ $this->then = $then;
+ $this->else = $else;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_AFTER;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
+
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
+
+ $if = $this->keywordValue( $schema );
+ if ( ! $this->isJsonSchema( $if ) ) {
+ throw $this->keywordException( '{keyword} keyword must be a json schema', $info );
+ }
+
+ $then = true;
+ if ( property_exists( $schema, $this->then ) ) {
+ $then = $schema->{$this->then};
+ }
+ if ( ! $this->isJsonSchema( $then ) ) {
+ throw $this->keywordException( '{keyword} keyword must be a json schema', $info, $this->then );
+ }
+
+ $else = true;
+ if ( property_exists( $schema, $this->else ) ) {
+ $else = $schema->{$this->else};
+ }
+ if ( ! $this->isJsonSchema( $else ) ) {
+ throw $this->keywordException( '{keyword} keyword must be a json schema', $info, $this->else );
+ }
+
+ if ( $if === true ) {
+ if ( $then === true ) {
+ return null;
+ }
+ $else = true;
+ } elseif ( $if === false ) {
+ if ( $else === true ) {
+ return null;
+ }
+ $then = true;
+ } elseif ( $then === true && $else === true ) {
+ return null;
+ }
+
+ return new IfThenElseKeyword( $if, $then, $else );
+ }
+
+ /**
+ * @param $value
+ * @return bool
+ */
+ protected function isJsonSchema( $value ): bool {
+ return is_bool( $value ) || is_object( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/ItemsKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/ItemsKeywordParser.php
index d944ee04..666e6c4f 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/ItemsKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/ItemsKeywordParser.php
@@ -1,5 +1,6 @@
mode = $mode;
- $this->startIndexKeyword = $startIndexKeyword;
- }
+ /**
+ * @var int
+ */
+ protected $mode;
+ /**
+ * @var string|null
+ */
+ protected $startIndexKeyword;
- /**
- * @inheritDoc
- */
- public function type(): string
- {
- return self::TYPE_ARRAY;
- }
+ public function __construct( string $keyword, int $mode = self::BOTH, $startIndexKeyword = null ) {
+ parent::__construct( $keyword );
+ $this->mode = $mode;
+ $this->startIndexKeyword = $startIndexKeyword;
+ }
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\Info\SchemaInfo $info
- * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
- * @param object $shared
- */
- public function parse($info, $parser, $shared)
- {
- $schema = $info->data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_ARRAY;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- $alwaysValid = false;
+ $value = $this->keywordValue( $schema );
- if (is_bool($value)) {
- if ($this->mode === self::ONLY_ARRAY) {
- throw $this->keywordException("{keyword} must contain an array of json schemas", $info);
- }
- if ($value) {
- $alwaysValid = true;
- }
- } elseif (is_array($value)) {
- if ($this->mode === self::ONLY_SCHEMA) {
- throw $this->keywordException("{keyword} must contain a valid json schema", $info);
- }
- $valid = 0;
- foreach ($value as $index => $v) {
- if (is_bool($v)) {
- if ($v) {
- $valid++;
- }
- } elseif (!is_object($v)) {
- throw $this->keywordException("{keyword}[$index] must contain a valid json schema", $info);
- } elseif (!count(get_object_vars($v))) {
- $valid++;
- }
- }
- if ($valid === count($value)) {
- $alwaysValid = true;
- }
- } elseif (!is_object($value)) {
- if ($this->mode === self::BOTH) {
- throw $this->keywordException("{keyword} must be a json schema or an array of json schemas", $info);
- } elseif ($this->mode === self::ONLY_ARRAY) {
- throw $this->keywordException("{keyword} must contain an array of json schemas", $info);
- } else {
- throw $this->keywordException("{keyword} must contain a valid json schema", $info);
- }
- } else {
- if ($this->mode === self::ONLY_ARRAY) {
- throw $this->keywordException("{keyword} must contain an array of json schemas", $info);
- }
- if (!count(get_object_vars($value))) {
- $alwaysValid = true;
- }
- }
+ $alwaysValid = false;
- $startIndex = 0;
- if ($this->startIndexKeyword !== null && $this->keywordExists($schema, $this->startIndexKeyword)) {
- $start = $this->keywordValue($schema, $this->startIndexKeyword);
- if (is_array($start)) {
- $startIndex = count($start);
- }
- }
+ if ( is_bool( $value ) ) {
+ if ( $this->mode === self::ONLY_ARRAY ) {
+ throw $this->keywordException( '{keyword} must contain an array of json schemas', $info );
+ }
+ if ( $value ) {
+ $alwaysValid = true;
+ }
+ } elseif ( is_array( $value ) ) {
+ if ( $this->mode === self::ONLY_SCHEMA ) {
+ throw $this->keywordException( '{keyword} must contain a valid json schema', $info );
+ }
+ $valid = 0;
+ foreach ( $value as $index => $v ) {
+ if ( is_bool( $v ) ) {
+ if ( $v ) {
+ ++$valid;
+ }
+ } elseif ( ! is_object( $v ) ) {
+ throw $this->keywordException( "{keyword}[$index] must contain a valid json schema", $info );
+ } elseif ( ! count( get_object_vars( $v ) ) ) {
+ ++$valid;
+ }
+ }
+ if ( $valid === count( $value ) ) {
+ $alwaysValid = true;
+ }
+ } elseif ( ! is_object( $value ) ) {
+ if ( $this->mode === self::BOTH ) {
+ throw $this->keywordException( '{keyword} must be a json schema or an array of json schemas', $info );
+ } elseif ( $this->mode === self::ONLY_ARRAY ) {
+ throw $this->keywordException( '{keyword} must contain an array of json schemas', $info );
+ } else {
+ throw $this->keywordException( '{keyword} must contain a valid json schema', $info );
+ }
+ } else {
+ if ( $this->mode === self::ONLY_ARRAY ) {
+ throw $this->keywordException( '{keyword} must contain an array of json schemas', $info );
+ }
+ if ( ! count( get_object_vars( $value ) ) ) {
+ $alwaysValid = true;
+ }
+ }
- return new ItemsKeyword($value, $alwaysValid, $this->keyword, $startIndex);
- }
+ $startIndex = 0;
+ if ( $this->startIndexKeyword !== null && $this->keywordExists( $schema, $this->startIndexKeyword ) ) {
+ $start = $this->keywordValue( $schema, $this->startIndexKeyword );
+ if ( is_array( $start ) ) {
+ $startIndex = count( $start );
+ }
+ }
+
+ return new ItemsKeyword( $value, $alwaysValid, $this->keyword, $startIndex );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/MaxItemsKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/MaxItemsKeywordParser.php
index f33cd92d..231761c4 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/MaxItemsKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/MaxItemsKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_ARRAY;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new MaxItemsDataKeyword($pointer);
- }
- }
+ $value = $this->keywordValue( $schema );
- if (!is_int($value) || $value < 0) {
- throw $this->keywordException("{keyword} most be a positive integer", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new MaxItemsDataKeyword( $pointer );
+ }
+ }
- return new MaxItemsKeyword($value);
- }
+ if ( ! is_int( $value ) || $value < 0 ) {
+ throw $this->keywordException( '{keyword} most be a positive integer', $info );
+ }
+
+ return new MaxItemsKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/MaxLengthKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/MaxLengthKeywordParser.php
index 5f691d53..6d7fef6e 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/MaxLengthKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/MaxLengthKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_STRING;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new MaxLengthDataKeyword($pointer);
- }
- }
+ $value = $this->keywordValue( $schema );
- if (!is_int($value) || $value < 0) {
- throw $this->keywordException("{keyword} must be a non-negative integer", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new MaxLengthDataKeyword( $pointer );
+ }
+ }
- return new MaxLengthKeyword($value);
- }
+ if ( ! is_int( $value ) || $value < 0 ) {
+ throw $this->keywordException( '{keyword} must be a non-negative integer', $info );
+ }
+
+ return new MaxLengthKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/MaxPropertiesKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/MaxPropertiesKeywordParser.php
index dc42ce46..63aaddaf 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/MaxPropertiesKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/MaxPropertiesKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_OBJECT;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new MaxPropertiesDataKeyword($pointer);
- }
- }
+ $value = $this->keywordValue( $schema );
- if (!is_int($value) || $value < 0) {
- throw $this->keywordException("{keyword} must be a non-negative integer", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new MaxPropertiesDataKeyword( $pointer );
+ }
+ }
- return new MaxPropertiesKeywords($value);
- }
+ if ( ! is_int( $value ) || $value < 0 ) {
+ throw $this->keywordException( '{keyword} must be a non-negative integer', $info );
+ }
+
+ return new MaxPropertiesKeywords( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/MaximumKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/MaximumKeywordParser.php
index e016403d..45d6eae4 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/MaximumKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/MaximumKeywordParser.php
@@ -1,5 +1,6 @@
exclusiveKeyword = $exclusiveKeyword;
- }
+ /**
+ * @var string|null
+ */
+ protected $exclusiveKeyword;
- /**
- * @inheritDoc
- */
- public function type(): string
- {
- return self::TYPE_NUMBER;
- }
+ /**
+ * @param string $keyword
+ * @param string|null $exclusiveKeyword
+ */
+ public function __construct( string $keyword, $exclusiveKeyword = null ) {
+ parent::__construct( $keyword );
+ $this->exclusiveKeyword = $exclusiveKeyword;
+ }
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\Info\SchemaInfo $info
- * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
- * @param object $shared
- */
- public function parse($info, $parser, $shared)
- {
- $schema = $info->data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_NUMBER;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- $exclusive = false;
- if ($parser->option('allowExclusiveMinMaxAsBool') &&
- $this->exclusiveKeyword !== null &&
- property_exists($schema, $this->exclusiveKeyword)) {
- $exclusive = $schema->{$this->exclusiveKeyword} === true;
- }
+ $value = $this->keywordValue( $schema );
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return $exclusive
- ? new ExclusiveMaximumDataKeyword($pointer)
- : new MaximumDataKeyword($pointer);
- }
- }
+ $exclusive = false;
+ if ( $parser->option( 'allowExclusiveMinMaxAsBool' ) &&
+ $this->exclusiveKeyword !== null &&
+ property_exists( $schema, $this->exclusiveKeyword ) ) {
+ $exclusive = $schema->{$this->exclusiveKeyword} === true;
+ }
- if (!is_int($value) && !is_float($value) || is_nan($value) || !is_finite($value)) {
- throw $this->keywordException('{keyword} must contain a valid number', $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return $exclusive
+ ? new ExclusiveMaximumDataKeyword( $pointer )
+ : new MaximumDataKeyword( $pointer );
+ }
+ }
- return $exclusive
- ? new ExclusiveMaximumKeyword($value)
- : new MaximumKeyword($value);
- }
+ if ( ! is_int( $value ) && ! is_float( $value ) || is_nan( $value ) || ! is_finite( $value ) ) {
+ throw $this->keywordException( '{keyword} must contain a valid number', $info );
+ }
+
+ return $exclusive
+ ? new ExclusiveMaximumKeyword( $value )
+ : new MaximumKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/MinItemsKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/MinItemsKeywordParser.php
index 2e36c18b..eb0ddbb6 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/MinItemsKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/MinItemsKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_ARRAY;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new MinItemsDataKeyword($pointer);
- }
- }
+ $value = $this->keywordValue( $schema );
- if (!is_int($value) || $value < 0) {
- throw $this->keywordException("{keyword} most be a positive integer", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new MinItemsDataKeyword( $pointer );
+ }
+ }
- if ($value === 0) {
- return null;
- }
+ if ( ! is_int( $value ) || $value < 0 ) {
+ throw $this->keywordException( '{keyword} most be a positive integer', $info );
+ }
- return new MinItemsKeyword($value);
- }
+ if ( $value === 0 ) {
+ return null;
+ }
+
+ return new MinItemsKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/MinLengthKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/MinLengthKeywordParser.php
index 261330e7..54364e3a 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/MinLengthKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/MinLengthKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_STRING;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new MinLengthDataKeyword($pointer);
- }
- }
+ $value = $this->keywordValue( $schema );
- if (!is_int($value) || $value < 0) {
- throw $this->keywordException("{keyword} must be a non-negative integer", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new MinLengthDataKeyword( $pointer );
+ }
+ }
- if ($value === 0) {
- return null;
- }
+ if ( ! is_int( $value ) || $value < 0 ) {
+ throw $this->keywordException( '{keyword} must be a non-negative integer', $info );
+ }
- return new MinLengthKeyword($value);
- }
+ if ( $value === 0 ) {
+ return null;
+ }
+
+ return new MinLengthKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/MinPropertiesKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/MinPropertiesKeywordParser.php
index 62592705..4fd66fb6 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/MinPropertiesKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/MinPropertiesKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_OBJECT;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new MinPropertiesDataKeyword($pointer);
- }
- }
+ $value = $this->keywordValue( $schema );
- if (!is_int($value) || $value < 0) {
- throw $this->keywordException("{keyword} must be a non-negative integer", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new MinPropertiesDataKeyword( $pointer );
+ }
+ }
- if ($value === 0) {
- return null;
- }
+ if ( ! is_int( $value ) || $value < 0 ) {
+ throw $this->keywordException( '{keyword} must be a non-negative integer', $info );
+ }
- return new MinPropertiesKeyword($value);
- }
+ if ( $value === 0 ) {
+ return null;
+ }
+
+ return new MinPropertiesKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/MinimumKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/MinimumKeywordParser.php
index 09fd9119..022ac1be 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/MinimumKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/MinimumKeywordParser.php
@@ -1,5 +1,6 @@
exclusiveKeyword = $exclusiveKeyword;
- }
+ /**
+ * @var string|null
+ */
+ protected $exclusiveKeyword;
- /**
- * @inheritDoc
- */
- public function type(): string
- {
- return self::TYPE_NUMBER;
- }
+ /**
+ * @param string $keyword
+ * @param string|null $exclusiveKeyword
+ */
+ public function __construct( string $keyword, $exclusiveKeyword = null ) {
+ parent::__construct( $keyword );
+ $this->exclusiveKeyword = $exclusiveKeyword;
+ }
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\Info\SchemaInfo $info
- * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
- * @param object $shared
- */
- public function parse($info, $parser, $shared)
- {
- $schema = $info->data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_NUMBER;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- $exclusive = false;
- if ($parser->option('allowExclusiveMinMaxAsBool') &&
- $this->exclusiveKeyword !== null &&
- property_exists($schema, $this->exclusiveKeyword)) {
- $exclusive = $schema->{$this->exclusiveKeyword} === true;
- }
+ $value = $this->keywordValue( $schema );
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return $exclusive
- ? new ExclusiveMinimumDataKeyword($pointer)
- : new MinimumDataKeyword($pointer);
- }
- }
+ $exclusive = false;
+ if ( $parser->option( 'allowExclusiveMinMaxAsBool' ) &&
+ $this->exclusiveKeyword !== null &&
+ property_exists( $schema, $this->exclusiveKeyword ) ) {
+ $exclusive = $schema->{$this->exclusiveKeyword} === true;
+ }
- if (!is_int($value) && !is_float($value) || is_nan($value) || !is_finite($value)) {
- throw $this->keywordException('{keyword} must contain a valid number', $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return $exclusive
+ ? new ExclusiveMinimumDataKeyword( $pointer )
+ : new MinimumDataKeyword( $pointer );
+ }
+ }
- return $exclusive
- ? new ExclusiveMinimumKeyword($value)
- : new MinimumKeyword($value);
- }
+ if ( ! is_int( $value ) && ! is_float( $value ) || is_nan( $value ) || ! is_finite( $value ) ) {
+ throw $this->keywordException( '{keyword} must contain a valid number', $info );
+ }
+
+ return $exclusive
+ ? new ExclusiveMinimumKeyword( $value )
+ : new MinimumKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/MultipleOfKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/MultipleOfKeywordParser.php
index 516ca674..ab0cfa69 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/MultipleOfKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/MultipleOfKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_NUMBER;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new MultipleOfDataKeyword($pointer);
- }
- }
+ $value = $this->keywordValue( $schema );
- if (!is_int($value) && !is_float($value) || is_nan($value) || !is_finite($value)) {
- throw $this->keywordException("{keyword} must be a valid number (integer or float)", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new MultipleOfDataKeyword( $pointer );
+ }
+ }
- if ($value <= 0) {
- throw $this->keywordException("{keyword} must be greater than zero", $info);
- }
+ if ( ! is_int( $value ) && ! is_float( $value ) || is_nan( $value ) || ! is_finite( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a valid number (integer or float)', $info );
+ }
- return new MultipleOfKeyword($value);
- }
+ if ( $value <= 0 ) {
+ throw $this->keywordException( '{keyword} must be greater than zero', $info );
+ }
+
+ return new MultipleOfKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/NotKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/NotKeywordParser.php
index 7832bbce..d41ab803 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/NotKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/NotKeywordParser.php
@@ -1,5 +1,6 @@
data();
-
- if (!$this->keywordExists($schema)) {
- return null;
- }
-
- $value = $this->keywordValue($schema);
-
- if (is_bool($value)) {
- if (!$value) {
- return null;
- }
- } elseif (!is_object($value)) {
- throw $this->keywordException("{keyword} must contain a json schema (object or boolean)", $info);
- }
-
- return new NotKeyword($value);
- }
+class NotKeywordParser extends KeywordParser {
+
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_AFTER;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
+
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
+
+ $value = $this->keywordValue( $schema );
+
+ if ( is_bool( $value ) ) {
+ if ( ! $value ) {
+ return null;
+ }
+ } elseif ( ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must contain a json schema (object or boolean)', $info );
+ }
+
+ return new NotKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/OneOfKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/OneOfKeywordParser.php
index a0570f2c..4ba57db7 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/OneOfKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/OneOfKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_AFTER;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (!is_array($value)) {
- throw $this->keywordException("{keyword} should be an array of json schemas", $info);
- }
+ $value = $this->keywordValue( $schema );
- if (!$value) {
- throw $this->keywordException("{keyword} must have at least one element", $info);
- }
+ if ( ! is_array( $value ) ) {
+ throw $this->keywordException( '{keyword} should be an array of json schemas', $info );
+ }
- $valid = 0;
+ if ( ! $value ) {
+ throw $this->keywordException( '{keyword} must have at least one element', $info );
+ }
- foreach ($value as $index => $item) {
- if ($item === false) {
- continue;
- }
- if ($item === true) {
- if (++$valid > 1) {
- throw $this->keywordException("{keyword} contains multiple true values", $info);
- }
- continue;
- }
- if (!is_object($item)) {
- throw $this->keywordException("{keyword}[{$index}] must be a json schema", $info);
- } elseif (!count(get_object_vars($item))) {
- if (++$valid > 1) {
- throw $this->keywordException("{keyword} contains multiple true values", $info);
- }
- }
- }
+ $valid = 0;
- return new OneOfKeyword($value);
- }
+ foreach ( $value as $index => $item ) {
+ if ( $item === false ) {
+ continue;
+ }
+ if ( $item === true ) {
+ if ( ++$valid > 1 ) {
+ throw $this->keywordException( '{keyword} contains multiple true values', $info );
+ }
+ continue;
+ }
+ if ( ! is_object( $item ) ) {
+ throw $this->keywordException( "{keyword}[{$index}] must be a json schema", $info );
+ } elseif ( ! count( get_object_vars( $item ) ) ) {
+ if ( ++$valid > 1 ) {
+ throw $this->keywordException( '{keyword} contains multiple true values', $info );
+ }
+ }
+ }
+
+ return new OneOfKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/PatternKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/PatternKeywordParser.php
index 2ffd51e4..b54f79b0 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/PatternKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/PatternKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_STRING;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new PatternDataKeyword($pointer);
- }
- }
+ $value = $this->keywordValue( $schema );
- if (!is_string($value)) {
- throw $this->keywordException("{keyword} value must be a string", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new PatternDataKeyword( $pointer );
+ }
+ }
- if (!Helper::isValidPattern($value)) {
- throw $this->keywordException("{keyword} value must be a valid regex", $info);
- }
+ if ( ! is_string( $value ) ) {
+ throw $this->keywordException( '{keyword} value must be a string', $info );
+ }
- return new PatternKeyword($value);
- }
+ if ( ! Helper::isValidPattern( $value ) ) {
+ throw $this->keywordException( '{keyword} value must be a valid regex', $info );
+ }
+
+ return new PatternKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/PatternPropertiesKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/PatternPropertiesKeywordParser.php
index c6aff641..5b03f714 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/PatternPropertiesKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/PatternPropertiesKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_OBJECT;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
- if (!is_object($value)) {
- throw $this->keywordException("{keyword} must be an object", $info);
- }
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- $list = [];
+ $value = $this->keywordValue( $schema );
+ if ( ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be an object', $info );
+ }
- foreach ($value as $pattern => $item) {
- if (!Helper::isValidPattern($pattern)) {
- throw $this->keywordException("Each property name from {keyword} must be valid regex", $info);
- }
+ $list = array();
- if (!is_bool($item) && !is_object($item)) {
- throw $this->keywordException("{keyword}[{$pattern}] must be a json schema (object or boolean)", $info);
- }
+ foreach ( $value as $pattern => $item ) {
+ if ( ! Helper::isValidPattern( $pattern ) ) {
+ throw $this->keywordException( 'Each property name from {keyword} must be valid regex', $info );
+ }
- $list[$pattern] = $item;
- }
+ if ( ! is_bool( $item ) && ! is_object( $item ) ) {
+ throw $this->keywordException( "{keyword}[{$pattern}] must be a json schema (object or boolean)", $info );
+ }
- return $list ? new PatternPropertiesKeyword($list) : null;
- }
+ $list[ $pattern ] = $item;
+ }
+
+ return $list ? new PatternPropertiesKeyword( $list ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/PropertiesKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/PropertiesKeywordParser.php
index faa3312b..72597166 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/PropertiesKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/PropertiesKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_OBJECT;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (!is_object($value)) {
- throw $this->keywordException("{keyword} must be an object", $info);
- }
+ $value = $this->keywordValue( $schema );
- $list = [];
+ if ( ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be an object', $info );
+ }
- foreach ($value as $name => $s) {
- if (!is_bool($s) && !is_object($s)) {
- throw $this->keywordException("{keyword}[{$name}] must be a json schema (object or boolean)", $info);
- }
+ $list = array();
- $list[$name] = $s;
- }
+ foreach ( $value as $name => $s ) {
+ if ( ! is_bool( $s ) && ! is_object( $s ) ) {
+ throw $this->keywordException( "{keyword}[{$name}] must be a json schema (object or boolean)", $info );
+ }
- return $list ? new PropertiesKeyword($list) : null;
- }
+ $list[ $name ] = $s;
+ }
+
+ return $list ? new PropertiesKeyword( $list ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/PropertyNamesKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/PropertyNamesKeywordParser.php
index 8e03e387..ce0dd870 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/PropertyNamesKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/PropertyNamesKeywordParser.php
@@ -1,5 +1,6 @@
data();
-
- if (!$this->keywordExists($schema)) {
- return null;
- }
-
- $value = $this->keywordValue($schema);
-
- if (is_bool($value)) {
- if ($value) {
- return null;
- }
- } elseif (!is_object($value)) {
- throw $this->keywordException("{keyword} must be a valid json schema (object or boolean)", $info);
- }
-
- return new PropertyNamesKeyword($value);
- }
+class PropertyNamesKeywordParser extends KeywordParser {
+
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_OBJECT;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
+
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
+
+ $value = $this->keywordValue( $schema );
+
+ if ( is_bool( $value ) ) {
+ if ( $value ) {
+ return null;
+ }
+ } elseif ( ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a valid json schema (object or boolean)', $info );
+ }
+
+ return new PropertyNamesKeyword( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/RefKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/RefKeywordParser.php
index 554ddcfa..ec06cd93 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/RefKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/RefKeywordParser.php
@@ -1,5 +1,6 @@
variations = $variations;
- }
-
- /**
- * @inheritDoc
- */
- public function type(): string
- {
- return self::TYPE_AFTER_REF;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\Info\SchemaInfo $info
- * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
- * @param object $shared
- */
- public function parse($info, $parser, $shared)
- {
- $ref = null;
- $recursive = false;
- $schema = $info->data();
- $variation = null;
-
- if ($this->keywordExists($schema)) {
- $ref = $this->keywordValue($schema);
- if (!is_string($ref) || $ref === '') {
- throw $this->keywordException('{keyword} must be a non-empty string', $info);
- }
- } elseif ($this->variations) {
- foreach ($this->variations as $v) {
- if (!$this->keywordExists($schema, $v['ref'])) {
- continue;
- }
- $ref = $this->keywordValue($schema, $v['ref']);
- if ($v['fragment']) {
- if (!preg_match('/^#[a-z][a-z0-9\\-.:_]*/i', $ref)) {
- $this->keywordException("{keyword} value is malformed", $info, $v['ref']);
- }
- } elseif ($ref !== '#') {
- $this->keywordException("{keyword} supports only '#' as value", $info, $v['ref']);
- }
- $variation = $v;
- $recursive = true;
- break;
- }
- if (!$recursive) {
- return null;
- }
- } else {
- return null;
- }
-
- // Mappers
- $mapper = null;
- if ($parser->option('allowMappers') && property_exists($schema, '$map')) {
- if (!is_object($schema->{'$map'}) && !is_array($schema->{'$map'})) {
- throw $this->keywordException('$map keyword must be an object or an array', $info, '$map');
- }
-
- if (!empty($schema->{'$map'})) {
- $mapper = $this->createVariables($parser, $schema->{'$map'});
- }
- }
-
- // Globals
- $globals = null;
- if ($parser->option('allowGlobals') && property_exists($schema, '$globals')) {
- if (!is_object($schema->{'$globals'})) {
- throw $this->keywordException('$globals keyword must be an object', $info, '$globals');
- }
-
- if (!empty($schema->{'$globals'})) {
- $globals = $this->createVariables($parser, $schema->{'$globals'});
- }
- }
-
- // Pass slots
- $slots = null;
- if ($parser->option('allowSlots') && property_exists($schema, '$inject')) {
- $slots = $this->parseInjectedSlots($info, $parser, '$inject');
- }
-
- if ($recursive) {
- $ref = $info->idBaseRoot()->resolveRef($ref);
- if ($variation['fragment']) {
- return new RecursiveRefKeyword($ref->resolveRef('#'), $mapper, $globals, $slots,
- $variation['ref'], $variation['anchor'], $ref->fragment());
- }
- return new RecursiveRefKeyword($ref, $mapper, $globals, $slots,
- $variation['ref'], $variation['anchor'], true);
- }
-
- if ($ref === '#') {
- return new URIRefKeyword(Uri::merge('#', $info->idBaseRoot()), $mapper, $globals, $slots, $this->keyword);
- }
-
- if ($parser->option('allowTemplates') && UriTemplate::isTemplate($ref)) {
- $tpl = new UriTemplate($ref);
-
- if ($tpl->hasPlaceholders()) {
- $vars = null;
-
- if (property_exists($schema, '$vars')) {
- if (!is_object($schema->{'$vars'})) {
- throw $this->keywordException('$vars keyword must be an object', $info, '$vars');
- }
-
- if (!empty($schema->{'$vars'})) {
- $vars = $this->createVariables($parser, $schema->{'$vars'});
- }
- }
-
- return new TemplateRefKeyword(
- $tpl, $vars, $mapper,
- $globals, $slots, $this->keyword,
- $parser->option('allowRelativeJsonPointerInRef')
- );
- }
-
- unset($tpl);
- }
-
- if ($ref[0] === '#') {
- if (($pointer = JsonPointer::parse(substr($ref, 1))) && $pointer->isAbsolute()) {
- return new PointerRefKeyword($pointer, $mapper, $globals, $slots, $this->keyword);
- }
- } elseif ($parser->option('allowRelativeJsonPointerInRef') &&
- ($pointer = JsonPointer::parse($ref)) && $pointer->isRelative()) {
- return new PointerRefKeyword($pointer, $mapper, $globals, $slots, $this->keyword);
- }
-
- $ref = Uri::merge($ref, $info->idBaseRoot(), true);
-
- if ($ref === null || !$ref->isAbsolute()) {
- throw $this->keywordException('{keyword} must be a valid uri, uri-reference, uri-template or json-pointer',
- $info);
- }
-
- return new URIRefKeyword($ref, $mapper, $globals, $slots, $this->keyword);
- }
-
- /**
- * @param SchemaInfo $info
- * @param SchemaParser $parser
- * @param string $keyword
- * @return string[]|object[]|Schema[]
- */
- protected function parseInjectedSlots($info, $parser, $keyword)
- {
- $schema = $info->data();
-
- if (!is_object($schema->{$keyword})) {
- throw $this->keywordException('{keyword} keyword value must be an object', $info, $keyword);
- }
-
- return $this->getSlotSchemas($info, $parser, $schema->{$keyword}, [$keyword]);
- }
-
- /**
- * @param SchemaInfo $info
- * @param SchemaParser $parser
- * @param object $slots
- * @param array $path
- * @return null
- */
- protected function getSlotSchemas($info, $parser, $slots, $path)
- {
- $keyword = null;
- if ($path) {
- $keyword = end($path);
- $path = array_merge($info->path(), $path);
- } else {
- $path = $info->path();
- }
-
- $list = [];
-
- foreach ($slots as $name => $value) {
- if ($value === null) {
- continue;
- }
- if (is_string($value) || is_object($value)) {
- $list[$name] = $value;
- } elseif (is_bool($value)) {
- $list[$name] = $parser->parseSchema(new SchemaInfo(
- $value, null, $info->id() ?? $info->base(), $info->root(),
- array_merge($path, [$name]),
- $info->draft() ?? $parser->defaultDraftVersion()
- ));
- } else {
- throw $this->keywordException('Slots must contain valid json schemas or slot names', $info, $keyword);
- }
- }
-
- return $list ?: null;
- }
+class RefKeywordParser extends KeywordParser {
+
+ use VariablesTrait;
+
+ /**
+ * @var mixed[]|null
+ */
+ protected $variations;
+
+ public function __construct( string $keyword, $variations = null ) {
+ parent::__construct( $keyword );
+ $this->variations = $variations;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_AFTER_REF;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $ref = null;
+ $recursive = false;
+ $schema = $info->data();
+ $variation = null;
+
+ if ( $this->keywordExists( $schema ) ) {
+ $ref = $this->keywordValue( $schema );
+ if ( ! is_string( $ref ) || $ref === '' ) {
+ throw $this->keywordException( '{keyword} must be a non-empty string', $info );
+ }
+ } elseif ( $this->variations ) {
+ foreach ( $this->variations as $v ) {
+ if ( ! $this->keywordExists( $schema, $v['ref'] ) ) {
+ continue;
+ }
+ $ref = $this->keywordValue( $schema, $v['ref'] );
+ if ( $v['fragment'] ) {
+ if ( ! preg_match( '/^#[a-z][a-z0-9\\-.:_]*/i', $ref ) ) {
+ $this->keywordException( '{keyword} value is malformed', $info, $v['ref'] );
+ }
+ } elseif ( $ref !== '#' ) {
+ $this->keywordException( "{keyword} supports only '#' as value", $info, $v['ref'] );
+ }
+ $variation = $v;
+ $recursive = true;
+ break;
+ }
+ if ( ! $recursive ) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+
+ // Mappers
+ $mapper = null;
+ if ( $parser->option( 'allowMappers' ) && property_exists( $schema, '$map' ) ) {
+ if ( ! is_object( $schema->{'$map'} ) && ! is_array( $schema->{'$map'} ) ) {
+ throw $this->keywordException( '$map keyword must be an object or an array', $info, '$map' );
+ }
+
+ if ( ! empty( $schema->{'$map'} ) ) {
+ $mapper = $this->createVariables( $parser, $schema->{'$map'} );
+ }
+ }
+
+ // Globals
+ $globals = null;
+ if ( $parser->option( 'allowGlobals' ) && property_exists( $schema, '$globals' ) ) {
+ if ( ! is_object( $schema->{'$globals'} ) ) {
+ throw $this->keywordException( '$globals keyword must be an object', $info, '$globals' );
+ }
+
+ if ( ! empty( $schema->{'$globals'} ) ) {
+ $globals = $this->createVariables( $parser, $schema->{'$globals'} );
+ }
+ }
+
+ // Pass slots
+ $slots = null;
+ if ( $parser->option( 'allowSlots' ) && property_exists( $schema, '$inject' ) ) {
+ $slots = $this->parseInjectedSlots( $info, $parser, '$inject' );
+ }
+
+ if ( $recursive ) {
+ $ref = $info->idBaseRoot()->resolveRef( $ref );
+ if ( $variation['fragment'] ) {
+ return new RecursiveRefKeyword(
+ $ref->resolveRef( '#' ),
+ $mapper,
+ $globals,
+ $slots,
+ $variation['ref'],
+ $variation['anchor'],
+ $ref->fragment()
+ );
+ }
+ return new RecursiveRefKeyword(
+ $ref,
+ $mapper,
+ $globals,
+ $slots,
+ $variation['ref'],
+ $variation['anchor'],
+ true
+ );
+ }
+
+ if ( $ref === '#' ) {
+ return new URIRefKeyword( Uri::merge( '#', $info->idBaseRoot() ), $mapper, $globals, $slots, $this->keyword );
+ }
+
+ if ( $parser->option( 'allowTemplates' ) && UriTemplate::isTemplate( $ref ) ) {
+ $tpl = new UriTemplate( $ref );
+
+ if ( $tpl->hasPlaceholders() ) {
+ $vars = null;
+
+ if ( property_exists( $schema, '$vars' ) ) {
+ if ( ! is_object( $schema->{'$vars'} ) ) {
+ throw $this->keywordException( '$vars keyword must be an object', $info, '$vars' );
+ }
+
+ if ( ! empty( $schema->{'$vars'} ) ) {
+ $vars = $this->createVariables( $parser, $schema->{'$vars'} );
+ }
+ }
+
+ return new TemplateRefKeyword(
+ $tpl,
+ $vars,
+ $mapper,
+ $globals,
+ $slots,
+ $this->keyword,
+ $parser->option( 'allowRelativeJsonPointerInRef' )
+ );
+ }
+
+ unset( $tpl );
+ }
+
+ if ( $ref[0] === '#' ) {
+ if ( ( $pointer = JsonPointer::parse( substr( $ref, 1 ) ) ) && $pointer->isAbsolute() ) {
+ return new PointerRefKeyword( $pointer, $mapper, $globals, $slots, $this->keyword );
+ }
+ } elseif ( $parser->option( 'allowRelativeJsonPointerInRef' ) &&
+ ( $pointer = JsonPointer::parse( $ref ) ) && $pointer->isRelative() ) {
+ return new PointerRefKeyword( $pointer, $mapper, $globals, $slots, $this->keyword );
+ }
+
+ $ref = Uri::merge( $ref, $info->idBaseRoot(), true );
+
+ if ( $ref === null || ! $ref->isAbsolute() ) {
+ throw $this->keywordException(
+ '{keyword} must be a valid uri, uri-reference, uri-template or json-pointer',
+ $info
+ );
+ }
+
+ return new URIRefKeyword( $ref, $mapper, $globals, $slots, $this->keyword );
+ }
+
+ /**
+ * @param SchemaInfo $info
+ * @param SchemaParser $parser
+ * @param string $keyword
+ * @return string[]|object[]|Schema[]
+ */
+ protected function parseInjectedSlots( $info, $parser, $keyword ) {
+ $schema = $info->data();
+
+ if ( ! is_object( $schema->{$keyword} ) ) {
+ throw $this->keywordException( '{keyword} keyword value must be an object', $info, $keyword );
+ }
+
+ return $this->getSlotSchemas( $info, $parser, $schema->{$keyword}, array( $keyword ) );
+ }
+
+ /**
+ * @param SchemaInfo $info
+ * @param SchemaParser $parser
+ * @param object $slots
+ * @param array $path
+ * @return null
+ */
+ protected function getSlotSchemas( $info, $parser, $slots, $path ) {
+ $keyword = null;
+ if ( $path ) {
+ $keyword = end( $path );
+ $path = array_merge( $info->path(), $path );
+ } else {
+ $path = $info->path();
+ }
+
+ $list = array();
+
+ foreach ( $slots as $name => $value ) {
+ if ( $value === null ) {
+ continue;
+ }
+ if ( is_string( $value ) || is_object( $value ) ) {
+ $list[ $name ] = $value;
+ } elseif ( is_bool( $value ) ) {
+ $list[ $name ] = $parser->parseSchema(
+ new SchemaInfo(
+ $value,
+ null,
+ $info->id() ?? $info->base(),
+ $info->root(),
+ array_merge( $path, array( $name ) ),
+ $info->draft() ?? $parser->defaultDraftVersion()
+ )
+ );
+ } else {
+ throw $this->keywordException( 'Slots must contain valid json schemas or slot names', $info, $keyword );
+ }
+ }
+
+ return $list ?: null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/RequiredKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/RequiredKeywordParser.php
index b723877f..1cf40588 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/RequiredKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/RequiredKeywordParser.php
@@ -1,5 +1,6 @@
data();
-
- if (!$this->keywordExists($schema)) {
- return null;
- }
-
- $value = $this->keywordValue($schema);
-
- $filter = $this->propertiesFilter($parser, $schema);
-
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new RequiredDataKeyword($pointer, $filter);
- }
- }
-
- if (!is_array($value)) {
- throw $this->keywordException("{keyword} must be an array of strings", $info);
- }
-
- foreach ($value as $name) {
- if (!is_string($name)) {
- throw $this->keywordException("{keyword} must be an array of strings", $info);
- }
- }
-
- if ($filter) {
- $value = array_filter($value, $filter === null ? function ($value, $key) : bool {
- return !empty($value);
- } : $filter, $filter === null ? ARRAY_FILTER_USE_BOTH : 0);
- }
-
- return $value ? new RequiredKeyword(array_unique($value)) : null;
- }
-
- /**
- * @param SchemaParser $parser
- * @param object $schema
- * @return callable|null
- */
- protected function propertiesFilter($parser, $schema)
- {
- if (!$parser->option('allowDefaults')) {
- return null;
- }
-
- if (!property_exists($schema, 'properties') || !is_object($schema->properties)) {
- return null;
- }
-
- $props = $schema->properties;
-
- return static function (string $name) use ($props) {
- if (!property_exists($props, $name)) {
- return true;
- }
-
- if (is_object($props->{$name}) && property_exists($props->{$name}, 'default')) {
- return false;
- }
-
- return true;
- };
- }
+class RequiredKeywordParser extends KeywordParser {
+
+ use DataKeywordTrait;
+
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_OBJECT;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
+
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
+
+ $value = $this->keywordValue( $schema );
+
+ $filter = $this->propertiesFilter( $parser, $schema );
+
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new RequiredDataKeyword( $pointer, $filter );
+ }
+ }
+
+ if ( ! is_array( $value ) ) {
+ throw $this->keywordException( '{keyword} must be an array of strings', $info );
+ }
+
+ foreach ( $value as $name ) {
+ if ( ! is_string( $name ) ) {
+ throw $this->keywordException( '{keyword} must be an array of strings', $info );
+ }
+ }
+
+ if ( $filter ) {
+ $value = array_filter(
+ $value,
+ $filter === null ? function ( $value, $key ): bool {
+ return ! empty( $value );
+ } : $filter,
+ $filter === null ? ARRAY_FILTER_USE_BOTH : 0
+ );
+ }
+
+ return $value ? new RequiredKeyword( array_unique( $value ) ) : null;
+ }
+
+ /**
+ * @param SchemaParser $parser
+ * @param object $schema
+ * @return callable|null
+ */
+ protected function propertiesFilter( $parser, $schema ) {
+ if ( ! $parser->option( 'allowDefaults' ) ) {
+ return null;
+ }
+
+ if ( ! property_exists( $schema, 'properties' ) || ! is_object( $schema->properties ) ) {
+ return null;
+ }
+
+ $props = $schema->properties;
+
+ return static function ( string $name ) use ( $props ) {
+ if ( ! property_exists( $props, $name ) ) {
+ return true;
+ }
+
+ if ( is_object( $props->{$name} ) && property_exists( $props->{$name}, 'default' ) ) {
+ return false;
+ }
+
+ return true;
+ };
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/SlotsKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/SlotsKeywordParser.php
index 609e750d..7ee46334 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/SlotsKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/SlotsKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_APPEND;
+ }
- if (!$parser->option('allowSlots') || !$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $parser->option( 'allowSlots' ) || ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (!is_object($value)) {
- throw $this->keywordException('{keyword} keyword value must be an object', $info);
- }
+ $value = $this->keywordValue( $schema );
- $slots = [];
- foreach ($value as $name => $fallback) {
- if (!is_string($name) || $name === '') {
- continue;
- }
- if (is_bool($fallback) || is_string($fallback) || is_object($fallback)) {
- $slots[$name] = $fallback;
- }
- }
+ if ( ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} keyword value must be an object', $info );
+ }
- return $slots ? new SlotsKeyword($slots) : null;
- }
+ $slots = array();
+ foreach ( $value as $name => $fallback ) {
+ if ( ! is_string( $name ) || $name === '' ) {
+ continue;
+ }
+ if ( is_bool( $fallback ) || is_string( $fallback ) || is_object( $fallback ) ) {
+ $slots[ $name ] = $fallback;
+ }
+ }
+
+ return $slots ? new SlotsKeyword( $slots ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/TypeKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/TypeKeywordParser.php
index 8aa9d79b..ffb9b563 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/TypeKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/TypeKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_BEFORE;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $type = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if (is_string($type)) {
- $type = [$type];
- } elseif (!is_array($type)) {
- throw $this->keywordException('{keyword} can only be a string or an array of string', $info);
- }
+ $type = $this->keywordValue( $schema );
- foreach ($type as $t) {
- if (!Helper::isValidJsonType($t)) {
- throw $this->keywordException("{keyword} contains invalid json type: {$t}", $info);
- }
- }
+ if ( is_string( $type ) ) {
+ $type = array( $type );
+ } elseif ( ! is_array( $type ) ) {
+ throw $this->keywordException( '{keyword} can only be a string or an array of string', $info );
+ }
- $type = array_unique($type);
+ foreach ( $type as $t ) {
+ if ( ! Helper::isValidJsonType( $t ) ) {
+ throw $this->keywordException( "{keyword} contains invalid json type: {$t}", $info );
+ }
+ }
- if (!isset($shared->types)) {
- $shared->types = $type;
- } else {
- $shared->types = array_unique(array_merge($shared->types, $type));
- }
+ $type = array_unique( $type );
- $count = count($type);
+ if ( ! isset( $shared->types ) ) {
+ $shared->types = $type;
+ } else {
+ $shared->types = array_unique( array_merge( $shared->types, $type ) );
+ }
- if ($count === 0) {
- throw $this->keywordException("{keyword} cannot be an empty array", $info);
- } elseif ($count === 1) {
- $type = reset($type);
- }
+ $count = count( $type );
- return new TypeKeyword($type);
- }
+ if ( $count === 0 ) {
+ throw $this->keywordException( '{keyword} cannot be an empty array', $info );
+ } elseif ( $count === 1 ) {
+ $type = reset( $type );
+ }
+
+ return new TypeKeyword( $type );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/UnevaluatedItemsKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/UnevaluatedItemsKeywordParser.php
index ff88103e..a71f140e 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/UnevaluatedItemsKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/UnevaluatedItemsKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_AFTER_REF;
+ }
- if (!$this->keywordExists($schema) || !$parser->option('allowUnevaluated')) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
-// if (!$this->makesSense($schema)) {
-// return null;
-// }
+ if ( ! $this->keywordExists( $schema ) || ! $parser->option( 'allowUnevaluated' ) ) {
+ return null;
+ }
- $value = $this->keywordValue($schema);
+ // if (!$this->makesSense($schema)) {
+ // return null;
+ // }
- if (!is_bool($value) && !is_object($value)) {
- throw $this->keywordException("{keyword} must be a json schema (object or boolean)", $info);
- }
+ $value = $this->keywordValue( $schema );
- return new UnevaluatedItemsKeyword($value);
- }
+ if ( ! is_bool( $value ) && ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a json schema (object or boolean)', $info );
+ }
- /**
- * @param object $schema
- */
- protected function makesSense($schema): bool
- {
- if (property_exists($schema, 'additionalItems')) {
- return false;
- }
-// if (property_exists($schema, 'contains')) {
-// return false;
-// }
- if (property_exists($schema, 'items') && !is_array($schema->items)) {
- return false;
- }
+ return new UnevaluatedItemsKeyword( $value );
+ }
- return true;
- }
+ /**
+ * @param object $schema
+ */
+ protected function makesSense( $schema ): bool {
+ if ( property_exists( $schema, 'additionalItems' ) ) {
+ return false;
+ }
+ // if (property_exists($schema, 'contains')) {
+ // return false;
+ // }
+ if ( property_exists( $schema, 'items' ) && ! is_array( $schema->items ) ) {
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/UnevaluatedPropertiesKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/UnevaluatedPropertiesKeywordParser.php
index 953088bb..7fb0d7f2 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/UnevaluatedPropertiesKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/UnevaluatedPropertiesKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- if (!$this->keywordExists($schema) || !$parser->option('allowUnevaluated')) {
- return null;
- }
+ if ( ! $this->keywordExists( $schema ) || ! $parser->option( 'allowUnevaluated' ) ) {
+ return null;
+ }
-// if (!$this->makesSense($schema)) {
-// return null;
-// }
+ // if (!$this->makesSense($schema)) {
+ // return null;
+ // }
- $value = $this->keywordValue($schema);
+ $value = $this->keywordValue( $schema );
- if (!is_bool($value) && !is_object($value)) {
- throw $this->keywordException("{keyword} must be a json schema (object or boolean)", $info);
- }
+ if ( ! is_bool( $value ) && ! is_object( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a json schema (object or boolean)', $info );
+ }
- return new UnevaluatedPropertiesKeyword($value);
- }
+ return new UnevaluatedPropertiesKeyword( $value );
+ }
- /**
- * @param object $schema
- */
- protected function makesSense($schema): bool
- {
- if (property_exists($schema, 'additionalProperties')) {
- return false;
- }
+ /**
+ * @param object $schema
+ */
+ protected function makesSense( $schema ): bool {
+ if ( property_exists( $schema, 'additionalProperties' ) ) {
+ return false;
+ }
- return true;
- }
+ return true;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Keywords/UniqueItemsKeywordParser.php b/src/opis/json-schema/src/Parsers/Keywords/UniqueItemsKeywordParser.php
index 12bbcfbe..e2dbf527 100644
--- a/src/opis/json-schema/src/Parsers/Keywords/UniqueItemsKeywordParser.php
+++ b/src/opis/json-schema/src/Parsers/Keywords/UniqueItemsKeywordParser.php
@@ -1,5 +1,6 @@
data();
+ /**
+ * @inheritDoc
+ */
+ public function type(): string {
+ return self::TYPE_ARRAY;
+ }
- if (!$this->keywordExists($schema)) {
- return null;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ $schema = $info->data();
- $value = $this->keywordValue($schema);
+ if ( ! $this->keywordExists( $schema ) ) {
+ return null;
+ }
- if ($this->isDataKeywordAllowed($parser, $this->keyword)) {
- if ($pointer = $this->getDataKeywordPointer($value)) {
- return new UniqueItemsDataKeyword($pointer);
- }
- }
+ $value = $this->keywordValue( $schema );
- if (!is_bool($value)) {
- throw $this->keywordException("{keyword} must be a boolean", $info);
- }
+ if ( $this->isDataKeywordAllowed( $parser, $this->keyword ) ) {
+ if ( $pointer = $this->getDataKeywordPointer( $value ) ) {
+ return new UniqueItemsDataKeyword( $pointer );
+ }
+ }
- return $value ? new UniqueItemsKeyword() : null;
- }
+ if ( ! is_bool( $value ) ) {
+ throw $this->keywordException( '{keyword} must be a boolean', $info );
+ }
+
+ return $value ? new UniqueItemsKeyword() : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/PragmaParser.php b/src/opis/json-schema/src/Parsers/PragmaParser.php
index 1f6a7c72..183b52e0 100644
--- a/src/opis/json-schema/src/Parsers/PragmaParser.php
+++ b/src/opis/json-schema/src/Parsers/PragmaParser.php
@@ -1,5 +1,6 @@
pragma = $pragma;
- }
+ /**
+ * @var string
+ */
+ protected $pragma;
- /**
- * @param SchemaInfo $info
- * @param SchemaParser $parser
- * @param object $shared
- * @return Pragma|null
- */
- abstract public function parse($info, $parser, $shared);
+ /**
+ * @param string $pragma
+ */
+ public function __construct( string $pragma ) {
+ $this->pragma = $pragma;
+ }
- /**
- * @param object|SchemaInfo $schema
- * @param string|null $pragma
- * @return bool
- */
- protected function pragmaExists($schema, $pragma = null): bool
- {
- if ($schema instanceof SchemaInfo) {
- $schema = $schema->isObject() ? $schema->data() : null;
- }
+ /**
+ * @param SchemaInfo $info
+ * @param SchemaParser $parser
+ * @param object $shared
+ * @return Pragma|null
+ */
+ abstract public function parse( $info, $parser, $shared );
- return is_object($schema) && property_exists($schema, $pragma ?? $this->pragma);
- }
+ /**
+ * @param object|SchemaInfo $schema
+ * @param string|null $pragma
+ * @return bool
+ */
+ protected function pragmaExists( $schema, $pragma = null ): bool {
+ if ( $schema instanceof SchemaInfo ) {
+ $schema = $schema->isObject() ? $schema->data() : null;
+ }
- /**
- * @param object|SchemaInfo $schema
- * @param string|null $pragma
- * @return mixed
- */
- protected function pragmaValue($schema, $pragma = null)
- {
- if ($schema instanceof SchemaInfo) {
- $schema = $schema->isObject() ? $schema->data() : null;
- }
+ return is_object( $schema ) && property_exists( $schema, $pragma ?? $this->pragma );
+ }
- return is_object($schema) ? $schema->{$pragma ?? $this->pragma} : null;
- }
+ /**
+ * @param object|SchemaInfo $schema
+ * @param string|null $pragma
+ * @return mixed
+ */
+ protected function pragmaValue( $schema, $pragma = null ) {
+ if ( $schema instanceof SchemaInfo ) {
+ $schema = $schema->isObject() ? $schema->data() : null;
+ }
- /**
- * @param string $message
- * @param SchemaInfo $info
- * @param string|null $pragma
- * @return InvalidPragmaException
- */
- protected function pragmaException($message, $info, $pragma = null): InvalidPragmaException
- {
- $pragma = $pragma ?? $this->pragma;
+ return is_object( $schema ) ? $schema->{$pragma ?? $this->pragma} : null;
+ }
- return new InvalidPragmaException(str_replace('{pragma}', $pragma, $message), $pragma, $info);
- }
+ /**
+ * @param string $message
+ * @param SchemaInfo $info
+ * @param string|null $pragma
+ * @return InvalidPragmaException
+ */
+ protected function pragmaException( $message, $info, $pragma = null ): InvalidPragmaException {
+ $pragma = $pragma ?? $this->pragma;
+
+ return new InvalidPragmaException( str_replace( '{pragma}', $pragma, $message ), $pragma, $info );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Pragmas/CastPragmaParser.php b/src/opis/json-schema/src/Parsers/Pragmas/CastPragmaParser.php
index b382520f..e9e2620e 100644
--- a/src/opis/json-schema/src/Parsers/Pragmas/CastPragmaParser.php
+++ b/src/opis/json-schema/src/Parsers/Pragmas/CastPragmaParser.php
@@ -1,5 +1,6 @@
pragmaExists($info)) {
- return null;
- }
+class CastPragmaParser extends PragmaParser {
- $value = $this->pragmaValue($info);
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ if ( ! $this->pragmaExists( $info ) ) {
+ return null;
+ }
- if (!is_string($value) || !Helper::isValidJsonType($value)) {
- throw $this->pragmaException('Pragma {pragma} must contain a valid json type name', $info);
- }
+ $value = $this->pragmaValue( $info );
- return new CastPragma($value);
- }
+ if ( ! is_string( $value ) || ! Helper::isValidJsonType( $value ) ) {
+ throw $this->pragmaException( 'Pragma {pragma} must contain a valid json type name', $info );
+ }
+
+ return new CastPragma( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Pragmas/GlobalsPragmaParser.php b/src/opis/json-schema/src/Parsers/Pragmas/GlobalsPragmaParser.php
index 4bb99d65..b4aab506 100644
--- a/src/opis/json-schema/src/Parsers/Pragmas/GlobalsPragmaParser.php
+++ b/src/opis/json-schema/src/Parsers/Pragmas/GlobalsPragmaParser.php
@@ -1,5 +1,6 @@
option('allowGlobals') || !$this->pragmaExists($info)) {
- return null;
- }
+ use VariablesTrait;
- $value = $this->pragmaValue($info);
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ if ( ! $parser->option( 'allowGlobals' ) || ! $this->pragmaExists( $info ) ) {
+ return null;
+ }
- if (!is_object($value)) {
- throw $this->pragmaException('Pragma {pragma} must be an object', $info);
- }
+ $value = $this->pragmaValue( $info );
- $value = get_object_vars($value);
+ if ( ! is_object( $value ) ) {
+ throw $this->pragmaException( 'Pragma {pragma} must be an object', $info );
+ }
- return $value ? new GlobalsPragma($this->createVariables($parser, $value)) : null;
- }
+ $value = get_object_vars( $value );
+
+ return $value ? new GlobalsPragma( $this->createVariables( $parser, $value ) ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Pragmas/MaxErrorsPragmaParser.php b/src/opis/json-schema/src/Parsers/Pragmas/MaxErrorsPragmaParser.php
index dcff09e5..a58113f3 100644
--- a/src/opis/json-schema/src/Parsers/Pragmas/MaxErrorsPragmaParser.php
+++ b/src/opis/json-schema/src/Parsers/Pragmas/MaxErrorsPragmaParser.php
@@ -1,5 +1,6 @@
pragmaExists($info)) {
- return null;
- }
+class MaxErrorsPragmaParser extends PragmaParser {
- $value = $this->pragmaValue($info);
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ if ( ! $this->pragmaExists( $info ) ) {
+ return null;
+ }
- if (!is_int($value)) {
- throw $this->pragmaException('Pragma {pragma} must be an integer', $info);
- }
+ $value = $this->pragmaValue( $info );
- return new MaxErrorsPragma($value);
- }
+ if ( ! is_int( $value ) ) {
+ throw $this->pragmaException( 'Pragma {pragma} must be an integer', $info );
+ }
+
+ return new MaxErrorsPragma( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/Pragmas/SlotsPragmaParser.php b/src/opis/json-schema/src/Parsers/Pragmas/SlotsPragmaParser.php
index 4bd68cfe..0ddd4806 100644
--- a/src/opis/json-schema/src/Parsers/Pragmas/SlotsPragmaParser.php
+++ b/src/opis/json-schema/src/Parsers/Pragmas/SlotsPragmaParser.php
@@ -1,5 +1,6 @@
option('allowSlots') || !$this->pragmaExists($info)) {
- return null;
- }
+class SlotsPragmaParser extends PragmaParser {
- $value = $this->pragmaValue($info);
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\Info\SchemaInfo $info
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ * @param object $shared
+ */
+ public function parse( $info, $parser, $shared ) {
+ if ( ! $parser->option( 'allowSlots' ) || ! $this->pragmaExists( $info ) ) {
+ return null;
+ }
- if (!is_object($value)) {
- throw $this->pragmaException('Pragma {pragma} must be an object', $info);
- }
+ $value = $this->pragmaValue( $info );
- $list = [];
+ if ( ! is_object( $value ) ) {
+ throw $this->pragmaException( 'Pragma {pragma} must be an object', $info );
+ }
- foreach ($value as $name => $slot) {
- if ($slot === null) {
- continue;
- }
+ $list = array();
- if (is_bool($slot)) {
+ foreach ( $value as $name => $slot ) {
+ if ( $slot === null ) {
+ continue;
+ }
- $list[$name] = $parser->parseSchema(new SchemaInfo(
- $slot, null, $info->base(), $info->root(),
- array_merge($info->path(), [$this->pragma, $name]),
- $info->draft() ?? $parser->defaultDraftVersion()
- ));
- } elseif (is_string($slot) || is_object($slot)) {
- $list[$name] = $slot;
- } else {
- throw $this->pragmaException('Pragma {pragma} contains invalid value for slot ' . $name, $info);
- }
- }
+ if ( is_bool( $slot ) ) {
- return $list ? new SlotsPragma($list) : null;
- }
+ $list[ $name ] = $parser->parseSchema(
+ new SchemaInfo(
+ $slot,
+ null,
+ $info->base(),
+ $info->root(),
+ array_merge( $info->path(), array( $this->pragma, $name ) ),
+ $info->draft() ?? $parser->defaultDraftVersion()
+ )
+ );
+ } elseif ( is_string( $slot ) || is_object( $slot ) ) {
+ $list[ $name ] = $slot;
+ } else {
+ throw $this->pragmaException( 'Pragma {pragma} contains invalid value for slot ' . $name, $info );
+ }
+ }
+
+ return $list ? new SlotsPragma( $list ) : null;
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/ResolverTrait.php b/src/opis/json-schema/src/Parsers/ResolverTrait.php
index a4916fda..705715c7 100644
--- a/src/opis/json-schema/src/Parsers/ResolverTrait.php
+++ b/src/opis/json-schema/src/Parsers/ResolverTrait.php
@@ -1,5 +1,6 @@
$super) {
- if (!isset($list[$sub]) && isset($list[$super])) {
- $list[$sub] = $list[$super];
- }
- }
+trait ResolverTrait {
- return $list;
- }
-}
\ No newline at end of file
+ /**
+ * @param array $list
+ * @return array
+ */
+ protected function resolveSubTypes( $list ): array {
+ foreach ( Helper::JSON_SUBTYPES as $sub => $super ) {
+ if ( ! isset( $list[ $sub ] ) && isset( $list[ $super ] ) ) {
+ $list[ $sub ] = $list[ $super ];
+ }
+ }
+
+ return $list;
+ }
+}
diff --git a/src/opis/json-schema/src/Parsers/SchemaParser.php b/src/opis/json-schema/src/Parsers/SchemaParser.php
index 2678c622..1744c098 100644
--- a/src/opis/json-schema/src/Parsers/SchemaParser.php
+++ b/src/opis/json-schema/src/Parsers/SchemaParser.php
@@ -1,5 +1,6 @@
true,
- 'allowFormats' => true,
- 'allowMappers' => true,
- 'allowTemplates' => true,
- 'allowGlobals' => true,
- 'allowDefaults' => true,
- 'allowSlots' => true,
- 'allowKeywordValidators' => true,
- 'allowPragmas' => true,
-
- 'allowDataKeyword' => true,
- 'allowKeywordsAlongsideRef' => false,
- 'allowUnevaluated' => true,
- 'allowRelativeJsonPointerInRef' => true,
- 'allowExclusiveMinMaxAsBool' => true,
-
- 'keepDependenciesKeyword' => true,
- 'keepAdditionalItemsKeyword' => true,
-
- 'decodeContent' => ['06', '07'],
- 'defaultDraft' => self::DEFAULT_DRAFT,
-
- 'varRefKey' => '$ref',
- 'varEachKey' => '$each',
- 'varDefaultKey' => 'default',
- ];
-
- /** @var array */
- protected $options;
-
- /** @var Draft[] */
- protected $drafts;
-
- /** @var array */
- protected $resolvers;
-
- /**
- * @param array $resolvers
- * @param array $options
- * @param Vocabulary|null $extraVocabulary
- */
- public function __construct(
- array $resolvers = [],
- array $options = [],
- $extraVocabulary = null
- )
- {
- if ($options) {
- $this->options = $options + self::DEFAULT_OPTIONS;
- } else {
- $this->options = self::DEFAULT_OPTIONS;
- }
-
- $this->resolvers = $this->getResolvers($resolvers);
-
- $this->drafts = $this->getDrafts($extraVocabulary ?? new DefaultVocabulary());
- }
-
- /**
- * @param Vocabulary|null $extraVocabulary
- * @return array
- */
- protected function getDrafts($extraVocabulary): array
- {
- return [
- '06' => new Draft06($extraVocabulary),
- '07' => new Draft07($extraVocabulary),
- '2019-09' => new Draft201909($extraVocabulary),
- '2020-12' => new Draft202012($extraVocabulary),
- ];
- }
-
- /**
- * @param array $resolvers
- * @return array
- */
- protected function getResolvers($resolvers): array
- {
- if (!array_key_exists('format', $resolvers)) {
- $resolvers['format'] = new FormatResolver();
- }
-
- if (!array_key_exists('contentEncoding', $resolvers)) {
- $resolvers['contentEncoding'] = new ContentEncodingResolver();
- }
-
- if (!array_key_exists('contentMediaType', $resolvers)) {
- $resolvers['contentMediaType'] = new ContentMediaTypeResolver();
- }
-
- if (!array_key_exists('$filters', $resolvers)) {
- $resolvers['$filters'] = new FilterResolver();
- }
-
- return $resolvers;
- }
-
- /**
- * @param string $name
- * @param null $default
- * @return mixed|null
- */
- public function option($name, $default = null)
- {
- return $this->options[$name] ?? $default;
- }
-
- /**
- * @param string $name
- * @param $value
- * @return $this
- */
- public function setOption($name, $value): self
- {
- $this->options[$name] = $value;
-
- return $this;
- }
-
- /**
- * @return array
- */
- public function getOptions(): array
- {
- return $this->options;
- }
-
- /**
- * @param string $name
- * @param $resolver
- * @return $this
- */
- public function setResolver($name, $resolver): self
- {
- $this->resolvers[$name] = $resolver;
-
- return $this;
- }
-
- /**
- * @return null|FilterResolver
- */
- public function getFilterResolver()
- {
- return $this->getResolver('$filters');
- }
-
- /**
- * @param null|FilterResolver $resolver
- * @return $this
- */
- public function setFilterResolver($resolver): self
- {
- return $this->setResolver('$filters', $resolver);
- }
-
- /**
- * @return null|FormatResolver
- */
- public function getFormatResolver()
- {
- return $this->getResolver('format');
- }
-
- /**
- * @param FormatResolver|null $resolver
- * @return $this
- */
- public function setFormatResolver($resolver): self
- {
- return $this->setResolver('format', $resolver);
- }
-
- /**
- * @return null|ContentEncodingResolver
- */
- public function getContentEncodingResolver()
- {
- return $this->getResolver('contentEncoding');
- }
-
- /**
- * @param ContentEncodingResolver|null $resolver
- * @return $this
- */
- public function setContentEncodingResolver($resolver): self
- {
- return $this->setResolver('contentEncoding', $resolver);
- }
-
- /**
- * @return null|ContentMediaTypeResolver
- */
- public function getMediaTypeResolver()
- {
- return $this->getResolver('contentMediaType');
- }
-
- /**
- * @param ContentMediaTypeResolver|null $resolver
- * @return $this
- */
- public function setMediaTypeResolver($resolver): self
- {
- return $this->setResolver('contentMediaType', $resolver);
- }
-
- /**
- * @return string
- */
- public function defaultDraftVersion(): string
- {
- return $this->option('defaultDraft', self::DEFAULT_DRAFT);
- }
-
- /**
- * @param string $draft
- * @return $this
- */
- public function setDefaultDraftVersion($draft): self
- {
- return $this->setOption('defaultDraft', $draft);
- }
-
- /**
- * @param string $schema
- * @return string|null
- */
- public function parseDraftVersion($schema)
- {
- if (!preg_match(self::DRAFT_REGEX, $schema, $m)) {
- return null;
- }
-
- return $m[1] ?? null;
- }
-
- /**
- * @param object $schema
- * @return string|null
- */
- public function parseId($schema)
- {
- if (property_exists($schema, '$id') && is_string($schema->{'$id'})) {
- return $schema->{'$id'};
- }
-
- return null;
- }
-
- /**
- * @param object $schema
- * @param string $draft
- * @return string|null
- */
- public function parseAnchor($schema, $draft)
- {
- if (!property_exists($schema, '$anchor') ||
- !isset($this->drafts[$draft]) ||
- !$this->drafts[$draft]->supportsAnchorId()) {
- return null;
- }
-
- $anchor = $schema->{'$anchor'};
-
- if (!is_string($anchor) || !preg_match(self::ANCHOR_REGEX, $anchor)) {
- return null;
- }
-
- return $anchor;
- }
-
- /**
- * @param object $schema
- * @return string|null
- */
- public function parseSchemaDraft($schema)
- {
- if (!property_exists($schema, '$schema') || !is_string($schema->{'$schema'})) {
- return null;
- }
-
- return $this->parseDraftVersion($schema->{'$schema'});
- }
-
- /**
- * @param object $schema
- * @param Uri $id
- * @param callable $handle_id
- * @param callable $handle_object
- * @param string|null $draft
- * @return Schema|null
- */
- public function parseRootSchema(
- $schema,
- $id,
- $handle_id,
- $handle_object,
- $draft = null
- )
- {
- $existent = false;
- if (property_exists($schema, '$id')) {
- $existent = true;
- $id = Uri::parse($schema->{'$id'}, true);
- }
-
- if ($id instanceof Uri) {
- if ($id->fragment() === null) {
- $id = Uri::merge($id, null, true);
- }
- } else {
- throw new ParseException('Root schema id must be an URI', new SchemaInfo($schema, $id));
- }
-
- if (!$id->isAbsolute()) {
- throw new ParseException('Root schema id must be an absolute URI', new SchemaInfo($schema, $id));
- }
-
- if ($id->fragment() !== '') {
- throw new ParseException('Root schema id must have an empty fragment or none', new SchemaInfo($schema, $id));
- }
-
- // Check if id exists
- if ($resolved = $handle_id($id)) {
- return $resolved;
- }
-
- if (property_exists($schema, '$schema')) {
- if (!is_string($schema->{'$schema'})) {
- throw new ParseException('Schema draft must be a string', new SchemaInfo($schema, $id));
- }
- $draft = $this->parseDraftVersion($schema->{'$schema'});
- }
-
- if ($draft === null) {
- $draft = $this->defaultDraftVersion();
- }
-
- if (!$existent) {
- $schema->{'$id'} = (string)$id;
- }
-
- $resolved = $handle_object($schema, $id, $draft);
-
- if (!$existent) {
- unset($schema->{'$id'});
- }
-
- return $resolved;
- }
-
- /**
- * @param SchemaInfo $info
- * @return Schema
- */
- public function parseSchema($info): Schema
- {
- if ($info->isBoolean()) {
- return new BooleanSchema($info);
- }
-
- try {
- return $this->parseSchemaObject($info);
- } catch (SchemaException $exception) {
- return new ExceptionSchema($info, $exception);
- }
- }
-
- /**
- * @param string $version
- * @return Draft|null
- */
- public function draft($version)
- {
- return $this->drafts[$version] ?? null;
- }
-
- /**
- * @param Draft $draft
- * @return $this
- */
- public function addDraft($draft): self
- {
- $this->drafts[$draft->version()] = $draft;
-
- return $this;
- }
-
- /**
- * @return string[]
- */
- public function supportedDrafts(): array
- {
- return array_keys($this->drafts);
- }
-
- /**
- * @param array $options
- * @return $this
- */
- protected function setOptions($options): self
- {
- $this->options = $options + $this->options;
-
- return $this;
- }
-
- /**
- * @param string $name
- * @return mixed|null
- */
- protected function getResolver($name)
- {
- $resolver = $this->resolvers[$name] ?? null;
-
- if (!is_object($resolver)) {
- return null;
- }
-
- return $resolver;
- }
-
- /**
- * @param SchemaInfo $info
- * @return Schema
- */
- protected function parseSchemaObject($info): Schema
- {
- $draftObject = $this->draft($info->draft());
-
- if ($draftObject === null) {
- throw new ParseException("Unsupported draft-{$info->draft()}", $info);
- }
-
- /** @var object $schema */
- $schema = $info->data();
-
- // Check id
- if (property_exists($schema, '$id')) {
- $id = $info->id();
- if ($id === null || !$id->isAbsolute()) {
- throw new ParseException('Schema id must be a valid URI', $info);
- }
- }
-
- if ($hasRef = property_exists($schema, '$ref')) {
- if ($this->option('allowKeywordsAlongsideRef') || $draftObject->allowKeywordsAlongsideRef()) {
- $hasRef = false;
- }
- }
-
- $shared = (object) [];
-
- if ($this->option('allowKeywordValidators')) {
- $keywordValidator = $this->parseKeywordValidators($info, $draftObject->keywordValidators(), $shared);
- } else {
- $keywordValidator = null;
- }
-
- return $this->parseSchemaKeywords($info, $keywordValidator, $draftObject->keywords(), $shared, $hasRef);
- }
-
- /**
- * @param SchemaInfo $info
- * @param KeywordValidatorParser[] $keywordValidators
- * @param object $shared
- * @return KeywordValidator|null
- */
- protected function parseKeywordValidators($info, $keywordValidators, $shared)
- {
- $last = null;
-
- while ($keywordValidators) {
- /** @var KeywordValidatorParser $keywordValidator */
- $keywordValidator = array_pop($keywordValidators);
- if ($keywordValidator && ($keyword = $keywordValidator->parse($info, $this, $shared))) {
- $keyword->setNext($last);
- $last = $keyword;
- unset($keyword);
- }
- unset($keywordValidator);
- }
-
- return $last;
- }
-
- /**
- * @param SchemaInfo $info
- * @param KeywordValidator|null $keywordValidator
- * @param KeywordParser[] $parsers
- * @param object $shared
- * @param bool $hasRef
- * @return Schema
- */
- protected function parseSchemaKeywords($info, $keywordValidator,
- $parsers, $shared, $hasRef = false): Schema
- {
- /** @var Keyword[] $prepend */
- $prepend = [];
- /** @var Keyword[] $append */
- $append = [];
- /** @var Keyword[] $before */
- $before = [];
- /** @var Keyword[] $after */
- $after = [];
- /** @var Keyword[][] $types */
- $types = [];
- /** @var Keyword[] $ref */
- $ref = [];
-
- if ($hasRef) {
- foreach ($parsers as $parser) {
- $kType = $parser->type();
-
- if ($kType === KeywordParser::TYPE_APPEND) {
- $container = &$append;
- } elseif ($kType === KeywordParser::TYPE_AFTER_REF) {
- $container = &$ref;
- } elseif ($kType === KeywordParser::TYPE_PREPEND) {
- $container = &$prepend;
- } else {
- continue;
- }
-
- if ($keyword = $parser->parse($info, $this, $shared)) {
- $container[] = $keyword;
- }
-
- unset($container, $keyword, $kType);
- }
- } else {
- foreach ($parsers as $parser) {
- $keyword = $parser->parse($info, $this, $shared);
- if ($keyword === null) {
- continue;
- }
-
- $kType = $parser->type();
-
- switch ($kType) {
- case KeywordParser::TYPE_PREPEND:
- $prepend[] = $keyword;
- break;
- case KeywordParser::TYPE_APPEND:
- $append[] = $keyword;
- break;
- case KeywordParser::TYPE_BEFORE:
- $before[] = $keyword;
- break;
- case KeywordParser::TYPE_AFTER:
- $after[] = $keyword;
- break;
- case KeywordParser::TYPE_AFTER_REF:
- $ref[] = $keyword;
- break;
- default:
- if (!isset($types[$kType])) {
- $types[$kType] = [];
- }
- $types[$kType][] = $keyword;
- break;
-
- }
- }
- }
-
- unset($shared);
-
- if ($prepend) {
- $before = array_merge($prepend, $before);
- }
- unset($prepend);
-
- if ($ref) {
- $after = array_merge($after, $ref);
- }
- unset($ref);
-
- if ($append) {
- $after = array_merge($after, $append);
- }
- unset($append);
-
- if (empty($before)) {
- $before = null;
- }
- if (empty($after)) {
- $after = null;
- }
- if (empty($types)) {
- $types = null;
- }
-
- if (empty($types) && empty($before) && empty($after)) {
- return new EmptySchema($info, $keywordValidator);
- }
-
- return new ObjectSchema($info, $keywordValidator, $types, $before, $after);
- }
+class SchemaParser {
+
+ const DRAFT_REGEX = '~^https?://json-schema\.org/draft(?:/|-)(\d[0-9-]*\d)/schema#?$~i';
+ const ANCHOR_REGEX = '/^[a-z][a-z0-9\\-.:_]*/i';
+ const DEFAULT_DRAFT = '2020-12';
+
+ /** @var array */
+ const DEFAULT_OPTIONS = array(
+ 'allowFilters' => true,
+ 'allowFormats' => true,
+ 'allowMappers' => true,
+ 'allowTemplates' => true,
+ 'allowGlobals' => true,
+ 'allowDefaults' => true,
+ 'allowSlots' => true,
+ 'allowKeywordValidators' => true,
+ 'allowPragmas' => true,
+
+ 'allowDataKeyword' => true,
+ 'allowKeywordsAlongsideRef' => false,
+ 'allowUnevaluated' => true,
+ 'allowRelativeJsonPointerInRef' => true,
+ 'allowExclusiveMinMaxAsBool' => true,
+
+ 'keepDependenciesKeyword' => true,
+ 'keepAdditionalItemsKeyword' => true,
+
+ 'decodeContent' => array( '06', '07' ),
+ 'defaultDraft' => self::DEFAULT_DRAFT,
+
+ 'varRefKey' => '$ref',
+ 'varEachKey' => '$each',
+ 'varDefaultKey' => 'default',
+ );
+
+ /** @var array */
+ protected $options;
+
+ /** @var Draft[] */
+ protected $drafts;
+
+ /** @var array */
+ protected $resolvers;
+
+ /**
+ * @param array $resolvers
+ * @param array $options
+ * @param Vocabulary|null $extraVocabulary
+ */
+ public function __construct(
+ array $resolvers = array(),
+ array $options = array(),
+ $extraVocabulary = null
+ ) {
+ if ( $options ) {
+ $this->options = $options + self::DEFAULT_OPTIONS;
+ } else {
+ $this->options = self::DEFAULT_OPTIONS;
+ }
+
+ $this->resolvers = $this->getResolvers( $resolvers );
+
+ $this->drafts = $this->getDrafts( $extraVocabulary ?? new DefaultVocabulary() );
+ }
+
+ /**
+ * @param Vocabulary|null $extraVocabulary
+ * @return array
+ */
+ protected function getDrafts( $extraVocabulary ): array {
+ return array(
+ '06' => new Draft06( $extraVocabulary ),
+ '07' => new Draft07( $extraVocabulary ),
+ '2019-09' => new Draft201909( $extraVocabulary ),
+ '2020-12' => new Draft202012( $extraVocabulary ),
+ );
+ }
+
+ /**
+ * @param array $resolvers
+ * @return array
+ */
+ protected function getResolvers( $resolvers ): array {
+ if ( ! array_key_exists( 'format', $resolvers ) ) {
+ $resolvers['format'] = new FormatResolver();
+ }
+
+ if ( ! array_key_exists( 'contentEncoding', $resolvers ) ) {
+ $resolvers['contentEncoding'] = new ContentEncodingResolver();
+ }
+
+ if ( ! array_key_exists( 'contentMediaType', $resolvers ) ) {
+ $resolvers['contentMediaType'] = new ContentMediaTypeResolver();
+ }
+
+ if ( ! array_key_exists( '$filters', $resolvers ) ) {
+ $resolvers['$filters'] = new FilterResolver();
+ }
+
+ return $resolvers;
+ }
+
+ /**
+ * @param string $name
+ * @param null $default
+ * @return mixed|null
+ */
+ public function option( $name, $default = null ) {
+ return $this->options[ $name ] ?? $default;
+ }
+
+ /**
+ * @param string $name
+ * @param $value
+ * @return $this
+ */
+ public function setOption( $name, $value ): self {
+ $this->options[ $name ] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function getOptions(): array {
+ return $this->options;
+ }
+
+ /**
+ * @param string $name
+ * @param $resolver
+ * @return $this
+ */
+ public function setResolver( $name, $resolver ): self {
+ $this->resolvers[ $name ] = $resolver;
+
+ return $this;
+ }
+
+ /**
+ * @return null|FilterResolver
+ */
+ public function getFilterResolver() {
+ return $this->getResolver( '$filters' );
+ }
+
+ /**
+ * @param null|FilterResolver $resolver
+ * @return $this
+ */
+ public function setFilterResolver( $resolver ): self {
+ return $this->setResolver( '$filters', $resolver );
+ }
+
+ /**
+ * @return null|FormatResolver
+ */
+ public function getFormatResolver() {
+ return $this->getResolver( 'format' );
+ }
+
+ /**
+ * @param FormatResolver|null $resolver
+ * @return $this
+ */
+ public function setFormatResolver( $resolver ): self {
+ return $this->setResolver( 'format', $resolver );
+ }
+
+ /**
+ * @return null|ContentEncodingResolver
+ */
+ public function getContentEncodingResolver() {
+ return $this->getResolver( 'contentEncoding' );
+ }
+
+ /**
+ * @param ContentEncodingResolver|null $resolver
+ * @return $this
+ */
+ public function setContentEncodingResolver( $resolver ): self {
+ return $this->setResolver( 'contentEncoding', $resolver );
+ }
+
+ /**
+ * @return null|ContentMediaTypeResolver
+ */
+ public function getMediaTypeResolver() {
+ return $this->getResolver( 'contentMediaType' );
+ }
+
+ /**
+ * @param ContentMediaTypeResolver|null $resolver
+ * @return $this
+ */
+ public function setMediaTypeResolver( $resolver ): self {
+ return $this->setResolver( 'contentMediaType', $resolver );
+ }
+
+ /**
+ * @return string
+ */
+ public function defaultDraftVersion(): string {
+ return $this->option( 'defaultDraft', self::DEFAULT_DRAFT );
+ }
+
+ /**
+ * @param string $draft
+ * @return $this
+ */
+ public function setDefaultDraftVersion( $draft ): self {
+ return $this->setOption( 'defaultDraft', $draft );
+ }
+
+ /**
+ * @param string $schema
+ * @return string|null
+ */
+ public function parseDraftVersion( $schema ) {
+ if ( ! preg_match( self::DRAFT_REGEX, $schema, $m ) ) {
+ return null;
+ }
+
+ return $m[1] ?? null;
+ }
+
+ /**
+ * @param object $schema
+ * @return string|null
+ */
+ public function parseId( $schema ) {
+ if ( property_exists( $schema, '$id' ) && is_string( $schema->{'$id'} ) ) {
+ return $schema->{'$id'};
+ }
+
+ return null;
+ }
+
+ /**
+ * @param object $schema
+ * @param string $draft
+ * @return string|null
+ */
+ public function parseAnchor( $schema, $draft ) {
+ if ( ! property_exists( $schema, '$anchor' ) ||
+ ! isset( $this->drafts[ $draft ] ) ||
+ ! $this->drafts[ $draft ]->supportsAnchorId() ) {
+ return null;
+ }
+
+ $anchor = $schema->{'$anchor'};
+
+ if ( ! is_string( $anchor ) || ! preg_match( self::ANCHOR_REGEX, $anchor ) ) {
+ return null;
+ }
+
+ return $anchor;
+ }
+
+ /**
+ * @param object $schema
+ * @return string|null
+ */
+ public function parseSchemaDraft( $schema ) {
+ if ( ! property_exists( $schema, '$schema' ) || ! is_string( $schema->{'$schema'} ) ) {
+ return null;
+ }
+
+ return $this->parseDraftVersion( $schema->{'$schema'} );
+ }
+
+ /**
+ * @param object $schema
+ * @param Uri $id
+ * @param callable $handle_id
+ * @param callable $handle_object
+ * @param string|null $draft
+ * @return Schema|null
+ */
+ public function parseRootSchema(
+ $schema,
+ $id,
+ $handle_id,
+ $handle_object,
+ $draft = null
+ ) {
+ $existent = false;
+ if ( property_exists( $schema, '$id' ) ) {
+ $existent = true;
+ $id = Uri::parse( $schema->{'$id'}, true );
+ }
+
+ if ( $id instanceof Uri ) {
+ if ( $id->fragment() === null ) {
+ $id = Uri::merge( $id, null, true );
+ }
+ } else {
+ throw new ParseException( 'Root schema id must be an URI', new SchemaInfo( $schema, $id ) );
+ }
+
+ if ( ! $id->isAbsolute() ) {
+ throw new ParseException( 'Root schema id must be an absolute URI', new SchemaInfo( $schema, $id ) );
+ }
+
+ if ( $id->fragment() !== '' ) {
+ throw new ParseException( 'Root schema id must have an empty fragment or none', new SchemaInfo( $schema, $id ) );
+ }
+
+ // Check if id exists
+ if ( $resolved = $handle_id( $id ) ) {
+ return $resolved;
+ }
+
+ if ( property_exists( $schema, '$schema' ) ) {
+ if ( ! is_string( $schema->{'$schema'} ) ) {
+ throw new ParseException( 'Schema draft must be a string', new SchemaInfo( $schema, $id ) );
+ }
+ $draft = $this->parseDraftVersion( $schema->{'$schema'} );
+ }
+
+ if ( $draft === null ) {
+ $draft = $this->defaultDraftVersion();
+ }
+
+ if ( ! $existent ) {
+ $schema->{'$id'} = (string) $id;
+ }
+
+ $resolved = $handle_object( $schema, $id, $draft );
+
+ if ( ! $existent ) {
+ unset( $schema->{'$id'} );
+ }
+
+ return $resolved;
+ }
+
+ /**
+ * @param SchemaInfo $info
+ * @return Schema
+ */
+ public function parseSchema( $info ): Schema {
+ if ( $info->isBoolean() ) {
+ return new BooleanSchema( $info );
+ }
+
+ try {
+ return $this->parseSchemaObject( $info );
+ } catch ( SchemaException $exception ) {
+ return new ExceptionSchema( $info, $exception );
+ }
+ }
+
+ /**
+ * @param string $version
+ * @return Draft|null
+ */
+ public function draft( $version ) {
+ return $this->drafts[ $version ] ?? null;
+ }
+
+ /**
+ * @param Draft $draft
+ * @return $this
+ */
+ public function addDraft( $draft ): self {
+ $this->drafts[ $draft->version() ] = $draft;
+
+ return $this;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function supportedDrafts(): array {
+ return array_keys( $this->drafts );
+ }
+
+ /**
+ * @param array $options
+ * @return $this
+ */
+ protected function setOptions( $options ): self {
+ $this->options = $options + $this->options;
+
+ return $this;
+ }
+
+ /**
+ * @param string $name
+ * @return mixed|null
+ */
+ protected function getResolver( $name ) {
+ $resolver = $this->resolvers[ $name ] ?? null;
+
+ if ( ! is_object( $resolver ) ) {
+ return null;
+ }
+
+ return $resolver;
+ }
+
+ /**
+ * @param SchemaInfo $info
+ * @return Schema
+ */
+ protected function parseSchemaObject( $info ): Schema {
+ $draftObject = $this->draft( $info->draft() );
+
+ if ( $draftObject === null ) {
+ throw new ParseException( "Unsupported draft-{$info->draft()}", $info );
+ }
+
+ /** @var object $schema */
+ $schema = $info->data();
+
+ // Check id
+ if ( property_exists( $schema, '$id' ) ) {
+ $id = $info->id();
+ if ( $id === null || ! $id->isAbsolute() ) {
+ throw new ParseException( 'Schema id must be a valid URI', $info );
+ }
+ }
+
+ if ( $hasRef = property_exists( $schema, '$ref' ) ) {
+ if ( $this->option( 'allowKeywordsAlongsideRef' ) || $draftObject->allowKeywordsAlongsideRef() ) {
+ $hasRef = false;
+ }
+ }
+
+ $shared = (object) array();
+
+ if ( $this->option( 'allowKeywordValidators' ) ) {
+ $keywordValidator = $this->parseKeywordValidators( $info, $draftObject->keywordValidators(), $shared );
+ } else {
+ $keywordValidator = null;
+ }
+
+ return $this->parseSchemaKeywords( $info, $keywordValidator, $draftObject->keywords(), $shared, $hasRef );
+ }
+
+ /**
+ * @param SchemaInfo $info
+ * @param KeywordValidatorParser[] $keywordValidators
+ * @param object $shared
+ * @return KeywordValidator|null
+ */
+ protected function parseKeywordValidators( $info, $keywordValidators, $shared ) {
+ $last = null;
+
+ while ( $keywordValidators ) {
+ /** @var KeywordValidatorParser $keywordValidator */
+ $keywordValidator = array_pop( $keywordValidators );
+ if ( $keywordValidator && ( $keyword = $keywordValidator->parse( $info, $this, $shared ) ) ) {
+ $keyword->setNext( $last );
+ $last = $keyword;
+ unset( $keyword );
+ }
+ unset( $keywordValidator );
+ }
+
+ return $last;
+ }
+
+ /**
+ * @param SchemaInfo $info
+ * @param KeywordValidator|null $keywordValidator
+ * @param KeywordParser[] $parsers
+ * @param object $shared
+ * @param bool $hasRef
+ * @return Schema
+ */
+ protected function parseSchemaKeywords(
+ $info,
+ $keywordValidator,
+ $parsers,
+ $shared,
+ $hasRef = false
+ ): Schema {
+ /** @var Keyword[] $prepend */
+ $prepend = array();
+ /** @var Keyword[] $append */
+ $append = array();
+ /** @var Keyword[] $before */
+ $before = array();
+ /** @var Keyword[] $after */
+ $after = array();
+ /** @var Keyword[][] $types */
+ $types = array();
+ /** @var Keyword[] $ref */
+ $ref = array();
+
+ if ( $hasRef ) {
+ foreach ( $parsers as $parser ) {
+ $kType = $parser->type();
+
+ if ( $kType === KeywordParser::TYPE_APPEND ) {
+ $container = &$append;
+ } elseif ( $kType === KeywordParser::TYPE_AFTER_REF ) {
+ $container = &$ref;
+ } elseif ( $kType === KeywordParser::TYPE_PREPEND ) {
+ $container = &$prepend;
+ } else {
+ continue;
+ }
+
+ if ( $keyword = $parser->parse( $info, $this, $shared ) ) {
+ $container[] = $keyword;
+ }
+
+ unset( $container, $keyword, $kType );
+ }
+ } else {
+ foreach ( $parsers as $parser ) {
+ $keyword = $parser->parse( $info, $this, $shared );
+ if ( $keyword === null ) {
+ continue;
+ }
+
+ $kType = $parser->type();
+
+ switch ( $kType ) {
+ case KeywordParser::TYPE_PREPEND:
+ $prepend[] = $keyword;
+ break;
+ case KeywordParser::TYPE_APPEND:
+ $append[] = $keyword;
+ break;
+ case KeywordParser::TYPE_BEFORE:
+ $before[] = $keyword;
+ break;
+ case KeywordParser::TYPE_AFTER:
+ $after[] = $keyword;
+ break;
+ case KeywordParser::TYPE_AFTER_REF:
+ $ref[] = $keyword;
+ break;
+ default:
+ if ( ! isset( $types[ $kType ] ) ) {
+ $types[ $kType ] = array();
+ }
+ $types[ $kType ][] = $keyword;
+ break;
+
+ }
+ }
+ }
+
+ unset( $shared );
+
+ if ( $prepend ) {
+ $before = array_merge( $prepend, $before );
+ }
+ unset( $prepend );
+
+ if ( $ref ) {
+ $after = array_merge( $after, $ref );
+ }
+ unset( $ref );
+
+ if ( $append ) {
+ $after = array_merge( $after, $append );
+ }
+ unset( $append );
+
+ if ( empty( $before ) ) {
+ $before = null;
+ }
+ if ( empty( $after ) ) {
+ $after = null;
+ }
+ if ( empty( $types ) ) {
+ $types = null;
+ }
+
+ if ( empty( $types ) && empty( $before ) && empty( $after ) ) {
+ return new EmptySchema( $info, $keywordValidator );
+ }
+
+ return new ObjectSchema( $info, $keywordValidator, $types, $before, $after );
+ }
}
diff --git a/src/opis/json-schema/src/Parsers/VariablesTrait.php b/src/opis/json-schema/src/Parsers/VariablesTrait.php
index 611127ce..edbddb81 100644
--- a/src/opis/json-schema/src/Parsers/VariablesTrait.php
+++ b/src/opis/json-schema/src/Parsers/VariablesTrait.php
@@ -1,5 +1,6 @@
option('varRefKey', '$ref'),
- $parser->option('varEachKey', '$each'),
- $parser->option('varDefaultKey', 'default')
- );
- }
-}
\ No newline at end of file
+trait VariablesTrait {
+
+ /**
+ * @param SchemaParser $parser
+ * @param array|object $vars
+ * @param bool $lazy
+ * @return Variables
+ */
+ protected function createVariables( $parser, $vars, $lazy = true ): Variables {
+ return new VariablesContainer(
+ $vars,
+ $lazy,
+ $parser->option( 'varRefKey', '$ref' ),
+ $parser->option( 'varEachKey', '$each' ),
+ $parser->option( 'varDefaultKey', 'default' )
+ );
+ }
+}
diff --git a/src/opis/json-schema/src/Parsers/Vocabulary.php b/src/opis/json-schema/src/Parsers/Vocabulary.php
index 9d402270..bb504579 100644
--- a/src/opis/json-schema/src/Parsers/Vocabulary.php
+++ b/src/opis/json-schema/src/Parsers/Vocabulary.php
@@ -1,5 +1,6 @@
keywords = $keywords;
- $this->keywordValidators = $keywordValidators;
- $this->pragmas = $pragmas;
- }
+ /** @var PragmaParser[] */
+ protected $pragmas;
- /**
- * @return KeywordParser[]
- */
- public function keywords(): array
- {
- return $this->keywords;
- }
+ /**
+ * @param KeywordParser[] $keywords
+ * @param KeywordValidatorParser[] $keywordValidators
+ * @param PragmaParser[] $pragmas
+ */
+ public function __construct( array $keywords = array(), array $keywordValidators = array(), array $pragmas = array() ) {
+ $this->keywords = $keywords;
+ $this->keywordValidators = $keywordValidators;
+ $this->pragmas = $pragmas;
+ }
- /**
- * @return KeywordValidatorParser[]
- */
- public function keywordValidators(): array
- {
- return $this->keywordValidators;
- }
+ /**
+ * @return KeywordParser[]
+ */
+ public function keywords(): array {
+ return $this->keywords;
+ }
- /**
- * @return PragmaParser[]
- */
- public function pragmas(): array
- {
- return $this->pragmas;
- }
+ /**
+ * @return KeywordValidatorParser[]
+ */
+ public function keywordValidators(): array {
+ return $this->keywordValidators;
+ }
- /**
- * @param KeywordParser $keyword
- * @return Vocabulary
- */
- public function appendKeyword($keyword): self
- {
- $this->keywords[] = $keyword;
- return $this;
- }
+ /**
+ * @return PragmaParser[]
+ */
+ public function pragmas(): array {
+ return $this->pragmas;
+ }
- /**
- * @param KeywordParser $keyword
- * @return Vocabulary
- */
- public function prependKeyword($keyword): self
- {
- array_unshift($this->keywords, $keyword);
- return $this;
- }
+ /**
+ * @param KeywordParser $keyword
+ * @return Vocabulary
+ */
+ public function appendKeyword( $keyword ): self {
+ $this->keywords[] = $keyword;
+ return $this;
+ }
- /**
- * @param KeywordValidatorParser $keywordValidatorParser
- * @return Vocabulary
- */
- public function appendKeywordValidator($keywordValidatorParser): self
- {
- $this->keywordValidators[] = $keywordValidatorParser;
- return $this;
- }
+ /**
+ * @param KeywordParser $keyword
+ * @return Vocabulary
+ */
+ public function prependKeyword( $keyword ): self {
+ array_unshift( $this->keywords, $keyword );
+ return $this;
+ }
- /**
- * @param KeywordValidatorParser $keywordValidator
- * @return Vocabulary
- */
- public function prependKeywordValidator($keywordValidator): self
- {
- array_unshift($this->keywordValidators, $keywordValidator);
- return $this;
- }
+ /**
+ * @param KeywordValidatorParser $keywordValidatorParser
+ * @return Vocabulary
+ */
+ public function appendKeywordValidator( $keywordValidatorParser ): self {
+ $this->keywordValidators[] = $keywordValidatorParser;
+ return $this;
+ }
- /**
- * @param PragmaParser $pragma
- * @return Vocabulary
- */
- public function appendPragma($pragma): self
- {
- $this->pragmas[] = $pragma;
- return $this;
- }
+ /**
+ * @param KeywordValidatorParser $keywordValidator
+ * @return Vocabulary
+ */
+ public function prependKeywordValidator( $keywordValidator ): self {
+ array_unshift( $this->keywordValidators, $keywordValidator );
+ return $this;
+ }
- /**
- * @param PragmaParser $pragma
- * @return Vocabulary
- */
- public function prependPragma($pragma): self
- {
- array_unshift($this->pragmas, $pragma);
- return $this;
- }
-}
\ No newline at end of file
+ /**
+ * @param PragmaParser $pragma
+ * @return Vocabulary
+ */
+ public function appendPragma( $pragma ): self {
+ $this->pragmas[] = $pragma;
+ return $this;
+ }
+
+ /**
+ * @param PragmaParser $pragma
+ * @return Vocabulary
+ */
+ public function prependPragma( $pragma ): self {
+ array_unshift( $this->pragmas, $pragma );
+ return $this;
+ }
+}
diff --git a/src/opis/json-schema/src/Pragma.php b/src/opis/json-schema/src/Pragma.php
index 22ebbb72..f2ff2897 100644
--- a/src/opis/json-schema/src/Pragma.php
+++ b/src/opis/json-schema/src/Pragma.php
@@ -1,5 +1,6 @@
cast = $cast;
- $this->func = $this->getCastFunction($cast);
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function enter($context)
- {
- $currentType = $context->currentDataType();
- if ($currentType !== null && Helper::jsonTypeMatches($currentType, $this->cast)) {
- // Cast not needed
- return $this;
- }
- unset($currentType);
-
- $currentData = $context->currentData();
-
- $context->setCurrentData(($this->func)($currentData));
-
- return $currentData;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function leave($context, $data)
- {
- if ($data !== $this) {
- $context->setCurrentData($data);
- }
- }
-
- /**
- * @param string $type
- * @return callable
- */
- protected function getCastFunction($type): callable
- {
- $f = 'toNull';
-
- switch ($type) {
- case 'integer':
- $f = 'toInteger';
- break;
- case 'number':
- $f = 'toNumber';
- break;
- case 'string':
- $f = 'toString';
- break;
- case 'array':
- $f = 'toArray';
- break;
- case 'object':
- $f = 'toObject';
- break;
- case 'boolean':
- $f = 'toBoolean';
- break;
- }
-
- return [$this, $f];
- }
-
- /**
- * @param $value
- * @return int|null
- */
- public function toInteger($value)
- {
- if ($value === null) {
- return 0;
- }
-
- return is_scalar($value) ? intval($value) : null;
- }
-
- /**
- * @param $value
- * @return float|null
- */
- public function toNumber($value)
- {
- if ($value === null) {
- return 0.0;
- }
-
- return is_scalar($value) ? floatval($value) : null;
- }
-
- /**
- * @param $value
- * @return string|null
- */
- public function toString($value)
- {
- if ($value === null) {
- return '';
- }
-
- if (is_scalar($value)) {
- return (string) $value;
- }
-
- return null;
- }
-
- /**
- * @param $value
- * @return array|null
- */
- public function toArray($value)
- {
- if ($value === null) {
- return [];
- }
-
- if (is_scalar($value)) {
- return [$value];
- }
-
- if (is_array($value)) {
- return array_values($value);
- }
-
- if (is_object($value)) {
- return array_values(get_object_vars($value));
- }
-
- return null;
- }
-
- /**
- * @param $value
- * @return object|null
- */
- public function toObject($value)
- {
- if (is_object($value) || is_array($value)) {
- return (object) $value;
- }
-
- return null;
- }
-
- /**
- * @param $value
- * @return bool
- */
- public function toBoolean($value): bool
- {
- if ($value === null) {
- return false;
- }
- if (is_string($value)) {
- return !($value === '');
- }
- if (is_object($value)) {
- return count(get_object_vars($value)) > 0;
- }
- return boolval($value);
- }
+class CastPragma implements Pragma {
+
+
+ /**
+ * @var string
+ */
+ protected $cast;
+
+ /** @var callable */
+ protected $func;
+
+ /**
+ * @param string $cast
+ */
+ public function __construct( string $cast ) {
+ $this->cast = $cast;
+ $this->func = $this->getCastFunction( $cast );
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function enter( $context ) {
+ $currentType = $context->currentDataType();
+ if ( $currentType !== null && Helper::jsonTypeMatches( $currentType, $this->cast ) ) {
+ // Cast not needed
+ return $this;
+ }
+ unset( $currentType );
+
+ $currentData = $context->currentData();
+
+ $context->setCurrentData( ( $this->func )( $currentData ) );
+
+ return $currentData;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function leave( $context, $data ) {
+ if ( $data !== $this ) {
+ $context->setCurrentData( $data );
+ }
+ }
+
+ /**
+ * @param string $type
+ * @return callable
+ */
+ protected function getCastFunction( $type ): callable {
+ $f = 'toNull';
+
+ switch ( $type ) {
+ case 'integer':
+ $f = 'toInteger';
+ break;
+ case 'number':
+ $f = 'toNumber';
+ break;
+ case 'string':
+ $f = 'toString';
+ break;
+ case 'array':
+ $f = 'toArray';
+ break;
+ case 'object':
+ $f = 'toObject';
+ break;
+ case 'boolean':
+ $f = 'toBoolean';
+ break;
+ }
+
+ return array( $this, $f );
+ }
+
+ /**
+ * @param $value
+ * @return int|null
+ */
+ public function toInteger( $value ) {
+ if ( $value === null ) {
+ return 0;
+ }
+
+ return is_scalar( $value ) ? intval( $value ) : null;
+ }
+
+ /**
+ * @param $value
+ * @return float|null
+ */
+ public function toNumber( $value ) {
+ if ( $value === null ) {
+ return 0.0;
+ }
+
+ return is_scalar( $value ) ? floatval( $value ) : null;
+ }
+
+ /**
+ * @param $value
+ * @return string|null
+ */
+ public function toString( $value ) {
+ if ( $value === null ) {
+ return '';
+ }
+
+ if ( is_scalar( $value ) ) {
+ return (string) $value;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param $value
+ * @return array|null
+ */
+ public function toArray( $value ) {
+ if ( $value === null ) {
+ return array();
+ }
+
+ if ( is_scalar( $value ) ) {
+ return array( $value );
+ }
+
+ if ( is_array( $value ) ) {
+ return array_values( $value );
+ }
+
+ if ( is_object( $value ) ) {
+ return array_values( get_object_vars( $value ) );
+ }
+
+ return null;
+ }
+
+ /**
+ * @param $value
+ * @return object|null
+ */
+ public function toObject( $value ) {
+ if ( is_object( $value ) || is_array( $value ) ) {
+ return (object) $value;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param $value
+ * @return bool
+ */
+ public function toBoolean( $value ): bool {
+ if ( $value === null ) {
+ return false;
+ }
+ if ( is_string( $value ) ) {
+ return ! ( $value === '' );
+ }
+ if ( is_object( $value ) ) {
+ return count( get_object_vars( $value ) ) > 0;
+ }
+ return boolval( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Pragmas/GlobalsPragma.php b/src/opis/json-schema/src/Pragmas/GlobalsPragma.php
index b9b7473c..9b10ab34 100644
--- a/src/opis/json-schema/src/Pragmas/GlobalsPragma.php
+++ b/src/opis/json-schema/src/Pragmas/GlobalsPragma.php
@@ -1,5 +1,6 @@
globals = $globals;
- }
+ /**
+ * @var \Opis\JsonSchema\Variables
+ */
+ protected $globals;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function enter($context)
- {
- $resolved = (array) $this->globals->resolve($context->rootData(), $context->currentDataPath());
- if (!$resolved) {
- return null;
- }
+ /**
+ * @param Variables $globals
+ */
+ public function __construct( Variables $globals ) {
+ $this->globals = $globals;
+ }
- $data = $context->globals();
- $context->setGlobals($resolved, false);
- return $data;
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function enter( $context ) {
+ $resolved = (array) $this->globals->resolve( $context->rootData(), $context->currentDataPath() );
+ if ( ! $resolved ) {
+ return null;
+ }
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function leave($context, $data)
- {
- if ($data === null) {
- return;
- }
- $context->setGlobals($data, true);
- }
+ $data = $context->globals();
+ $context->setGlobals( $resolved, false );
+ return $data;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function leave( $context, $data ) {
+ if ( $data === null ) {
+ return;
+ }
+ $context->setGlobals( $data, true );
+ }
}
diff --git a/src/opis/json-schema/src/Pragmas/MaxErrorsPragma.php b/src/opis/json-schema/src/Pragmas/MaxErrorsPragma.php
index d669929e..65ef1ecb 100644
--- a/src/opis/json-schema/src/Pragmas/MaxErrorsPragma.php
+++ b/src/opis/json-schema/src/Pragmas/MaxErrorsPragma.php
@@ -1,5 +1,6 @@
maxErrors = $maxErrors;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function enter($context)
- {
- $data = $context->maxErrors();
- $context->setMaxErrors($this->maxErrors);
- return $data;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function leave($context, $data)
- {
- if ($data === null) {
- return;
- }
- $context->setMaxErrors($data);
- }
+class MaxErrorsPragma implements Pragma {
+
+
+ /**
+ * @var int
+ */
+ protected $maxErrors;
+
+ /**
+ * @param int $maxErrors
+ */
+ public function __construct( int $maxErrors ) {
+ $this->maxErrors = $maxErrors;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function enter( $context ) {
+ $data = $context->maxErrors();
+ $context->setMaxErrors( $this->maxErrors );
+ return $data;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function leave( $context, $data ) {
+ if ( $data === null ) {
+ return;
+ }
+ $context->setMaxErrors( $data );
+ }
}
diff --git a/src/opis/json-schema/src/Pragmas/SlotsPragma.php b/src/opis/json-schema/src/Pragmas/SlotsPragma.php
index 60d380fd..3da6578f 100644
--- a/src/opis/json-schema/src/Pragmas/SlotsPragma.php
+++ b/src/opis/json-schema/src/Pragmas/SlotsPragma.php
@@ -1,5 +1,6 @@
slots = $slots;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function enter($context)
- {
- $data = $context->slots();
- $context->setSlots($data ? $this->slots + $data : $this->slots);
- return $data;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function leave($context, $data)
- {
- $context->setSlots($data);
- }
+class SlotsPragma implements Pragma {
+
+
+ /**
+ * @var mixed[]
+ */
+ protected $slots;
+
+ /**
+ * @param array $slots
+ */
+ public function __construct( array $slots ) {
+ $this->slots = $slots;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function enter( $context ) {
+ $data = $context->slots();
+ $context->setSlots( $data ? $this->slots + $data : $this->slots );
+ return $data;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function leave( $context, $data ) {
+ $context->setSlots( $data );
+ }
}
diff --git a/src/opis/json-schema/src/Resolvers/ContentEncodingResolver.php b/src/opis/json-schema/src/Resolvers/ContentEncodingResolver.php
index 40d0f387..69e9363c 100644
--- a/src/opis/json-schema/src/Resolvers/ContentEncodingResolver.php
+++ b/src/opis/json-schema/src/Resolvers/ContentEncodingResolver.php
@@ -1,5 +1,6 @@
self::class . '::DecodeBinary',
- 'base64' => self::class . '::DecodeBase64',
- 'quoted-printable' => self::class . '::DecodeQuotedPrintable',
- ];
-
- $this->list = $list;
- $this->defaultEncoding = $defaultEncoding;
- }
-
- /**
- * @param string $name
- * @return callable|ContentEncoding|string|null
- */
- public function resolve($name)
- {
- return $this->list[$name] ?? $this->defaultEncoding;
- }
-
- /**
- * @param string $name
- * @param ContentEncoding $encoding
- * @return ContentEncodingResolver
- */
- public function register($name, $encoding): self
- {
- $this->list[$name] = $encoding;
-
- return $this;
- }
-
- /**
- * @param string $name
- * @param callable $encoding
- * @return ContentEncodingResolver
- */
- public function registerCallable($name, $encoding): self
- {
- $this->list[$name] = $encoding;
-
- return $this;
- }
-
- /**
- * @param string $name
- * @return bool
- */
- public function unregister($name): bool
- {
- if (isset($this->list[$name])) {
- unset($this->list[$name]);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * @param callable|ContentEncoding|null $handler
- * @return $this
- */
- public function setDefaultHandler($handler): self
- {
- $this->defaultEncoding = $handler;
- return $this;
- }
-
- public function __serialize(): array
- {
- return [
- 'list' => $this->list,
- 'defaultEncoding' => $this->defaultEncoding,
- ];
- }
-
- public function __unserialize(array $data)
- {
- $this->list = $data['list'];
- $this->defaultEncoding = $data['defaultEncoding'] ?? null;
- }
-
- /**
- * @param string $value
- */
- public static function DecodeBinary($value)
- {
- return $value;
- }
-
- /**
- * @param string $value
- */
- public static function DecodeBase64($value)
- {
- $value = base64_decode($value, true);
-
- return is_string($value) ? $value : null;
- }
-
- /**
- * @param string $value
- */
- public static function DecodeQuotedPrintable($value)
- {
- return quoted_printable_decode($value);
- }
+class ContentEncodingResolver {
+
+ /** @var callable[]|ContentEncoding[] */
+ protected $list;
+
+ /** @var callable|ContentEncoding|null */
+ protected $defaultEncoding = null;
+
+ /**
+ * @param callable[]|ContentEncoding[] $list
+ * @param callable|ContentEncoding|null $defaultEncoding
+ */
+ public function __construct( array $list = array(), $defaultEncoding = null ) {
+ $list += array(
+ 'binary' => self::class . '::DecodeBinary',
+ 'base64' => self::class . '::DecodeBase64',
+ 'quoted-printable' => self::class . '::DecodeQuotedPrintable',
+ );
+
+ $this->list = $list;
+ $this->defaultEncoding = $defaultEncoding;
+ }
+
+ /**
+ * @param string $name
+ * @return callable|ContentEncoding|string|null
+ */
+ public function resolve( $name ) {
+ return $this->list[ $name ] ?? $this->defaultEncoding;
+ }
+
+ /**
+ * @param string $name
+ * @param ContentEncoding $encoding
+ * @return ContentEncodingResolver
+ */
+ public function register( $name, $encoding ): self {
+ $this->list[ $name ] = $encoding;
+
+ return $this;
+ }
+
+ /**
+ * @param string $name
+ * @param callable $encoding
+ * @return ContentEncodingResolver
+ */
+ public function registerCallable( $name, $encoding ): self {
+ $this->list[ $name ] = $encoding;
+
+ return $this;
+ }
+
+ /**
+ * @param string $name
+ * @return bool
+ */
+ public function unregister( $name ): bool {
+ if ( isset( $this->list[ $name ] ) ) {
+ unset( $this->list[ $name ] );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param callable|ContentEncoding|null $handler
+ * @return $this
+ */
+ public function setDefaultHandler( $handler ): self {
+ $this->defaultEncoding = $handler;
+ return $this;
+ }
+
+ public function __serialize(): array {
+ return array(
+ 'list' => $this->list,
+ 'defaultEncoding' => $this->defaultEncoding,
+ );
+ }
+
+ public function __unserialize( array $data ) {
+ $this->list = $data['list'];
+ $this->defaultEncoding = $data['defaultEncoding'] ?? null;
+ }
+
+ /**
+ * @param string $value
+ */
+ public static function DecodeBinary( $value ) {
+ return $value;
+ }
+
+ /**
+ * @param string $value
+ */
+ public static function DecodeBase64( $value ) {
+ $value = base64_decode( $value, true );
+
+ return is_string( $value ) ? $value : null;
+ }
+
+ /**
+ * @param string $value
+ */
+ public static function DecodeQuotedPrintable( $value ) {
+ return quoted_printable_decode( $value );
+ }
}
diff --git a/src/opis/json-schema/src/Resolvers/ContentMediaTypeResolver.php b/src/opis/json-schema/src/Resolvers/ContentMediaTypeResolver.php
index 7b86c116..f12daf59 100644
--- a/src/opis/json-schema/src/Resolvers/ContentMediaTypeResolver.php
+++ b/src/opis/json-schema/src/Resolvers/ContentMediaTypeResolver.php
@@ -1,5 +1,6 @@
self::class . '::IsJsonEncoded',
- ];
-
- $this->media = $media;
- $this->defaultMedia = $defaultMedia ?? self::class . '::IsEncodedAsType';
- }
-
- /**
- * @param string $name
- * @return callable|ContentMediaType|string|null
- */
- public function resolve($name)
- {
- return $this->media[$name] ?? $this->defaultMedia;
- }
-
- /**
- * @param string $name
- * @param ContentMediaType $media
- * @return ContentMediaTypeResolver
- */
- public function register($name, $media): self
- {
- $this->media[$name] = $media;
-
- return $this;
- }
-
- /**
- * @param string $name
- * @param callable $media
- * @return ContentMediaTypeResolver
- */
- public function registerCallable($name, $media): self
- {
- $this->media[$name] = $media;
-
- return $this;
- }
-
- /**
- * @param string $name
- * @return bool
- */
- public function unregister($name): bool
- {
- if (isset($this->media[$name])) {
- unset($this->media[$name]);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * @param callable|ContentMediaType|null $handler
- * @return ContentMediaTypeResolver
- */
- public function setDefaultHandler($handler): self
- {
- $this->defaultMedia = $handler;
-
- return $this;
- }
-
- public function __serialize(): array
- {
- return [
- 'media' => $this->media,
- 'defaultMedia' => $this->defaultMedia,
- ];
- }
-
- public function __unserialize(array $data)
- {
- $this->media = $data['media'];
- $this->defaultMedia = $data['defaultMedia'];
- }
-
- /**
- * @param string $value
- * @param string $type
- */
- public static function IsJsonEncoded($value,
- /** @noinspection PhpUnusedParameterInspection */ $type): bool
- {
- json_decode($value);
-
- return json_last_error() === JSON_ERROR_NONE;
- }
-
- /**
- * @param string $value
- * @param string $type
- */
- public static function IsEncodedAsType($value, $type): bool
- {
- /** @var finfo|null|bool $finfo */
- static $finfo = false;
-
- if ($finfo === false) {
- if (!class_exists(finfo::class)) {
- $finfo = null;
- return false;
- }
- $finfo = new finfo(FILEINFO_MIME_TYPE);
- } elseif (!$finfo) {
- return false;
- }
-
- $r = $finfo->buffer($value);
-
- return $r == $type || $r == 'application/x-empty';
- }
+class ContentMediaTypeResolver {
+
+ /** @var callable[]|ContentMediaType[] */
+ protected $media;
+
+ /** @var callable|null|ContentMediaType */
+ protected $defaultMedia = null;
+
+ /**
+ * @param callable[]|ContentMediaType[] $media
+ * @param callable|ContentMediaType|null $defaultMedia
+ */
+ public function __construct( array $media = array(), $defaultMedia = null ) {
+ $media += array(
+ 'application/json' => self::class . '::IsJsonEncoded',
+ );
+
+ $this->media = $media;
+ $this->defaultMedia = $defaultMedia ?? self::class . '::IsEncodedAsType';
+ }
+
+ /**
+ * @param string $name
+ * @return callable|ContentMediaType|string|null
+ */
+ public function resolve( $name ) {
+ return $this->media[ $name ] ?? $this->defaultMedia;
+ }
+
+ /**
+ * @param string $name
+ * @param ContentMediaType $media
+ * @return ContentMediaTypeResolver
+ */
+ public function register( $name, $media ): self {
+ $this->media[ $name ] = $media;
+
+ return $this;
+ }
+
+ /**
+ * @param string $name
+ * @param callable $media
+ * @return ContentMediaTypeResolver
+ */
+ public function registerCallable( $name, $media ): self {
+ $this->media[ $name ] = $media;
+
+ return $this;
+ }
+
+ /**
+ * @param string $name
+ * @return bool
+ */
+ public function unregister( $name ): bool {
+ if ( isset( $this->media[ $name ] ) ) {
+ unset( $this->media[ $name ] );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param callable|ContentMediaType|null $handler
+ * @return ContentMediaTypeResolver
+ */
+ public function setDefaultHandler( $handler ): self {
+ $this->defaultMedia = $handler;
+
+ return $this;
+ }
+
+ public function __serialize(): array {
+ return array(
+ 'media' => $this->media,
+ 'defaultMedia' => $this->defaultMedia,
+ );
+ }
+
+ public function __unserialize( array $data ) {
+ $this->media = $data['media'];
+ $this->defaultMedia = $data['defaultMedia'];
+ }
+
+ /**
+ * @param string $value
+ * @param string $type
+ */
+ public static function IsJsonEncoded(
+ $value,
+ /** @noinspection PhpUnusedParameterInspection */ $type
+ ): bool {
+ json_decode( $value );
+
+ return json_last_error() === JSON_ERROR_NONE;
+ }
+
+ /**
+ * @param string $value
+ * @param string $type
+ */
+ public static function IsEncodedAsType( $value, $type ): bool {
+ /** @var finfo|null|bool $finfo */
+ static $finfo = false;
+
+ if ( $finfo === false ) {
+ if ( ! class_exists( finfo::class ) ) {
+ $finfo = null;
+ return false;
+ }
+ $finfo = new finfo( FILEINFO_MIME_TYPE );
+ } elseif ( ! $finfo ) {
+ return false;
+ }
+
+ $r = $finfo->buffer( $value );
+
+ return $r == $type || $r == 'application/x-empty';
+ }
}
diff --git a/src/opis/json-schema/src/Resolvers/FilterResolver.php b/src/opis/json-schema/src/Resolvers/FilterResolver.php
index 4a670dc7..accdfb87 100644
--- a/src/opis/json-schema/src/Resolvers/FilterResolver.php
+++ b/src/opis/json-schema/src/Resolvers/FilterResolver.php
@@ -1,5 +1,6 @@
separator = $ns_separator;
- $this->defaultNS = $default_ns;
-
- $this->registerDefaultFilters();
- }
-
- /**
- * You can override this to add/remove default filters
- */
- protected function registerDefaultFilters()
- {
- $this->registerMultipleTypes("schema-exists", new SchemaExistsFilter());
- $this->registerMultipleTypes("data-exists", new DataExistsFilter());
- $this->registerMultipleTypes("global-exists", new GlobalVarExistsFilter());
- $this->registerMultipleTypes("slot-exists", new SlotExistsFilter());
- $this->registerMultipleTypes("filter-exists", new FilterExistsFilter());
- $this->registerMultipleTypes("format-exists", new FormatExistsFilter());
-
- $cls = DateTimeFilters::class . "::";
- $this->registerCallable("string", "min-date", $cls . "MinDate");
- $this->registerCallable("string", "max-date", $cls . "MaxDate");
- $this->registerCallable("string", "not-date", $cls . "NotDate");
- $this->registerCallable("string", "min-time", $cls . "MinTime");
- $this->registerCallable("string", "max-time", $cls . "MaxTime");
- $this->registerCallable("string", "min-datetime", $cls . "MinDateTime");
- $this->registerCallable("string", "max-datetime", $cls . "MaxDateTime");
-
- $cls = CommonFilters::class . "::";
- $this->registerCallable("string", "regex", $cls . "Regex");
- $this->registerMultipleTypes("equals", $cls . "Equals");
- }
-
-
- /**
- * @param string $name
- * @param string $type
- * @return Filter|callable|null
- */
- public function resolve($name, $type)
- {
- list($ns, $name) = $this->parseName($name);
-
- if (isset($this->filters[$ns][$name])) {
- return $this->filters[$ns][$name][$type] ?? null;
- }
-
- if (!isset($this->ns[$ns])) {
- return null;
- }
-
- $this->filters[$ns][$name] = $this->ns[$ns]->resolveAll($name);
-
- return $this->filters[$ns][$name][$type] ?? null;
- }
-
- /**
- * @param string $name
- * @return Filter[]|callable[]|null
- */
- public function resolveAll($name)
- {
- list($ns, $name) = $this->parseName($name);
-
- if (isset($this->filters[$ns][$name])) {
- return $this->filters[$ns][$name];
- }
-
- if (!isset($this->ns[$ns])) {
- return null;
- }
-
- return $this->filters[$ns][$name] = $this->ns[$ns]->resolveAll($name);
- }
-
- /**
- * @param string $type
- * @param string $name
- * @param Filter $filter
- * @return FilterResolver
- */
- public function register($type, $name, $filter): self
- {
- list($ns, $name) = $this->parseName($name);
-
- $this->filters[$ns][$name][$type] = $filter;
-
- return $this;
- }
-
- /**
- * @param string $name
- * @param string|null $type
- * @return bool
- */
- public function unregister($name, $type = null): bool
- {
- list($ns, $name) = $this->parseName($name);
- if (!isset($this->filters[$ns][$name])) {
- return false;
- }
-
- if ($type === null) {
- unset($this->filters[$ns][$name]);
-
- return true;
- }
-
- if (isset($this->filters[$ns][$name][$type])) {
- unset($this->filters[$ns][$name][$type]);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * @param string $name
- * @param callable|Filter $filter
- * @param array|null $types
- * @return FilterResolver
- */
- public function registerMultipleTypes($name, $filter, $types = null): self
- {
- list($ns, $name) = $this->parseName($name);
-
- $types = $types ?? Helper::JSON_TYPES;
-
- foreach ($types as $type) {
- $this->filters[$ns][$name][$type] = $filter;
- }
-
- return $this;
- }
-
- /**
- * @param string $type
- * @param string $name
- * @param callable $filter
- * @return FilterResolver
- */
- public function registerCallable($type, $name, $filter): self
- {
- list($ns, $name) = $this->parseName($name);
-
- $this->filters[$ns][$name][$type] = $filter;
-
- return $this;
- }
-
- /**
- * @param string $ns
- * @param FilterResolver $resolver
- * @return FilterResolver
- */
- public function registerNS($ns, $resolver): self
- {
- $this->ns[$ns] = $resolver;
-
- return $this;
- }
-
- /**
- * @param string $ns
- * @return bool
- */
- public function unregisterNS($ns): bool
- {
- if (isset($this->filters[$ns])) {
- unset($this->filters[$ns]);
- unset($this->ns[$ns]);
-
- return true;
- }
-
- if (isset($this->ns[$ns])) {
- unset($this->ns[$ns]);
-
- return true;
- }
-
- return false;
- }
-
- public function __serialize(): array
- {
- return [
- 'separator' => $this->separator,
- 'defaultNS' => $this->defaultNS,
- 'ns' => $this->ns,
- 'filters' => $this->filters,
- ];
- }
-
- public function __unserialize(array $data)
- {
- $this->separator = $data['separator'];
- $this->defaultNS = $data['defaultNS'];
- $this->ns = $data['ns'];
- $this->filters = $data['filters'];
- }
-
- /**
- * @param string $name
- * @return array
- */
- protected function parseName($name): array
- {
- $name = strtolower($name);
-
- if (strpos($name, $this->separator) === false) {
- return [$this->defaultNS, $name];
- }
-
- return explode($this->separator, $name, 2);
- }
+ DataExistsFilter,
+ DateTimeFilters,
+ FilterExistsFilter,
+ FormatExistsFilter,
+ SchemaExistsFilter,
+ SlotExistsFilter,
+ GlobalVarExistsFilter};
+
+class FilterResolver {
+
+ /** @var Filter[][][] */
+ protected $filters = array();
+
+ /** @var FilterResolver[] */
+ protected $ns = array();
+
+ /**
+ * @var string
+ */
+ protected $separator;
+
+ /**
+ * @var string
+ */
+ protected $defaultNS;
+
+ /**
+ * FilterResolver constructor.
+ *
+ * @param string $ns_separator
+ * @param string $default_ns
+ */
+ public function __construct( string $ns_separator = '::', string $default_ns = 'default' ) {
+ $this->separator = $ns_separator;
+ $this->defaultNS = $default_ns;
+
+ $this->registerDefaultFilters();
+ }
+
+ /**
+ * You can override this to add/remove default filters
+ */
+ protected function registerDefaultFilters() {
+ $this->registerMultipleTypes( 'schema-exists', new SchemaExistsFilter() );
+ $this->registerMultipleTypes( 'data-exists', new DataExistsFilter() );
+ $this->registerMultipleTypes( 'global-exists', new GlobalVarExistsFilter() );
+ $this->registerMultipleTypes( 'slot-exists', new SlotExistsFilter() );
+ $this->registerMultipleTypes( 'filter-exists', new FilterExistsFilter() );
+ $this->registerMultipleTypes( 'format-exists', new FormatExistsFilter() );
+
+ $cls = DateTimeFilters::class . '::';
+ $this->registerCallable( 'string', 'min-date', $cls . 'MinDate' );
+ $this->registerCallable( 'string', 'max-date', $cls . 'MaxDate' );
+ $this->registerCallable( 'string', 'not-date', $cls . 'NotDate' );
+ $this->registerCallable( 'string', 'min-time', $cls . 'MinTime' );
+ $this->registerCallable( 'string', 'max-time', $cls . 'MaxTime' );
+ $this->registerCallable( 'string', 'min-datetime', $cls . 'MinDateTime' );
+ $this->registerCallable( 'string', 'max-datetime', $cls . 'MaxDateTime' );
+
+ $cls = CommonFilters::class . '::';
+ $this->registerCallable( 'string', 'regex', $cls . 'Regex' );
+ $this->registerMultipleTypes( 'equals', $cls . 'Equals' );
+ }
+
+
+ /**
+ * @param string $name
+ * @param string $type
+ * @return Filter|callable|null
+ */
+ public function resolve( $name, $type ) {
+ list($ns, $name) = $this->parseName( $name );
+
+ if ( isset( $this->filters[ $ns ][ $name ] ) ) {
+ return $this->filters[ $ns ][ $name ][ $type ] ?? null;
+ }
+
+ if ( ! isset( $this->ns[ $ns ] ) ) {
+ return null;
+ }
+
+ $this->filters[ $ns ][ $name ] = $this->ns[ $ns ]->resolveAll( $name );
+
+ return $this->filters[ $ns ][ $name ][ $type ] ?? null;
+ }
+
+ /**
+ * @param string $name
+ * @return Filter[]|callable[]|null
+ */
+ public function resolveAll( $name ) {
+ list($ns, $name) = $this->parseName( $name );
+
+ if ( isset( $this->filters[ $ns ][ $name ] ) ) {
+ return $this->filters[ $ns ][ $name ];
+ }
+
+ if ( ! isset( $this->ns[ $ns ] ) ) {
+ return null;
+ }
+
+ return $this->filters[ $ns ][ $name ] = $this->ns[ $ns ]->resolveAll( $name );
+ }
+
+ /**
+ * @param string $type
+ * @param string $name
+ * @param Filter $filter
+ * @return FilterResolver
+ */
+ public function register( $type, $name, $filter ): self {
+ list($ns, $name) = $this->parseName( $name );
+
+ $this->filters[ $ns ][ $name ][ $type ] = $filter;
+
+ return $this;
+ }
+
+ /**
+ * @param string $name
+ * @param string|null $type
+ * @return bool
+ */
+ public function unregister( $name, $type = null ): bool {
+ list($ns, $name) = $this->parseName( $name );
+ if ( ! isset( $this->filters[ $ns ][ $name ] ) ) {
+ return false;
+ }
+
+ if ( $type === null ) {
+ unset( $this->filters[ $ns ][ $name ] );
+
+ return true;
+ }
+
+ if ( isset( $this->filters[ $ns ][ $name ][ $type ] ) ) {
+ unset( $this->filters[ $ns ][ $name ][ $type ] );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $name
+ * @param callable|Filter $filter
+ * @param array|null $types
+ * @return FilterResolver
+ */
+ public function registerMultipleTypes( $name, $filter, $types = null ): self {
+ list($ns, $name) = $this->parseName( $name );
+
+ $types = $types ?? Helper::JSON_TYPES;
+
+ foreach ( $types as $type ) {
+ $this->filters[ $ns ][ $name ][ $type ] = $filter;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $type
+ * @param string $name
+ * @param callable $filter
+ * @return FilterResolver
+ */
+ public function registerCallable( $type, $name, $filter ): self {
+ list($ns, $name) = $this->parseName( $name );
+
+ $this->filters[ $ns ][ $name ][ $type ] = $filter;
+
+ return $this;
+ }
+
+ /**
+ * @param string $ns
+ * @param FilterResolver $resolver
+ * @return FilterResolver
+ */
+ public function registerNS( $ns, $resolver ): self {
+ $this->ns[ $ns ] = $resolver;
+
+ return $this;
+ }
+
+ /**
+ * @param string $ns
+ * @return bool
+ */
+ public function unregisterNS( $ns ): bool {
+ if ( isset( $this->filters[ $ns ] ) ) {
+ unset( $this->filters[ $ns ] );
+ unset( $this->ns[ $ns ] );
+
+ return true;
+ }
+
+ if ( isset( $this->ns[ $ns ] ) ) {
+ unset( $this->ns[ $ns ] );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public function __serialize(): array {
+ return array(
+ 'separator' => $this->separator,
+ 'defaultNS' => $this->defaultNS,
+ 'ns' => $this->ns,
+ 'filters' => $this->filters,
+ );
+ }
+
+ public function __unserialize( array $data ) {
+ $this->separator = $data['separator'];
+ $this->defaultNS = $data['defaultNS'];
+ $this->ns = $data['ns'];
+ $this->filters = $data['filters'];
+ }
+
+ /**
+ * @param string $name
+ * @return array
+ */
+ protected function parseName( $name ): array {
+ $name = strtolower( $name );
+
+ if ( strpos( $name, $this->separator ) === false ) {
+ return array( $this->defaultNS, $name );
+ }
+
+ return explode( $this->separator, $name, 2 );
+ }
}
diff --git a/src/opis/json-schema/src/Resolvers/FormatResolver.php b/src/opis/json-schema/src/Resolvers/FormatResolver.php
index 0a259ceb..e8a79aaa 100644
--- a/src/opis/json-schema/src/Resolvers/FormatResolver.php
+++ b/src/opis/json-schema/src/Resolvers/FormatResolver.php
@@ -1,5 +1,6 @@
formats = [
- 'string' => [
- 'date' => DateTimeFormats::class . '::date',
- 'time' => DateTimeFormats::class . '::time',
- 'date-time' => DateTimeFormats::class . '::dateTime',
- 'duration' => DateTimeFormats::class . '::duration',
-
- 'uri' => UriFormats::class . '::uri',
- 'uri-reference' => UriFormats::class . '::uriReference',
- 'uri-template' => UriFormats::class . '::uriTemplate',
-
- 'regex' => Helper::class . '::isValidPattern',
- 'ipv4' => MiscFormats::class . '::ipv4',
- 'ipv6' => MiscFormats::class . '::ipv6',
- 'uuid' => MiscFormats::class . '::uuid',
-
- 'email' => MiscFormats::class . '::email',
- 'hostname' => Uri::class . '::isValidHost',
-
- 'json-pointer' => JsonPointer::class . '::isAbsolutePointer',
- 'relative-json-pointer' => JsonPointer::class . '::isRelativePointer',
-
- 'idn-hostname' => IriFormats::class . '::idnHostname',
- 'idn-email' => IriFormats::class . '::idnEmail',
- 'iri' => IriFormats::class . '::iri',
- 'iri-reference' => IriFormats::class . '::iriReference',
- ],
- ];
- }
-
- /**
- * @param string $name
- * @param string $type
- * @return callable|Format|null
- */
- public function resolve($name, $type)
- {
- return $this->formats[$type][$name] ?? null;
- }
-
- /**
- * @param string $name
- * @return Format[]|callable[]|null
- */
- public function resolveAll($name)
- {
- $list = null;
-
- foreach ($this->formats as $type => $items) {
- if (isset($items[$name])) {
- $list[$type] = $items[$name];
- }
- }
-
- return $list;
- }
-
- /**
- * @param string $type
- * @param string $name
- * @param Format $format
- * @return FormatResolver
- */
- public function register($type, $name, $format): self
- {
- $this->formats[$type][$name] = $format;
-
- return $this;
- }
-
- /**
- * @param string $type
- * @param string $name
- * @param callable $format
- * @return FormatResolver
- */
- public function registerCallable($type, $name, $format): self
- {
- $this->formats[$type][$name] = $format;
-
- return $this;
- }
-
- /**
- * @param string $type
- * @param string $name
- * @return bool
- */
- public function unregister($type, $name): bool
- {
- if (isset($this->formats[$type][$name])) {
- unset($this->formats[$type][$name]);
-
- return true;
- }
-
- return false;
- }
-
- public function __serialize(): array
- {
- return ['formats' => $this->formats];
- }
-
- public function __unserialize(array $data)
- {
- $this->formats = $data['formats'];
- }
+class FormatResolver {
+
+ /** @var Format[][]|callable[][] */
+ protected $formats = array();
+
+ /**
+ * FormatResolver constructor.
+ */
+ public function __construct() {
+ $this->formats = array(
+ 'string' => array(
+ 'date' => DateTimeFormats::class . '::date',
+ 'time' => DateTimeFormats::class . '::time',
+ 'date-time' => DateTimeFormats::class . '::dateTime',
+ 'duration' => DateTimeFormats::class . '::duration',
+
+ 'uri' => UriFormats::class . '::uri',
+ 'uri-reference' => UriFormats::class . '::uriReference',
+ 'uri-template' => UriFormats::class . '::uriTemplate',
+
+ 'regex' => Helper::class . '::isValidPattern',
+ 'ipv4' => MiscFormats::class . '::ipv4',
+ 'ipv6' => MiscFormats::class . '::ipv6',
+ 'uuid' => MiscFormats::class . '::uuid',
+
+ 'email' => MiscFormats::class . '::email',
+ 'hostname' => Uri::class . '::isValidHost',
+
+ 'json-pointer' => JsonPointer::class . '::isAbsolutePointer',
+ 'relative-json-pointer' => JsonPointer::class . '::isRelativePointer',
+
+ 'idn-hostname' => IriFormats::class . '::idnHostname',
+ 'idn-email' => IriFormats::class . '::idnEmail',
+ 'iri' => IriFormats::class . '::iri',
+ 'iri-reference' => IriFormats::class . '::iriReference',
+ ),
+ );
+ }
+
+ /**
+ * @param string $name
+ * @param string $type
+ * @return callable|Format|null
+ */
+ public function resolve( $name, $type ) {
+ return $this->formats[ $type ][ $name ] ?? null;
+ }
+
+ /**
+ * @param string $name
+ * @return Format[]|callable[]|null
+ */
+ public function resolveAll( $name ) {
+ $list = null;
+
+ foreach ( $this->formats as $type => $items ) {
+ if ( isset( $items[ $name ] ) ) {
+ $list[ $type ] = $items[ $name ];
+ }
+ }
+
+ return $list;
+ }
+
+ /**
+ * @param string $type
+ * @param string $name
+ * @param Format $format
+ * @return FormatResolver
+ */
+ public function register( $type, $name, $format ): self {
+ $this->formats[ $type ][ $name ] = $format;
+
+ return $this;
+ }
+
+ /**
+ * @param string $type
+ * @param string $name
+ * @param callable $format
+ * @return FormatResolver
+ */
+ public function registerCallable( $type, $name, $format ): self {
+ $this->formats[ $type ][ $name ] = $format;
+
+ return $this;
+ }
+
+ /**
+ * @param string $type
+ * @param string $name
+ * @return bool
+ */
+ public function unregister( $type, $name ): bool {
+ if ( isset( $this->formats[ $type ][ $name ] ) ) {
+ unset( $this->formats[ $type ][ $name ] );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public function __serialize(): array {
+ return array( 'formats' => $this->formats );
+ }
+
+ public function __unserialize( array $data ) {
+ $this->formats = $data['formats'];
+ }
}
diff --git a/src/opis/json-schema/src/Resolvers/SchemaResolver.php b/src/opis/json-schema/src/Resolvers/SchemaResolver.php
index cf6b625f..97677786 100644
--- a/src/opis/json-schema/src/Resolvers/SchemaResolver.php
+++ b/src/opis/json-schema/src/Resolvers/SchemaResolver.php
@@ -1,5 +1,6 @@
isAbsolute()) {
- return null;
- }
-
- $scheme = $uri->scheme();
- if (isset($this->protocols[$scheme])) {
- return ($this->protocols[$scheme])($uri);
- }
-
- $id = (string) $uri;
- if (isset($this->raw[$id])) {
- return $this->raw[$id];
- }
-
- $path = $this->resolvePath($uri);
-
- if ($path === null || !is_file($path)) {
- return null;
- }
-
- $data = file_get_contents($path);
- if (!is_string($data)) {
- return null;
- }
-
- $data = json_decode($data, false);
-
- return $data;
- }
-
- /**
- * @param bool|object|string $schema
- * @param string|null $id
- * @return bool
- */
- public function registerRaw($schema, $id = null): bool
- {
- if (is_string($schema)) {
- $schema = json_decode($schema, false);
- }
-
- if ($id !== null && strpos($id, '#') === false) {
- $id .= '#';
- }
-
- if (is_bool($schema)) {
- if ($id === null) {
- return false;
- }
- $this->raw[$id] = $schema;
- return true;
- }
-
- if (!is_object($schema)) {
- return false;
- }
-
-
- if ($id === null) {
- if (!isset($schema->{'$id'}) || !is_string($schema->{'$id'})) {
- return false;
- }
-
- $id = $schema->{'$id'};
- if (strpos($id, '#') === false) {
- $id .= '#';
- }
- }
-
- $this->raw[$id] = $schema;
-
- return true;
- }
-
- /**
- * @param string $id
- * @return bool
- */
- public function unregisterRaw($id): bool
- {
- if (strpos($id, '#') === false) {
- $id .= '#';
- }
-
- if (isset($this->raw[$id])) {
- unset($this->raw[$id]);
- return true;
- }
-
- return false;
- }
-
- /**
- * @param string $id
- * @param string $file
- * @return SchemaResolver
- */
- public function registerFile($id, $file): self
- {
- if (strpos($id, '#') === false) {
- $id .= '#';
- }
-
- $this->files[$id] = $file;
-
- return $this;
- }
-
- /**
- * @param string $id
- * @return bool
- */
- public function unregisterFile($id): bool
- {
- if (strpos($id, '#') === false) {
- $id .= '#';
- }
-
- if (!isset($this->files[$id])) {
- return false;
- }
-
- unset($this->files[$id]);
-
- return true;
- }
-
- /**
- * @param string $scheme
- * @param callable $handler
- * @return SchemaResolver
- */
- public function registerProtocol($scheme, $handler): self
- {
- $this->protocols[$scheme] = $handler;
-
- return $this;
- }
-
- /**
- * @param string $scheme
- * @return bool
- */
- public function unregisterProtocol($scheme): bool
- {
- if (isset($this->protocols[$scheme])) {
- unset($this->protocols[$scheme]);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * @param string $scheme
- * @param string $host
- * @param string|null $dir
- * @return SchemaResolver
- */
- public function registerProtocolDir($scheme, $host, $dir): self
- {
- if ($dir === null) {
- unset($this->dirs[$scheme][$host]);
- } else {
- $this->dirs[$scheme][$host] = rtrim($dir, '/');
- }
-
- return $this;
- }
-
- /**
- * @param string $scheme
- * @return bool
- */
- public function unregisterProtocolDirs($scheme): bool
- {
- if (isset($this->dirs[$scheme])) {
- unset($this->dirs[$scheme]);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * @param string $prefix
- * @param string $dir
- * @return SchemaResolver
- */
- public function registerPrefix($prefix, $dir): self
- {
- $this->prefixes[$prefix] = rtrim($dir, '/');
-
- // Sort
- uksort($this->prefixes, [$this, 'sortPrefixKeys']);
-
- return $this;
- }
-
- /**
- * @param string $prefix
- * @return SchemaResolver
- */
- public function unregisterPrefix($prefix): self
- {
- if (isset($this->prefixes[$prefix])) {
- unset($this->prefixes[$prefix]);
- // Sort
- uksort($this->prefixes, [$this, 'sortPrefixKeys']);
- }
-
- return $this;
- }
-
-
- public function __serialize(): array
- {
- return [
- 'raw' => $this->raw,
- 'protocols' => $this->protocols,
- 'prefixes' => $this->prefixes,
- 'dirs' => $this->dirs,
- ];
- }
-
- public function __unserialize(array $data)
- {
- $this->raw = $data['raw'];
- $this->protocols = $data['protocols'];
- $this->prefixes = $data['prefixes'];
- $this->dirs = $data['dirs'];
- }
-
- /**
- * @param string $a
- * @param string $b
- * @return int
- */
- protected function sortPrefixKeys($a, $b): int
- {
- $la = strlen($a);
- $lb = strlen($b);
-
- if ($lb > $la) {
- return 1;
- }
-
- if ($lb === $la) {
- return $b < $a ? 1 : ($b === $a ? 0 : -1);
- }
-
- return -1;
- }
-
- /**
- * @param Uri $uri
- * @return string|null
- */
- protected function resolvePath($uri)
- {
- $id = (string)$uri;
-
- if (isset($this->files[$id])) {
- return $this->files[$id];
- }
-
- $scheme = $uri->scheme();
-
- if (isset($this->dirs[$scheme])) {
- $host = (string)$uri->host();
- if (isset($this->dirs[$scheme][$host])) {
- return $this->dirs[$scheme][$host] . '/' . ltrim($uri->path(), '/');
- }
- unset($host);
- }
-
- $path = null;
- foreach ($this->prefixes as $prefix => $dir) {
- if ($prefix === '' || strpos($id, $prefix) === 0) {
- $path = substr($id, strlen($prefix));
- if ($path === false || $path === '') {
- $path = null;
- continue;
- }
- $path = Uri::parseComponents($path);
- if ($path && isset($path['path'])) {
- $path = $dir . '/' . ltrim($path['path'], '/');
- break;
- }
- $path = null;
- }
- }
-
- return $path;
- }
+class SchemaResolver {
+
+ /** @var bool[]|object[] */
+ protected $raw = array();
+
+ /** @var string[] */
+ protected $files = array();
+
+ /** @var callable[] */
+ protected $protocols = array();
+
+ /** @var array */
+ protected $prefixes = array();
+
+ /** @var array */
+ protected $dirs = array();
+
+ /**
+ * @param Uri $uri
+ * @return bool|mixed|object|null
+ */
+ public function resolve( $uri ) {
+ if ( ! $uri->isAbsolute() ) {
+ return null;
+ }
+
+ $scheme = $uri->scheme();
+ if ( isset( $this->protocols[ $scheme ] ) ) {
+ return ( $this->protocols[ $scheme ] )( $uri );
+ }
+
+ $id = (string) $uri;
+ if ( isset( $this->raw[ $id ] ) ) {
+ return $this->raw[ $id ];
+ }
+
+ $path = $this->resolvePath( $uri );
+
+ if ( $path === null || ! is_file( $path ) ) {
+ return null;
+ }
+
+ $data = file_get_contents( $path );
+ if ( ! is_string( $data ) ) {
+ return null;
+ }
+
+ $data = json_decode( $data, false );
+
+ return $data;
+ }
+
+ /**
+ * @param bool|object|string $schema
+ * @param string|null $id
+ * @return bool
+ */
+ public function registerRaw( $schema, $id = null ): bool {
+ if ( is_string( $schema ) ) {
+ $schema = json_decode( $schema, false );
+ }
+
+ if ( $id !== null && strpos( $id, '#' ) === false ) {
+ $id .= '#';
+ }
+
+ if ( is_bool( $schema ) ) {
+ if ( $id === null ) {
+ return false;
+ }
+ $this->raw[ $id ] = $schema;
+ return true;
+ }
+
+ if ( ! is_object( $schema ) ) {
+ return false;
+ }
+
+ if ( $id === null ) {
+ if ( ! isset( $schema->{'$id'} ) || ! is_string( $schema->{'$id'} ) ) {
+ return false;
+ }
+
+ $id = $schema->{'$id'};
+ if ( strpos( $id, '#' ) === false ) {
+ $id .= '#';
+ }
+ }
+
+ $this->raw[ $id ] = $schema;
+
+ return true;
+ }
+
+ /**
+ * @param string $id
+ * @return bool
+ */
+ public function unregisterRaw( $id ): bool {
+ if ( strpos( $id, '#' ) === false ) {
+ $id .= '#';
+ }
+
+ if ( isset( $this->raw[ $id ] ) ) {
+ unset( $this->raw[ $id ] );
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $id
+ * @param string $file
+ * @return SchemaResolver
+ */
+ public function registerFile( $id, $file ): self {
+ if ( strpos( $id, '#' ) === false ) {
+ $id .= '#';
+ }
+
+ $this->files[ $id ] = $file;
+
+ return $this;
+ }
+
+ /**
+ * @param string $id
+ * @return bool
+ */
+ public function unregisterFile( $id ): bool {
+ if ( strpos( $id, '#' ) === false ) {
+ $id .= '#';
+ }
+
+ if ( ! isset( $this->files[ $id ] ) ) {
+ return false;
+ }
+
+ unset( $this->files[ $id ] );
+
+ return true;
+ }
+
+ /**
+ * @param string $scheme
+ * @param callable $handler
+ * @return SchemaResolver
+ */
+ public function registerProtocol( $scheme, $handler ): self {
+ $this->protocols[ $scheme ] = $handler;
+
+ return $this;
+ }
+
+ /**
+ * @param string $scheme
+ * @return bool
+ */
+ public function unregisterProtocol( $scheme ): bool {
+ if ( isset( $this->protocols[ $scheme ] ) ) {
+ unset( $this->protocols[ $scheme ] );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $scheme
+ * @param string $host
+ * @param string|null $dir
+ * @return SchemaResolver
+ */
+ public function registerProtocolDir( $scheme, $host, $dir ): self {
+ if ( $dir === null ) {
+ unset( $this->dirs[ $scheme ][ $host ] );
+ } else {
+ $this->dirs[ $scheme ][ $host ] = rtrim( $dir, '/' );
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $scheme
+ * @return bool
+ */
+ public function unregisterProtocolDirs( $scheme ): bool {
+ if ( isset( $this->dirs[ $scheme ] ) ) {
+ unset( $this->dirs[ $scheme ] );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $prefix
+ * @param string $dir
+ * @return SchemaResolver
+ */
+ public function registerPrefix( $prefix, $dir ): self {
+ $this->prefixes[ $prefix ] = rtrim( $dir, '/' );
+
+ // Sort
+ uksort( $this->prefixes, array( $this, 'sortPrefixKeys' ) );
+
+ return $this;
+ }
+
+ /**
+ * @param string $prefix
+ * @return SchemaResolver
+ */
+ public function unregisterPrefix( $prefix ): self {
+ if ( isset( $this->prefixes[ $prefix ] ) ) {
+ unset( $this->prefixes[ $prefix ] );
+ // Sort
+ uksort( $this->prefixes, array( $this, 'sortPrefixKeys' ) );
+ }
+
+ return $this;
+ }
+
+
+ public function __serialize(): array {
+ return array(
+ 'raw' => $this->raw,
+ 'protocols' => $this->protocols,
+ 'prefixes' => $this->prefixes,
+ 'dirs' => $this->dirs,
+ );
+ }
+
+ public function __unserialize( array $data ) {
+ $this->raw = $data['raw'];
+ $this->protocols = $data['protocols'];
+ $this->prefixes = $data['prefixes'];
+ $this->dirs = $data['dirs'];
+ }
+
+ /**
+ * @param string $a
+ * @param string $b
+ * @return int
+ */
+ protected function sortPrefixKeys( $a, $b ): int {
+ $la = strlen( $a );
+ $lb = strlen( $b );
+
+ if ( $lb > $la ) {
+ return 1;
+ }
+
+ if ( $lb === $la ) {
+ return $b < $a ? 1 : ( $b === $a ? 0 : -1 );
+ }
+
+ return -1;
+ }
+
+ /**
+ * @param Uri $uri
+ * @return string|null
+ */
+ protected function resolvePath( $uri ) {
+ $id = (string) $uri;
+
+ if ( isset( $this->files[ $id ] ) ) {
+ return $this->files[ $id ];
+ }
+
+ $scheme = $uri->scheme();
+
+ if ( isset( $this->dirs[ $scheme ] ) ) {
+ $host = (string) $uri->host();
+ if ( isset( $this->dirs[ $scheme ][ $host ] ) ) {
+ return $this->dirs[ $scheme ][ $host ] . '/' . ltrim( $uri->path(), '/' );
+ }
+ unset( $host );
+ }
+
+ $path = null;
+ foreach ( $this->prefixes as $prefix => $dir ) {
+ if ( $prefix === '' || strpos( $id, $prefix ) === 0 ) {
+ $path = substr( $id, strlen( $prefix ) );
+ if ( $path === false || $path === '' ) {
+ $path = null;
+ continue;
+ }
+ $path = Uri::parseComponents( $path );
+ if ( $path && isset( $path['path'] ) ) {
+ $path = $dir . '/' . ltrim( $path['path'], '/' );
+ break;
+ }
+ $path = null;
+ }
+ }
+
+ return $path;
+ }
}
diff --git a/src/opis/json-schema/src/Schema.php b/src/opis/json-schema/src/Schema.php
index 821a6a02..9eee17ae 100644
--- a/src/opis/json-schema/src/Schema.php
+++ b/src/opis/json-schema/src/Schema.php
@@ -1,5 +1,6 @@
dataCache = new SplObjectStorage();
- $this->parser = $parser ?? new SchemaParser();
- $this->resolver = $resolver;
- $this->decodeJsonString = $decodeJsonString;
- }
-
- public function baseUri()
- {
- return $this->base;
- }
-
- /**
- * @param \Opis\JsonSchema\Uri|null $uri
- */
- public function setBaseUri($uri): self
- {
- $this->base = $uri;
- return $this;
- }
-
- public function parser(): SchemaParser
- {
- return $this->parser;
- }
-
- /**
- * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
- */
- public function setParser($parser): self
- {
- $this->parser = $parser;
-
- return $this;
- }
-
- public function resolver()
- {
- return $this->resolver;
- }
-
- /**
- * @param \Opis\JsonSchema\Resolvers\SchemaResolver|null $resolver
- */
- public function setResolver($resolver): self
- {
- $this->resolver = $resolver;
-
- return $this;
- }
-
- /**
- * @param object $data
- * @param null $id
- * @param string|null $draft
- * @return Schema
- */
- public function loadObjectSchema($data, $id = null, $draft = null): Schema
- {
- // Check if already loaded
- if ($schema = $this->checkExistingObject($data)) {
- return $schema;
- }
-
- if (!$id) {
- $id = $this->createSchemaId($data);
- }
-
- $handle_id = function (Uri $id) {
- return $this->checkExistingUri($id);
- };
-
- $handle_object = function ($data, Uri $id, string $draft) {
- $this->handleObject($data, $id, null, null, [], $draft, (string)$id);
-
- return $this->checkExistingObject($data);
- };
-
- return $this->parser->parseRootSchema($data, Uri::parse($id, true), $handle_id, $handle_object, $draft);
- }
-
- /**
- * @param bool $data
- * @param null $id
- * @param string|null $draft
- * @return Schema
- */
- public function loadBooleanSchema($data, $id = null, $draft = null): Schema
- {
- if (!$id) {
- $id = $this->createSchemaId($data);
- }
-
- return $this->parser->parseSchema(new SchemaInfo($data, Uri::parse($id, true), null, null, [], $draft));
- }
-
- /**
- * @param Uri $uri
- * @return Schema|null
- */
- public function loadSchemaById($uri)
- {
- if (!$uri->isAbsolute()) {
- if ($this->base === null || !$this->base->isAbsolute()) {
- return null;
- }
- $uri = $this->base->resolveRef($uri);
- }
-
- $fragment = $uri->fragment();
- if ($fragment === null) {
- $uri = Uri::merge($uri, null, true);
- $fragment = '';
- }
-
- $schema = $this->checkExistingUri($uri);
-
- if ($schema !== null) {
- return $schema;
- }
-
- if ($fragment === '') {
- return $this->resolve($uri);
- }
-
- $root = Uri::merge('#', $uri);
-
- // Check if already resolved
- if (($schema = $this->checkExistingUri($root)) === null) {
- // Try to resolve
- if (($schema = $this->resolve($root)) === null) {
- // Schema not found
- return null;
- }
- }
-
- // Resolve json pointer
- if ($fragment !== '' && $schema && $schema->info()->isObject() &&
- ($pointer = JsonPointer::parse($fragment)) && $pointer->isAbsolute()) {
- $object = $pointer->data($schema->info()->data());
- if (is_bool($object)) {
- $schema = $this->loadBooleanSchema($object, $uri, $schema->info()->draft());
- } elseif (is_object($object)) {
- $schema = $this->loadObjectSchema($object, $uri, $schema->info()->draft());
- } else {
- $schema = null;
- }
- if ($schema) {
- $key = $this->cacheKey((string) $uri);
- $this->uriCache[$key] = $schema;
- return $schema;
- }
- }
-
- // Check fragment
- return $this->checkExistingUri($uri);
- }
-
- /**
- * Clears internal cache
- */
- public function clearCache()
- {
- $this->dataCache->removeAll($this->dataCache);
- $this->uriCache = [];
- }
-
- /**
- * @param Uri $uri
- * @return null|Schema
- */
- protected function resolve($uri)
- {
- if ($this->resolver === null) {
- return null;
- }
-
- $data = $this->resolver->resolve($uri);
-
- if ($this->decodeJsonString && is_string($data)) {
- $data = json_decode($data, false);
- }
-
- if (is_bool($data)) {
- $this->handleBoolean($data, $uri, null, null, [], $this->parser->defaultDraftVersion(), (string)$uri);
-
- return $this->checkExistingUri($uri);
- }
-
- if (is_object($data)) {
- if ($data instanceof Schema) {
- return $data;
- }
-
- $this->handleObject($data, $uri, null, null, [], $this->parser->defaultDraftVersion(), (string)$uri);
-
- return $this->checkExistingObject($data);
- }
-
- return null;
- }
-
- /**
- * @param object $data
- * @return null|Schema
- */
- protected function checkExistingObject($data)
- {
- if (!$this->dataCache->contains($data)) {
- return null;
- }
-
- $schema = $this->dataCache[$data];
-
- if ($schema instanceof LazySchema) {
- $schema = $schema->schema();
- $this->dataCache[$data] = $schema;
- } elseif (!($schema instanceof Schema)) {
- $schema = null;
- }
-
- return $schema;
- }
-
- /**
- * @param Uri $uri
- * @return null|Schema
- */
- protected function checkExistingUri($uri)
- {
- if ($uri->fragment() === null || !$uri->isAbsolute()) {
- return null;
- }
-
- $key = $this->cacheKey((string)$uri);
-
- if (!isset($this->uriCache[$key])) {
- return null;
- }
-
- $schema = $this->uriCache[$key];
-
- if (!($schema instanceof Schema)) {
- return $this->uriCache[$key] = $this->checkExistingObject($schema);
- }
-
- if ($schema instanceof LazySchema) {
- $schema = $schema->schema();
- $this->uriCache[$key] = $schema;
- }
-
- return $schema;
- }
-
- /**
- * @param bool $data
- * @param Uri|null $id
- * @param Uri|null $base
- * @param Uri|null $root
- * @param array $path
- * @param string $draft
- * @param string $pointer
- */
- protected function handleBoolean(
- $data,
- $id,
- $base,
- $root,
- $path,
- $draft,
- $pointer
- )
- {
- $key = $this->cacheKey($pointer);
- if (isset($this->uriCache[$key])) {
- return;
- }
-
- $this->uriCache[$key] = $this->parser->parseSchema(new SchemaInfo($data, $id, $base, $root, $path, $draft));
- }
-
- /**
- * @param array $data
- * @param Uri $base
- * @param Uri $root
- * @param array $path
- * @param string $draft
- * @param string $pointer
- */
- protected function handleArray($data, $base, $root, $path, $draft, $pointer)
- {
- foreach ($data as $key => $value) {
- if (!is_int($key)) {
- continue;
- }
-
- if (is_bool($value)) {
- $this->handleBoolean($value, null, $base, $root, array_merge($path, [$key]), $draft,
- $pointer . '/' . $key);
- } elseif (is_array($value)) {
- $this->handleArray($value, $base, $root, array_merge($path, [$key]), $draft, $pointer . '/' . $key);
- } elseif (is_object($value)) {
- $this->handleObject($value, null, $base, $root, array_merge($path, [$key]), $draft,
- $pointer . '/' . $key);
- }
- }
- }
-
- /**
- * @param object $data
- * @param Uri|null $id
- * @param Uri|null $base
- * @param Uri|null $root
- * @param array $path
- * @param string $draft
- * @param string $pointer
- */
- protected function handleObject(
- $data,
- $id,
- $base,
- $root,
- $path,
- $draft,
- $pointer
- )
- {
- $schema_id = $this->parser->parseId($data);
- $schema_anchor = $this->parser->parseAnchor($data, $draft);
- $draft = $this->parser->parseSchemaDraft($data) ?? $draft;
-
- if ($schema_id !== null) {
- $id = Uri::merge($schema_id, $base, true);
- } elseif ($schema_anchor !== null) {
- $id = Uri::merge('#' . $schema_anchor, $base, true);
- }
-
- $lazy = new LazySchema(new SchemaInfo($data, $id, $base, $root, $path, $draft), $this->parser);
-
- if ($id && $id->isAbsolute()) {
- $key = $this->cacheKey((string)$id);
- if (isset($this->uriCache[$key])) {
- throw new DuplicateSchemaIdException($id, $data);
- }
- $this->uriCache[$key] = $lazy;
- }
-
- // When $id and $anchor are both present add a reference to the same lazy object
- if ($schema_id !== null && $schema_anchor !== null) {
- $anchor_id = Uri::merge('#' . $schema_anchor, $id, true);
- $key = $this->cacheKey((string)$anchor_id);
- if (isset($this->uriCache[$key])) {
- throw new DuplicateSchemaIdException($anchor_id, $data);
- }
- $this->uriCache[$key] = $lazy;
- }
-
- $this->dataCache[$data] = $lazy;
- $this->uriCache[$this->cacheKey($pointer)] = $lazy;
-
- if ($root === null) {
- $root = $id;
- }
-
- if ($base === null) {
- $base = $id ?? $root;
- } elseif ($id !== null) {
- $base = $id;
- }
-
- foreach ($data as $key => $value) {
- if (!is_string($key)) {
- continue;
- }
- if (is_bool($value)) {
- $this->handleBoolean($value, null, $base, $root, array_merge($path, [$key]), $draft,
- $pointer . '/' . JsonPointer::encodePath($key));
- } elseif (is_array($value)) {
- $this->handleArray($value, $base, $root, array_merge($path, [$key]), $draft,
- $pointer . '/' . JsonPointer::encodePath($key));
- } elseif (is_object($value)) {
- $this->handleObject($value, null, $base, $root, array_merge($path, [$key]), $draft,
- $pointer . '/' . JsonPointer::encodePath($key));
- }
- }
- }
-
- /**
- * @param string $path
- * @return string
- */
- protected function cacheKey($path): string
- {
- return isset($path[32]) ? md5($path) : $path;
- }
-
- /**
- * @param bool|object $data
- * @return string
- */
- protected function createSchemaId($data): string
- {
- if (is_bool($data)) {
- $data = $data ? 'true' : 'false';
- } else {
- $data = spl_object_hash($data);
- }
-
- return "schema:///{$data}.json";
- }
+class SchemaLoader {
+
+ /** @var Schema[]|object[] */
+ protected $uriCache = array();
+
+ /**
+ * @var \SplObjectStorage
+ */
+ protected $dataCache;
+
+ /**
+ * @var \Opis\JsonSchema\Parsers\SchemaParser
+ */
+ protected $parser;
+
+ /**
+ * @var \Opis\JsonSchema\Resolvers\SchemaResolver|null
+ */
+ protected $resolver;
+
+ /**
+ * @var bool
+ */
+ protected $decodeJsonString = false;
+
+ /**
+ * @var \Opis\JsonSchema\Uri|null
+ */
+ protected $base;
+
+ /**
+ * @param null|SchemaParser $parser
+ * @param null|SchemaResolver $resolver
+ * @param bool $decodeJsonString
+ */
+ public function __construct( $parser = null, $resolver = null, bool $decodeJsonString = true ) {
+ $this->dataCache = new SplObjectStorage();
+ $this->parser = $parser ?? new SchemaParser();
+ $this->resolver = $resolver;
+ $this->decodeJsonString = $decodeJsonString;
+ }
+
+ public function baseUri() {
+ return $this->base;
+ }
+
+ /**
+ * @param \Opis\JsonSchema\Uri|null $uri
+ */
+ public function setBaseUri( $uri ): self {
+ $this->base = $uri;
+ return $this;
+ }
+
+ public function parser(): SchemaParser {
+ return $this->parser;
+ }
+
+ /**
+ * @param \Opis\JsonSchema\Parsers\SchemaParser $parser
+ */
+ public function setParser( $parser ): self {
+ $this->parser = $parser;
+
+ return $this;
+ }
+
+ public function resolver() {
+ return $this->resolver;
+ }
+
+ /**
+ * @param \Opis\JsonSchema\Resolvers\SchemaResolver|null $resolver
+ */
+ public function setResolver( $resolver ): self {
+ $this->resolver = $resolver;
+
+ return $this;
+ }
+
+ /**
+ * @param object $data
+ * @param null $id
+ * @param string|null $draft
+ * @return Schema
+ */
+ public function loadObjectSchema( $data, $id = null, $draft = null ): Schema {
+ // Check if already loaded
+ if ( $schema = $this->checkExistingObject( $data ) ) {
+ return $schema;
+ }
+
+ if ( ! $id ) {
+ $id = $this->createSchemaId( $data );
+ }
+
+ $handle_id = function ( Uri $id ) {
+ return $this->checkExistingUri( $id );
+ };
+
+ $handle_object = function ( $data, Uri $id, string $draft ) {
+ $this->handleObject( $data, $id, null, null, array(), $draft, (string) $id );
+
+ return $this->checkExistingObject( $data );
+ };
+
+ return $this->parser->parseRootSchema( $data, Uri::parse( $id, true ), $handle_id, $handle_object, $draft );
+ }
+
+ /**
+ * @param bool $data
+ * @param null $id
+ * @param string|null $draft
+ * @return Schema
+ */
+ public function loadBooleanSchema( $data, $id = null, $draft = null ): Schema {
+ if ( ! $id ) {
+ $id = $this->createSchemaId( $data );
+ }
+
+ return $this->parser->parseSchema( new SchemaInfo( $data, Uri::parse( $id, true ), null, null, array(), $draft ) );
+ }
+
+ /**
+ * @param Uri $uri
+ * @return Schema|null
+ */
+ public function loadSchemaById( $uri ) {
+ if ( ! $uri->isAbsolute() ) {
+ if ( $this->base === null || ! $this->base->isAbsolute() ) {
+ return null;
+ }
+ $uri = $this->base->resolveRef( $uri );
+ }
+
+ $fragment = $uri->fragment();
+ if ( $fragment === null ) {
+ $uri = Uri::merge( $uri, null, true );
+ $fragment = '';
+ }
+
+ $schema = $this->checkExistingUri( $uri );
+
+ if ( $schema !== null ) {
+ return $schema;
+ }
+
+ if ( $fragment === '' ) {
+ return $this->resolve( $uri );
+ }
+
+ $root = Uri::merge( '#', $uri );
+
+ // Check if already resolved
+ if ( ( $schema = $this->checkExistingUri( $root ) ) === null ) {
+ // Try to resolve
+ if ( ( $schema = $this->resolve( $root ) ) === null ) {
+ // Schema not found
+ return null;
+ }
+ }
+
+ // Resolve json pointer
+ if ( $fragment !== '' && $schema && $schema->info()->isObject() &&
+ ( $pointer = JsonPointer::parse( $fragment ) ) && $pointer->isAbsolute() ) {
+ $object = $pointer->data( $schema->info()->data() );
+ if ( is_bool( $object ) ) {
+ $schema = $this->loadBooleanSchema( $object, $uri, $schema->info()->draft() );
+ } elseif ( is_object( $object ) ) {
+ $schema = $this->loadObjectSchema( $object, $uri, $schema->info()->draft() );
+ } else {
+ $schema = null;
+ }
+ if ( $schema ) {
+ $key = $this->cacheKey( (string) $uri );
+ $this->uriCache[ $key ] = $schema;
+ return $schema;
+ }
+ }
+
+ // Check fragment
+ return $this->checkExistingUri( $uri );
+ }
+
+ /**
+ * Clears internal cache
+ */
+ public function clearCache() {
+ $this->dataCache->removeAll( $this->dataCache );
+ $this->uriCache = array();
+ }
+
+ /**
+ * @param Uri $uri
+ * @return null|Schema
+ */
+ protected function resolve( $uri ) {
+ if ( $this->resolver === null ) {
+ return null;
+ }
+
+ $data = $this->resolver->resolve( $uri );
+
+ if ( $this->decodeJsonString && is_string( $data ) ) {
+ $data = json_decode( $data, false );
+ }
+
+ if ( is_bool( $data ) ) {
+ $this->handleBoolean( $data, $uri, null, null, array(), $this->parser->defaultDraftVersion(), (string) $uri );
+
+ return $this->checkExistingUri( $uri );
+ }
+
+ if ( is_object( $data ) ) {
+ if ( $data instanceof Schema ) {
+ return $data;
+ }
+
+ $this->handleObject( $data, $uri, null, null, array(), $this->parser->defaultDraftVersion(), (string) $uri );
+
+ return $this->checkExistingObject( $data );
+ }
+
+ return null;
+ }
+
+ /**
+ * @param object $data
+ * @return null|Schema
+ */
+ protected function checkExistingObject( $data ) {
+ if ( ! $this->dataCache->contains( $data ) ) {
+ return null;
+ }
+
+ $schema = $this->dataCache[ $data ];
+
+ if ( $schema instanceof LazySchema ) {
+ $schema = $schema->schema();
+ $this->dataCache[ $data ] = $schema;
+ } elseif ( ! ( $schema instanceof Schema ) ) {
+ $schema = null;
+ }
+
+ return $schema;
+ }
+
+ /**
+ * @param Uri $uri
+ * @return null|Schema
+ */
+ protected function checkExistingUri( $uri ) {
+ if ( $uri->fragment() === null || ! $uri->isAbsolute() ) {
+ return null;
+ }
+
+ $key = $this->cacheKey( (string) $uri );
+
+ if ( ! isset( $this->uriCache[ $key ] ) ) {
+ return null;
+ }
+
+ $schema = $this->uriCache[ $key ];
+
+ if ( ! ( $schema instanceof Schema ) ) {
+ return $this->uriCache[ $key ] = $this->checkExistingObject( $schema );
+ }
+
+ if ( $schema instanceof LazySchema ) {
+ $schema = $schema->schema();
+ $this->uriCache[ $key ] = $schema;
+ }
+
+ return $schema;
+ }
+
+ /**
+ * @param bool $data
+ * @param Uri|null $id
+ * @param Uri|null $base
+ * @param Uri|null $root
+ * @param array $path
+ * @param string $draft
+ * @param string $pointer
+ */
+ protected function handleBoolean(
+ $data,
+ $id,
+ $base,
+ $root,
+ $path,
+ $draft,
+ $pointer
+ ) {
+ $key = $this->cacheKey( $pointer );
+ if ( isset( $this->uriCache[ $key ] ) ) {
+ return;
+ }
+
+ $this->uriCache[ $key ] = $this->parser->parseSchema( new SchemaInfo( $data, $id, $base, $root, $path, $draft ) );
+ }
+
+ /**
+ * @param array $data
+ * @param Uri $base
+ * @param Uri $root
+ * @param array $path
+ * @param string $draft
+ * @param string $pointer
+ */
+ protected function handleArray( $data, $base, $root, $path, $draft, $pointer ) {
+ foreach ( $data as $key => $value ) {
+ if ( ! is_int( $key ) ) {
+ continue;
+ }
+
+ if ( is_bool( $value ) ) {
+ $this->handleBoolean(
+ $value,
+ null,
+ $base,
+ $root,
+ array_merge( $path, array( $key ) ),
+ $draft,
+ $pointer . '/' . $key
+ );
+ } elseif ( is_array( $value ) ) {
+ $this->handleArray( $value, $base, $root, array_merge( $path, array( $key ) ), $draft, $pointer . '/' . $key );
+ } elseif ( is_object( $value ) ) {
+ $this->handleObject(
+ $value,
+ null,
+ $base,
+ $root,
+ array_merge( $path, array( $key ) ),
+ $draft,
+ $pointer . '/' . $key
+ );
+ }
+ }
+ }
+
+ /**
+ * @param object $data
+ * @param Uri|null $id
+ * @param Uri|null $base
+ * @param Uri|null $root
+ * @param array $path
+ * @param string $draft
+ * @param string $pointer
+ */
+ protected function handleObject(
+ $data,
+ $id,
+ $base,
+ $root,
+ $path,
+ $draft,
+ $pointer
+ ) {
+ $schema_id = $this->parser->parseId( $data );
+ $schema_anchor = $this->parser->parseAnchor( $data, $draft );
+ $draft = $this->parser->parseSchemaDraft( $data ) ?? $draft;
+
+ if ( $schema_id !== null ) {
+ $id = Uri::merge( $schema_id, $base, true );
+ } elseif ( $schema_anchor !== null ) {
+ $id = Uri::merge( '#' . $schema_anchor, $base, true );
+ }
+
+ $lazy = new LazySchema( new SchemaInfo( $data, $id, $base, $root, $path, $draft ), $this->parser );
+
+ if ( $id && $id->isAbsolute() ) {
+ $key = $this->cacheKey( (string) $id );
+ if ( isset( $this->uriCache[ $key ] ) ) {
+ throw new DuplicateSchemaIdException( $id, $data );
+ }
+ $this->uriCache[ $key ] = $lazy;
+ }
+
+ // When $id and $anchor are both present add a reference to the same lazy object
+ if ( $schema_id !== null && $schema_anchor !== null ) {
+ $anchor_id = Uri::merge( '#' . $schema_anchor, $id, true );
+ $key = $this->cacheKey( (string) $anchor_id );
+ if ( isset( $this->uriCache[ $key ] ) ) {
+ throw new DuplicateSchemaIdException( $anchor_id, $data );
+ }
+ $this->uriCache[ $key ] = $lazy;
+ }
+
+ $this->dataCache[ $data ] = $lazy;
+ $this->uriCache[ $this->cacheKey( $pointer ) ] = $lazy;
+
+ if ( $root === null ) {
+ $root = $id;
+ }
+
+ if ( $base === null ) {
+ $base = $id ?? $root;
+ } elseif ( $id !== null ) {
+ $base = $id;
+ }
+
+ foreach ( $data as $key => $value ) {
+ if ( ! is_string( $key ) ) {
+ continue;
+ }
+ if ( is_bool( $value ) ) {
+ $this->handleBoolean(
+ $value,
+ null,
+ $base,
+ $root,
+ array_merge( $path, array( $key ) ),
+ $draft,
+ $pointer . '/' . JsonPointer::encodePath( $key )
+ );
+ } elseif ( is_array( $value ) ) {
+ $this->handleArray(
+ $value,
+ $base,
+ $root,
+ array_merge( $path, array( $key ) ),
+ $draft,
+ $pointer . '/' . JsonPointer::encodePath( $key )
+ );
+ } elseif ( is_object( $value ) ) {
+ $this->handleObject(
+ $value,
+ null,
+ $base,
+ $root,
+ array_merge( $path, array( $key ) ),
+ $draft,
+ $pointer . '/' . JsonPointer::encodePath( $key )
+ );
+ }
+ }
+ }
+
+ /**
+ * @param string $path
+ * @return string
+ */
+ protected function cacheKey( $path ): string {
+ return isset( $path[32] ) ? md5( $path ) : $path;
+ }
+
+ /**
+ * @param bool|object $data
+ * @return string
+ */
+ protected function createSchemaId( $data ): string {
+ if ( is_bool( $data ) ) {
+ $data = $data ? 'true' : 'false';
+ } else {
+ $data = spl_object_hash( $data );
+ }
+
+ return "schema:///{$data}.json";
+ }
}
diff --git a/src/opis/json-schema/src/SchemaValidator.php b/src/opis/json-schema/src/SchemaValidator.php
index 68c49509..de156cb8 100644
--- a/src/opis/json-schema/src/SchemaValidator.php
+++ b/src/opis/json-schema/src/SchemaValidator.php
@@ -1,5 +1,6 @@
info = $info;
- }
+ /**
+ * @var \Opis\JsonSchema\Info\SchemaInfo
+ */
+ protected $info;
- /**
- * @inheritDoc
- */
- public function info(): SchemaInfo
- {
- return $this->info;
- }
-}
\ No newline at end of file
+ /**
+ * @param SchemaInfo $info
+ */
+ public function __construct( SchemaInfo $info ) {
+ $this->info = $info;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function info(): SchemaInfo {
+ return $this->info;
+ }
+}
diff --git a/src/opis/json-schema/src/Schemas/BooleanSchema.php b/src/opis/json-schema/src/Schemas/BooleanSchema.php
index 884d5dfa..26301f42 100644
--- a/src/opis/json-schema/src/Schemas/BooleanSchema.php
+++ b/src/opis/json-schema/src/Schemas/BooleanSchema.php
@@ -1,5 +1,6 @@
data = $info->data();
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function validate($context)
- {
- if ($this->data) {
- return null;
- }
-
- return new ValidationError('', $this, DataInfo::fromContext($context), 'Data not allowed');
- }
+final class BooleanSchema extends AbstractSchema {
+
+
+ /**
+ * @var bool
+ */
+ private $data;
+
+ /**
+ * @param SchemaInfo $info
+ */
+ public function __construct( SchemaInfo $info ) {
+ parent::__construct( $info );
+ $this->data = $info->data();
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function validate( $context ) {
+ if ( $this->data ) {
+ return null;
+ }
+
+ return new ValidationError( '', $this, DataInfo::fromContext( $context ), 'Data not allowed' );
+ }
}
diff --git a/src/opis/json-schema/src/Schemas/EmptySchema.php b/src/opis/json-schema/src/Schemas/EmptySchema.php
index 4e158c46..e89b80b6 100644
--- a/src/opis/json-schema/src/Schemas/EmptySchema.php
+++ b/src/opis/json-schema/src/Schemas/EmptySchema.php
@@ -1,5 +1,6 @@
keywordValidator = $keywordValidator;
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function validate($context)
- {
- if (!$this->keywordValidator) {
- return null;
- }
-
- $context->pushSharedObject($this);
- $error = $this->keywordValidator->validate($context);
- $context->popSharedObject();
-
- return $error;
- }
+final class EmptySchema extends AbstractSchema {
+
+ /**
+ * @var \Opis\JsonSchema\KeywordValidator|null
+ */
+ protected $keywordValidator;
+
+ /**
+ * @inheritDoc
+ */
+ public function __construct( SchemaInfo $info, $keywordValidator = null ) {
+ parent::__construct( $info );
+ $this->keywordValidator = $keywordValidator;
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function validate( $context ) {
+ if ( ! $this->keywordValidator ) {
+ return null;
+ }
+
+ $context->pushSharedObject( $this );
+ $error = $this->keywordValidator->validate( $context );
+ $context->popSharedObject();
+
+ return $error;
+ }
}
diff --git a/src/opis/json-schema/src/Schemas/ExceptionSchema.php b/src/opis/json-schema/src/Schemas/ExceptionSchema.php
index a1789e9d..abc34659 100644
--- a/src/opis/json-schema/src/Schemas/ExceptionSchema.php
+++ b/src/opis/json-schema/src/Schemas/ExceptionSchema.php
@@ -1,5 +1,6 @@
exception = $exception;
- }
+ /**
+ * @var \Opis\JsonSchema\Exceptions\SchemaException
+ */
+ private $exception;
- /**
- * @inheritDoc
- * @throws SchemaException
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function validate($context)
- {
- throw $this->exception;
- }
+ /**
+ * @param SchemaInfo $info
+ * @param SchemaException $exception
+ */
+ public function __construct( SchemaInfo $info, SchemaException $exception ) {
+ parent::__construct( $info );
+ $this->exception = $exception;
+ }
+
+ /**
+ * @inheritDoc
+ * @throws SchemaException
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function validate( $context ) {
+ throw $this->exception;
+ }
}
diff --git a/src/opis/json-schema/src/Schemas/LazySchema.php b/src/opis/json-schema/src/Schemas/LazySchema.php
index f5ca5995..858ecfff 100644
--- a/src/opis/json-schema/src/Schemas/LazySchema.php
+++ b/src/opis/json-schema/src/Schemas/LazySchema.php
@@ -1,5 +1,6 @@
parser = $parser;
- }
+ /**
+ * @var \Opis\JsonSchema\Schema|null
+ */
+ private $schema;
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function validate($context)
- {
- return $this->schema()->validate($context);
- }
+ /**
+ * @param SchemaInfo $info
+ * @param SchemaParser $parser
+ */
+ public function __construct( SchemaInfo $info, SchemaParser $parser ) {
+ parent::__construct( $info );
+ $this->parser = $parser;
+ }
- /**
- * @return Schema
- */
- public function schema(): Schema
- {
- if ($this->schema === null) {
- $this->schema = $this->parser->parseSchema($this->info);
- }
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function validate( $context ) {
+ return $this->schema()->validate( $context );
+ }
- return $this->schema;
- }
+ /**
+ * @return Schema
+ */
+ public function schema(): Schema {
+ if ( $this->schema === null ) {
+ $this->schema = $this->parser->parseSchema( $this->info );
+ }
+
+ return $this->schema;
+ }
}
diff --git a/src/opis/json-schema/src/Schemas/ObjectSchema.php b/src/opis/json-schema/src/Schemas/ObjectSchema.php
index e2d08174..d64b7de1 100644
--- a/src/opis/json-schema/src/Schemas/ObjectSchema.php
+++ b/src/opis/json-schema/src/Schemas/ObjectSchema.php
@@ -1,5 +1,6 @@
types = $types;
- $this->before = $before;
- $this->after = $after;
- $this->keywordValidator = $keywordValidator;
-
- if ($keywordValidator) {
- while ($next = $keywordValidator->next()) {
- $keywordValidator = $next;
- }
- $keywordValidator->setNext(new CallbackKeywordValidator([$this, 'doValidate']));
- }
- }
-
- /**
- * @inheritDoc
- * @param \Opis\JsonSchema\ValidationContext $context
- */
- public function validate($context)
- {
- $context->pushSharedObject($this);
- $error = $this->keywordValidator ? $this->keywordValidator->validate($context) : $this->doValidate($context);
- $context->popSharedObject();
-
- return $error;
- }
-
- /**
- * @param ValidationContext $context
- * @return null|ValidationError
- *@internal
- */
- public function doValidate($context)
- {
- if ($this->before && ($error = $this->applyKeywords($this->before, $context))) {
- return $error;
- }
-
- if ($this->types && ($type = $context->currentDataType())) {
- if (isset($this->types[$type]) && ($error = $this->applyKeywords($this->types[$type], $context))) {
- return $error;
- }
-
- if (($type = Helper::getJsonSuperType($type)) && isset($this->types[$type])) {
- if ($error = $this->applyKeywords($this->types[$type], $context)) {
- return $error;
- }
- }
-
- unset($type);
- }
-
- if ($this->after && ($error = $this->applyKeywords($this->after, $context))) {
- return $error;
- }
-
- return null;
- }
-
- /**
- * @param Keyword[] $keywords
- * @param ValidationContext $context
- * @return ValidationError|null
- */
- protected function applyKeywords($keywords, $context)
- {
- foreach ($keywords as $keyword) {
- if ($error = $keyword->validate($context, $this)) {
- return $error;
- }
- }
-
- return null;
- }
+class ObjectSchema extends AbstractSchema {
+
+ /**
+ * @var \Opis\JsonSchema\KeywordValidator|null
+ */
+ protected $keywordValidator;
+
+ /** @var Keyword[]|null */
+ protected $before;
+
+ /** @var Keyword[]|null */
+ protected $after;
+
+ /** @var Keyword[][]|null */
+ protected $types;
+
+ /**
+ * @param SchemaInfo $info
+ * @param KeywordValidator|null $keywordValidator
+ * @param Keyword[][]|null $types
+ * @param Keyword[]|null $before
+ * @param Keyword[]|null $after
+ */
+ public function __construct( SchemaInfo $info, $keywordValidator, $types, $before, $after ) {
+ parent::__construct( $info );
+ $this->types = $types;
+ $this->before = $before;
+ $this->after = $after;
+ $this->keywordValidator = $keywordValidator;
+
+ if ( $keywordValidator ) {
+ while ( $next = $keywordValidator->next() ) {
+ $keywordValidator = $next;
+ }
+ $keywordValidator->setNext( new CallbackKeywordValidator( array( $this, 'doValidate' ) ) );
+ }
+ }
+
+ /**
+ * @inheritDoc
+ * @param \Opis\JsonSchema\ValidationContext $context
+ */
+ public function validate( $context ) {
+ $context->pushSharedObject( $this );
+ $error = $this->keywordValidator ? $this->keywordValidator->validate( $context ) : $this->doValidate( $context );
+ $context->popSharedObject();
+
+ return $error;
+ }
+
+ /**
+ * @param ValidationContext $context
+ * @return null|ValidationError
+ * @internal
+ */
+ public function doValidate( $context ) {
+ if ( $this->before && ( $error = $this->applyKeywords( $this->before, $context ) ) ) {
+ return $error;
+ }
+
+ if ( $this->types && ( $type = $context->currentDataType() ) ) {
+ if ( isset( $this->types[ $type ] ) && ( $error = $this->applyKeywords( $this->types[ $type ], $context ) ) ) {
+ return $error;
+ }
+
+ if ( ( $type = Helper::getJsonSuperType( $type ) ) && isset( $this->types[ $type ] ) ) {
+ if ( $error = $this->applyKeywords( $this->types[ $type ], $context ) ) {
+ return $error;
+ }
+ }
+
+ unset( $type );
+ }
+
+ if ( $this->after && ( $error = $this->applyKeywords( $this->after, $context ) ) ) {
+ return $error;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param Keyword[] $keywords
+ * @param ValidationContext $context
+ * @return ValidationError|null
+ */
+ protected function applyKeywords( $keywords, $context ) {
+ foreach ( $keywords as $keyword ) {
+ if ( $error = $keyword->validate( $context, $this ) ) {
+ return $error;
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/opis/json-schema/src/Uri.php b/src/opis/json-schema/src/Uri.php
index 1f9b5d38..17adfac5 100644
--- a/src/opis/json-schema/src/Uri.php
+++ b/src/opis/json-schema/src/Uri.php
@@ -1,5 +1,6 @@
__toString();
- }
+ public function __construct( array $components ) {
+ if ( static::$useNormalizedComponents ) {
+ $components = self::normalizeComponents( $components );
+ }
+ parent::__construct( $components );
+ }
- /**
- * @param string $uri
- * @param bool $ensure_fragment
- * @return static|null
- */
- public static function parse($uri, $ensure_fragment = false)
- {
- if ($ensure_fragment && strpos($uri, '#') === false) {
- $uri .= '#';
- }
+ /**
+ * @inheritDoc
+ */
+ public function jsonSerialize(): string {
+ return $this->__toString();
+ }
- return self::create($uri);
- }
+ /**
+ * @param string $uri
+ * @param bool $ensure_fragment
+ * @return static|null
+ */
+ public static function parse( $uri, $ensure_fragment = false ) {
+ if ( $ensure_fragment && strpos( $uri, '#' ) === false ) {
+ $uri .= '#';
+ }
- /**
- * @param string|array|static $uri
- * @param string|array|static $base
- * @param bool $ensure_fragment
- * @return static|null
- */
- public static function merge($uri, $base, $ensure_fragment = false)
- {
- $uri = self::resolveComponents($uri);
+ return self::create( $uri );
+ }
- if ($uri === null) {
- return null;
- }
+ /**
+ * @param string|array|static $uri
+ * @param string|array|static $base
+ * @param bool $ensure_fragment
+ * @return static|null
+ */
+ public static function merge( $uri, $base, $ensure_fragment = false ) {
+ $uri = self::resolveComponents( $uri );
- if ($ensure_fragment && !isset($uri['fragment'])) {
- $uri['fragment'] = '';
- }
+ if ( $uri === null ) {
+ return null;
+ }
- $base = self::resolveComponents($base);
+ if ( $ensure_fragment && ! isset( $uri['fragment'] ) ) {
+ $uri['fragment'] = '';
+ }
- if (!$base) {
- return new self($uri);
- }
+ $base = self::resolveComponents( $base );
- return new self(self::mergeComponents($uri, $base));
- }
+ if ( ! $base ) {
+ return new self( $uri );
+ }
- /**
- * @param bool $value
- */
- public static function useNormalizedComponents($value)
- {
- self::$useNormalizedComponents = $value;
- }
+ return new self( self::mergeComponents( $uri, $base ) );
+ }
+
+ /**
+ * @param bool $value
+ */
+ public static function useNormalizedComponents( $value ) {
+ self::$useNormalizedComponents = $value;
+ }
}
diff --git a/src/opis/json-schema/src/ValidationContext.php b/src/opis/json-schema/src/ValidationContext.php
index 6d6f4928..de182251 100644
--- a/src/opis/json-schema/src/ValidationContext.php
+++ b/src/opis/json-schema/src/ValidationContext.php
@@ -1,5 +1,6 @@
sender = $sender;
- $this->rootData = $data;
- $this->loader = $loader;
- $this->parent = $parent;
- $this->globals = $globals;
- $this->slots = null;
- $this->maxErrors = $max_errors;
- $this->currentData = [
- [$data, false],
- ];
-
- if ($slots) {
- $this->setSlots($slots);
- }
- }
-
- /**
- * @param $data
- * @param Schema|null $sender
- * @param array|null $globals
- * @param array|null $slots
- * @param int|null $max_errors
- * @return self
- */
- public function newInstance(
- $data,
- $sender,
- $globals = null,
- $slots = null,
- $max_errors = null
- ): self {
- return new self($data, $this->loader, $this, $sender, $globals ?? $this->globals, $slots ?? $this->slots,
- $max_errors ?? $this->maxErrors);
- }
-
- /**
- * @param \Opis\JsonSchema\Schema $sender
- * @param \Opis\JsonSchema\Variables|null $mapper
- * @param \Opis\JsonSchema\Variables|null $globals
- * @param mixed[]|null $slots
- * @param int|null $maxErrors
- */
- public function create(
- $sender,
- $mapper = null,
- $globals = null,
- $slots = null,
- $maxErrors = null
- ): self {
- if ($globals) {
- $globals = $globals->resolve($this->rootData(), $this->currentDataPath());
- if (!is_array($globals)) {
- $globals = (array)$globals;
- }
- $globals += $this->globals;
- } else {
- $globals = $this->globals;
- }
-
- if ($mapper) {
- $data = $mapper->resolve($this->rootData(), $this->currentDataPath());
- } else {
- $data = $this->currentData();
- }
-
- return new self($data, $this->loader, $this, $sender, $globals, $slots ?? $this->slots,
- $maxErrors ?? $this->maxErrors);
- }
-
- public function sender()
- {
- return $this->sender;
- }
-
- /**
- * @return self|null
- */
- public function parent()
- {
- return $this->parent;
- }
-
- /**
- * @return SchemaLoader
- */
- public function loader(): SchemaLoader
- {
- return $this->loader;
- }
-
- /**
- * @return mixed
- */
- public function rootData()
- {
- return $this->rootData;
- }
-
- /**
- * @return mixed
- */
- public function currentData()
- {
- return $this->currentData[$this->pathIndex][0];
- }
-
- /**
- * @param $value
- */
- public function setCurrentData($value)
- {
- $this->currentData[$this->pathIndex][0] = $value;
- $this->currentData[$this->pathIndex][1] = false;
- }
-
- /**
- * @return string|null
- */
- public function currentDataType()
- {
- $type = $this->currentData[$this->pathIndex][1];
- if ($type === false) {
- $type = Helper::getJsonType($this->currentData[$this->pathIndex][0]);
- $this->currentData[$this->pathIndex][1] = $type;
- }
-
- return $type;
- }
-
- public function fullDataPath(): array
- {
- if ($this->fullPath === null) {
- if ($this->parent === null) {
- return $this->currentDataPath;
- }
- $this->fullPath = array_merge($this->parent->fullDataPath(), $this->currentDataPath);
- }
-
- return $this->fullPath;
- }
-
- /**
- * @return int[]|string[]
- */
- public function currentDataPath(): array
- {
- return $this->currentDataPath;
- }
-
- /**
- * @param string|int $key
- * @return $this
- */
- public function pushDataPath($key): self
- {
- $this->currentDataPath[] = $key;
- if ($this->fullPath !== null) {
- $this->fullPath[] = $key;
- }
-
- $data = $this->currentData[$this->pathIndex][0];
-
- if (is_array($data)) {
- $data = $data[$key] ?? null;
- } elseif (is_object($data)) {
- $data = $data->{$key} ?? null;
- } else {
- $data = null;
- }
-
- $this->currentData[] = [$data, false];
- $this->pathIndex++;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function popDataPath(): self
- {
- if ($this->pathIndex < 1) {
- return $this;
- }
-
- if ($this->fullPath !== null) {
- array_pop($this->fullPath);
- }
- array_pop($this->currentDataPath);
- array_pop($this->currentData);
- $this->pathIndex--;
-
- return $this;
- }
-
- /**
- * @return array
- */
- public function globals(): array
- {
- return $this->globals;
- }
-
- /**
- * @param array $globals
- * @param bool $overwrite
- * @return $this
- */
- public function setGlobals($globals, $overwrite = false): self
- {
- if ($overwrite) {
- $this->globals = $globals;
- } elseif ($globals) {
- $this->globals = $globals + $this->globals;
- }
-
- return $this;
- }
-
- /**
- * @return object[]|Schema[]|string[]|null
- */
- public function slots()
- {
- return $this->slots;
- }
-
- /**
- * @param array|null $slots
- * @return $this
- */
- public function setSlots($slots): self
- {
- if ($slots) {
- $list = [];
-
- foreach ($slots as $name => $value) {
- if (is_bool($value)) {
- $value = $this->loader->loadBooleanSchema($value);
- } elseif (is_object($value)) {
- if ($value instanceof Schema) {
- $list[$name] = $value;
- continue;
- }
- $value = $this->loader->loadObjectSchema($value);
- } elseif (is_string($value)) {
- if (isset($this->slots[$value])) {
- $value = $this->slots[$value];
- } elseif ($this->parent) {
- $value = $this->parent->slot($value);
- }
- }
-
- if ($value instanceof Schema) {
- $list[$name] = $value;
- }
- }
-
- $this->slots = $list;
- } else {
- $this->slots = null;
- }
-
- return $this;
- }
-
- /**
- * @param string $name
- * @return Schema|null
- */
- public function slot($name)
- {
- return $this->slots[$name] ?? null;
- }
-
- /**
- * @return int
- */
- public function maxErrors(): int
- {
- return $this->maxErrors;
- }
-
- /**
- * @param int $max
- * @return $this
- */
- public function setMaxErrors($max): self
- {
- $this->maxErrors = $max;
-
- return $this;
- }
-
- /* --------------------- */
-
- /**
- * @param Schema $schema
- * @return $this
- */
- public function pushSharedObject($schema): self
- {
- $unevaluated = !in_array($schema->info()->draft(), ['06', '07']);
- if ($unevaluated && ($parser = $this->loader->parser()) && !$parser->option('allowUnevaluated', true)) {
- $unevaluated = false;
- }
-
- $this->shared[] = [
- 'schema' => $schema,
- 'unevaluated' => $unevaluated,
- 'object' => null,
- ];
- $this->sharedIndex++;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function popSharedObject(): self
- {
- if ($this->sharedIndex < 0) {
- return $this;
- }
-
- $data = array_pop($this->shared);
- $this->sharedIndex--;
-
- if ($data['unevaluated'] && $data['object']) {
- if ($this->sharedIndex >= 0) {
- $this->mergeUnevaluated($data['object']);
- } elseif ($this->parent && $this->parent->sharedIndex >= 0) {
- $this->parent->mergeUnevaluated($data['object']);
- }
- }
-
- return $this;
- }
-
- /**
- * @return object|null
- */
- public function sharedObject()
- {
- if ($this->sharedIndex < 0) {
- return null;
- }
-
- return $this->shared[$this->sharedIndex]['object'] = $this->shared[$this->sharedIndex]['object'] ?? (object)[];
- }
-
- public function schema()
- {
- return $this->shared[$this->sharedIndex]['schema'] ?? null;
- }
-
- public function trackUnevaluated(): bool
- {
- return $this->shared[$this->sharedIndex]['unevaluated'] ?? false;
- }
-
- /**
- * @param object $obj
- */
- protected function mergeUnevaluated($obj)
- {
- switch ($this->currentDataType()) {
- case 'object':
- if (isset($obj->evaluatedProperties)) {
- $this->addEvaluatedProperties($obj->evaluatedProperties);
- }
- break;
- case 'array':
- if (isset($obj->evaluatedItems)) {
- $this->addEvaluatedItems($obj->evaluatedItems);
- }
- break;
- }
- }
-
- /* ----------------*/
-
- public function getStringLength()
- {
- if ($this->currentDataType() !== 'string') {
- return null;
- }
-
- $shared = $this->sharedObject();
-
- if (!isset($shared->stringLength)) {
- $shared->stringLength = UnicodeString::from($this->currentData())->length();
- }
-
- return $shared->stringLength;
- }
-
- /**
- * @param string $content
- */
- public function setDecodedContent($content): bool
- {
- if ($this->currentDataType() !== 'string') {
- return false;
- }
-
- $this->sharedObject()->decodedContent = $content;
-
- return true;
- }
-
- public function getDecodedContent()
- {
- if ($this->currentDataType() !== 'string') {
- return null;
- }
- return $this->sharedObject()->decodedContent ?? $this->currentData();
- }
-
- public function getObjectProperties()
- {
- if ($this->currentDataType() !== 'object') {
- return null;
- }
-
- return $this->sharedObject()->objectProperties = $this->sharedObject()->objectProperties ?? array_keys(get_object_vars($this->currentData()));
- }
-
- /**
- * @param mixed[]|null $properties
- */
- public function addCheckedProperties($properties): bool
- {
- if (!$properties) {
- return false;
- }
-
- $shared = $this->sharedObject();
-
- if (!isset($shared->checkedProperties)) {
- $shared->checkedProperties = $properties;
- } else {
- $shared->checkedProperties = array_values(array_unique(array_merge($shared->checkedProperties, $properties)));
- }
-
- return true;
- }
-
- public function getCheckedProperties()
- {
- return $this->sharedObject()->checkedProperties ?? null;
- }
-
- public function getUncheckedProperties()
- {
- $properties = $this->getObjectProperties();
- if (!$properties) {
- return $properties;
- }
-
- $checked = $this->sharedObject()->checkedProperties ?? null;
- if (!$checked) {
- return $properties;
- }
-
- return array_values(array_diff($properties, $checked));
- }
-
- public function markAllAsEvaluatedProperties(): bool
- {
- return $this->addEvaluatedProperties($this->getObjectProperties());
- }
-
- /**
- * @param mixed[]|null $properties
- */
- public function addEvaluatedProperties($properties): bool
- {
- if (!$properties || !($this->currentDataType() === 'object') || !$this->trackUnevaluated()) {
- return false;
- }
-
- $shared = $this->sharedObject();
-
- if (!isset($shared->evaluatedProperties)) {
- $shared->evaluatedProperties = $properties;
- } else {
- $shared->evaluatedProperties = array_values(array_unique(array_merge($shared->evaluatedProperties, $properties)));
- }
-
- return true;
- }
-
- public function getEvaluatedProperties()
- {
- return $this->sharedObject()->evaluatedProperties ?? null;
- }
-
- public function getUnevaluatedProperties()
- {
- $properties = $this->getObjectProperties();
- if (!$properties) {
- return $properties;
- }
-
- $evaluated = $this->sharedObject()->evaluatedProperties ?? null;
- if (!$evaluated) {
- return $properties;
- }
-
- return array_values(array_diff($properties, $evaluated));
- }
-
- public function markAllAsEvaluatedItems(): bool
- {
- return $this->addEvaluatedItems(range(0, count($this->currentData())));
- }
-
- /**
- * @param int $count
- */
- public function markCountAsEvaluatedItems($count): bool
- {
- if (!$count) {
- return false;
- }
-
- return $this->addEvaluatedItems(range(0, $count));
- }
-
- /**
- * @param mixed[]|null $items
- */
- public function addEvaluatedItems($items): bool
- {
- if (!$items || !($this->currentDataType() === 'array') || !$this->trackUnevaluated()) {
- return false;
- }
-
- $shared = $this->sharedObject();
-
- if (!isset($shared->evaluatedItems)) {
- $shared->evaluatedItems = $items;
- } else {
- $shared->evaluatedItems = array_values(array_unique(array_merge($shared->evaluatedItems, $items), SORT_NUMERIC));
- }
-
- return true;
- }
-
- public function getEvaluatedItems()
- {
- return $this->sharedObject()->evaluatedItems ?? null;
- }
-
- public function getUnevaluatedItems()
- {
- if ($this->currentDataType() !== 'array') {
- return null;
- }
-
- $items = array_keys($this->currentData());
- if (!$items) {
- return $items;
- }
-
- $evaluated = $this->sharedObject()->evaluatedItems ?? null;
- if (!$evaluated) {
- return $items;
- }
-
- return array_values(array_diff($items, $evaluated));
- }
-
- /**
- * @param \Opis\JsonSchema\Schema $schema
- * @param int|null $maxErrors
- * @param bool $reset_on_error_only
- * @param \ArrayObject|null $array
- */
- public function validateSchemaWithoutEvaluated(
- $schema,
- $maxErrors = null,
- $reset_on_error_only = false,
- $array = null
- ) {
- $currentMaxErrors = $this->maxErrors;
-
- $this->maxErrors = $maxErrors ?? $currentMaxErrors;
-
- if ($this->trackUnevaluated()) {
- $shared = $this->sharedObject();
-
- $props = $shared->evaluatedProperties ?? null;
- $items = $shared->evaluatedItems ?? null;
-
- $error = $schema->validate($this);
-
- if ($array) {
- $value = null;
-
- if ($shared->evaluatedProperties ?? null) {
- if ($props) {
- if ($diff = array_diff($shared->evaluatedProperties, $props)) {
- $value['properties'] = $diff;
- }
- } else {
- $value['properties'] = $shared->evaluatedProperties;
- }
- }
-
- if ($shared->evaluatedItems ?? null) {
- if ($items) {
- if ($diff = array_diff($shared->evaluatedItems, $items)) {
- $value['items'] = $diff;
- }
- } else {
- $value['items'] = $shared->evaluatedItems;
- }
- }
-
- if ($value) {
- $array[] = $value;
- }
- }
-
- if ($reset_on_error_only) {
- if ($error) {
- $shared->evaluatedProperties = $props;
- $shared->evaluatedItems = $items;
- }
- } else {
- $shared->evaluatedProperties = $props;
- $shared->evaluatedItems = $items;
- }
- } else {
- $error = $schema->validate($this);
- }
-
- $this->maxErrors = $currentMaxErrors;
-
- return $error;
- }
+class ValidationContext {
+
+ /** @var mixed */
+ protected $rootData;
+
+ /** @var string[]|int[] */
+ protected $currentDataPath = array();
+
+ /**
+ * @var mixed[]|null
+ */
+ protected $fullPath;
+
+ /**
+ * @var mixed[]
+ */
+ protected $globals;
+
+ /** @var mixed */
+ protected $currentData = null;
+
+ /**
+ * @var $this|null
+ */
+ protected $parent;
+
+ /**
+ * @var \Opis\JsonSchema\SchemaLoader
+ */
+ protected $loader;
+
+ /**
+ * @var \Opis\JsonSchema\Schema|null
+ */
+ protected $sender;
+
+ /** @var object[]|null[]|null */
+ protected $shared;
+
+ /** @var null|string[]|Schema[]|object[] */
+ protected $slots;
+
+ /**
+ * @var int
+ */
+ protected $sharedIndex = -1;
+
+ /**
+ * @var int
+ */
+ protected $pathIndex = 0;
+
+ /**
+ * @var int
+ */
+ protected $maxErrors = 1;
+
+ /**
+ * @param $data
+ * @param SchemaLoader $loader
+ * @param null|self $parent
+ * @param Schema|null $parent
+ * @param array $globals
+ * @param null|string[]|Schema[] $slots
+ * @param int $max_errors
+ */
+ public function __construct(
+ $data,
+ SchemaLoader $loader,
+ $parent = null,
+ $sender = null,
+ array $globals = array(),
+ $slots = null,
+ int $max_errors = 1
+ ) {
+ $this->sender = $sender;
+ $this->rootData = $data;
+ $this->loader = $loader;
+ $this->parent = $parent;
+ $this->globals = $globals;
+ $this->slots = null;
+ $this->maxErrors = $max_errors;
+ $this->currentData = array(
+ array( $data, false ),
+ );
+
+ if ( $slots ) {
+ $this->setSlots( $slots );
+ }
+ }
+
+ /**
+ * @param $data
+ * @param Schema|null $sender
+ * @param array|null $globals
+ * @param array|null $slots
+ * @param int|null $max_errors
+ * @return self
+ */
+ public function newInstance(
+ $data,
+ $sender,
+ $globals = null,
+ $slots = null,
+ $max_errors = null
+ ): self {
+ return new self(
+ $data,
+ $this->loader,
+ $this,
+ $sender,
+ $globals ?? $this->globals,
+ $slots ?? $this->slots,
+ $max_errors ?? $this->maxErrors
+ );
+ }
+
+ /**
+ * @param \Opis\JsonSchema\Schema $sender
+ * @param \Opis\JsonSchema\Variables|null $mapper
+ * @param \Opis\JsonSchema\Variables|null $globals
+ * @param mixed[]|null $slots
+ * @param int|null $maxErrors
+ */
+ public function create(
+ $sender,
+ $mapper = null,
+ $globals = null,
+ $slots = null,
+ $maxErrors = null
+ ): self {
+ if ( $globals ) {
+ $globals = $globals->resolve( $this->rootData(), $this->currentDataPath() );
+ if ( ! is_array( $globals ) ) {
+ $globals = (array) $globals;
+ }
+ $globals += $this->globals;
+ } else {
+ $globals = $this->globals;
+ }
+
+ if ( $mapper ) {
+ $data = $mapper->resolve( $this->rootData(), $this->currentDataPath() );
+ } else {
+ $data = $this->currentData();
+ }
+
+ return new self(
+ $data,
+ $this->loader,
+ $this,
+ $sender,
+ $globals,
+ $slots ?? $this->slots,
+ $maxErrors ?? $this->maxErrors
+ );
+ }
+
+ public function sender() {
+ return $this->sender;
+ }
+
+ /**
+ * @return self|null
+ */
+ public function parent() {
+ return $this->parent;
+ }
+
+ /**
+ * @return SchemaLoader
+ */
+ public function loader(): SchemaLoader {
+ return $this->loader;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function rootData() {
+ return $this->rootData;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function currentData() {
+ return $this->currentData[ $this->pathIndex ][0];
+ }
+
+ /**
+ * @param $value
+ */
+ public function setCurrentData( $value ) {
+ $this->currentData[ $this->pathIndex ][0] = $value;
+ $this->currentData[ $this->pathIndex ][1] = false;
+ }
+
+ /**
+ * @return string|null
+ */
+ public function currentDataType() {
+ $type = $this->currentData[ $this->pathIndex ][1];
+ if ( $type === false ) {
+ $type = Helper::getJsonType( $this->currentData[ $this->pathIndex ][0] );
+ $this->currentData[ $this->pathIndex ][1] = $type;
+ }
+
+ return $type;
+ }
+
+ public function fullDataPath(): array {
+ if ( $this->fullPath === null ) {
+ if ( $this->parent === null ) {
+ return $this->currentDataPath;
+ }
+ $this->fullPath = array_merge( $this->parent->fullDataPath(), $this->currentDataPath );
+ }
+
+ return $this->fullPath;
+ }
+
+ /**
+ * @return int[]|string[]
+ */
+ public function currentDataPath(): array {
+ return $this->currentDataPath;
+ }
+
+ /**
+ * @param string|int $key
+ * @return $this
+ */
+ public function pushDataPath( $key ): self {
+ $this->currentDataPath[] = $key;
+ if ( $this->fullPath !== null ) {
+ $this->fullPath[] = $key;
+ }
+
+ $data = $this->currentData[ $this->pathIndex ][0];
+
+ if ( is_array( $data ) ) {
+ $data = $data[ $key ] ?? null;
+ } elseif ( is_object( $data ) ) {
+ $data = $data->{$key} ?? null;
+ } else {
+ $data = null;
+ }
+
+ $this->currentData[] = array( $data, false );
+ ++$this->pathIndex;
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function popDataPath(): self {
+ if ( $this->pathIndex < 1 ) {
+ return $this;
+ }
+
+ if ( $this->fullPath !== null ) {
+ array_pop( $this->fullPath );
+ }
+ array_pop( $this->currentDataPath );
+ array_pop( $this->currentData );
+ --$this->pathIndex;
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function globals(): array {
+ return $this->globals;
+ }
+
+ /**
+ * @param array $globals
+ * @param bool $overwrite
+ * @return $this
+ */
+ public function setGlobals( $globals, $overwrite = false ): self {
+ if ( $overwrite ) {
+ $this->globals = $globals;
+ } elseif ( $globals ) {
+ $this->globals = $globals + $this->globals;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return object[]|Schema[]|string[]|null
+ */
+ public function slots() {
+ return $this->slots;
+ }
+
+ /**
+ * @param array|null $slots
+ * @return $this
+ */
+ public function setSlots( $slots ): self {
+ if ( $slots ) {
+ $list = array();
+
+ foreach ( $slots as $name => $value ) {
+ if ( is_bool( $value ) ) {
+ $value = $this->loader->loadBooleanSchema( $value );
+ } elseif ( is_object( $value ) ) {
+ if ( $value instanceof Schema ) {
+ $list[ $name ] = $value;
+ continue;
+ }
+ $value = $this->loader->loadObjectSchema( $value );
+ } elseif ( is_string( $value ) ) {
+ if ( isset( $this->slots[ $value ] ) ) {
+ $value = $this->slots[ $value ];
+ } elseif ( $this->parent ) {
+ $value = $this->parent->slot( $value );
+ }
+ }
+
+ if ( $value instanceof Schema ) {
+ $list[ $name ] = $value;
+ }
+ }
+
+ $this->slots = $list;
+ } else {
+ $this->slots = null;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $name
+ * @return Schema|null
+ */
+ public function slot( $name ) {
+ return $this->slots[ $name ] ?? null;
+ }
+
+ /**
+ * @return int
+ */
+ public function maxErrors(): int {
+ return $this->maxErrors;
+ }
+
+ /**
+ * @param int $max
+ * @return $this
+ */
+ public function setMaxErrors( $max ): self {
+ $this->maxErrors = $max;
+
+ return $this;
+ }
+
+ /* --------------------- */
+
+ /**
+ * @param Schema $schema
+ * @return $this
+ */
+ public function pushSharedObject( $schema ): self {
+ $unevaluated = ! in_array( $schema->info()->draft(), array( '06', '07' ) );
+ if ( $unevaluated && ( $parser = $this->loader->parser() ) && ! $parser->option( 'allowUnevaluated', true ) ) {
+ $unevaluated = false;
+ }
+
+ $this->shared[] = array(
+ 'schema' => $schema,
+ 'unevaluated' => $unevaluated,
+ 'object' => null,
+ );
+ ++$this->sharedIndex;
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function popSharedObject(): self {
+ if ( $this->sharedIndex < 0 ) {
+ return $this;
+ }
+
+ $data = array_pop( $this->shared );
+ --$this->sharedIndex;
+
+ if ( $data['unevaluated'] && $data['object'] ) {
+ if ( $this->sharedIndex >= 0 ) {
+ $this->mergeUnevaluated( $data['object'] );
+ } elseif ( $this->parent && $this->parent->sharedIndex >= 0 ) {
+ $this->parent->mergeUnevaluated( $data['object'] );
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return object|null
+ */
+ public function sharedObject() {
+ if ( $this->sharedIndex < 0 ) {
+ return null;
+ }
+
+ return $this->shared[ $this->sharedIndex ]['object'] = $this->shared[ $this->sharedIndex ]['object'] ?? (object) array();
+ }
+
+ public function schema() {
+ return $this->shared[ $this->sharedIndex ]['schema'] ?? null;
+ }
+
+ public function trackUnevaluated(): bool {
+ return $this->shared[ $this->sharedIndex ]['unevaluated'] ?? false;
+ }
+
+ /**
+ * @param object $obj
+ */
+ protected function mergeUnevaluated( $obj ) {
+ switch ( $this->currentDataType() ) {
+ case 'object':
+ if ( isset( $obj->evaluatedProperties ) ) {
+ $this->addEvaluatedProperties( $obj->evaluatedProperties );
+ }
+ break;
+ case 'array':
+ if ( isset( $obj->evaluatedItems ) ) {
+ $this->addEvaluatedItems( $obj->evaluatedItems );
+ }
+ break;
+ }
+ }
+
+ /* ----------------*/
+
+ public function getStringLength() {
+ if ( $this->currentDataType() !== 'string' ) {
+ return null;
+ }
+
+ $shared = $this->sharedObject();
+
+ if ( ! isset( $shared->stringLength ) ) {
+ $shared->stringLength = UnicodeString::from( $this->currentData() )->length();
+ }
+
+ return $shared->stringLength;
+ }
+
+ /**
+ * @param string $content
+ */
+ public function setDecodedContent( $content ): bool {
+ if ( $this->currentDataType() !== 'string' ) {
+ return false;
+ }
+
+ $this->sharedObject()->decodedContent = $content;
+
+ return true;
+ }
+
+ public function getDecodedContent() {
+ if ( $this->currentDataType() !== 'string' ) {
+ return null;
+ }
+ return $this->sharedObject()->decodedContent ?? $this->currentData();
+ }
+
+ public function getObjectProperties() {
+ if ( $this->currentDataType() !== 'object' ) {
+ return null;
+ }
+
+ return $this->sharedObject()->objectProperties = $this->sharedObject()->objectProperties ?? array_keys( get_object_vars( $this->currentData() ) );
+ }
+
+ /**
+ * @param mixed[]|null $properties
+ */
+ public function addCheckedProperties( $properties ): bool {
+ if ( ! $properties ) {
+ return false;
+ }
+
+ $shared = $this->sharedObject();
+
+ if ( ! isset( $shared->checkedProperties ) ) {
+ $shared->checkedProperties = $properties;
+ } else {
+ $shared->checkedProperties = array_values( array_unique( array_merge( $shared->checkedProperties, $properties ) ) );
+ }
+
+ return true;
+ }
+
+ public function getCheckedProperties() {
+ return $this->sharedObject()->checkedProperties ?? null;
+ }
+
+ public function getUncheckedProperties() {
+ $properties = $this->getObjectProperties();
+ if ( ! $properties ) {
+ return $properties;
+ }
+
+ $checked = $this->sharedObject()->checkedProperties ?? null;
+ if ( ! $checked ) {
+ return $properties;
+ }
+
+ return array_values( array_diff( $properties, $checked ) );
+ }
+
+ public function markAllAsEvaluatedProperties(): bool {
+ return $this->addEvaluatedProperties( $this->getObjectProperties() );
+ }
+
+ /**
+ * @param mixed[]|null $properties
+ */
+ public function addEvaluatedProperties( $properties ): bool {
+ if ( ! $properties || ! ( $this->currentDataType() === 'object' ) || ! $this->trackUnevaluated() ) {
+ return false;
+ }
+
+ $shared = $this->sharedObject();
+
+ if ( ! isset( $shared->evaluatedProperties ) ) {
+ $shared->evaluatedProperties = $properties;
+ } else {
+ $shared->evaluatedProperties = array_values( array_unique( array_merge( $shared->evaluatedProperties, $properties ) ) );
+ }
+
+ return true;
+ }
+
+ public function getEvaluatedProperties() {
+ return $this->sharedObject()->evaluatedProperties ?? null;
+ }
+
+ public function getUnevaluatedProperties() {
+ $properties = $this->getObjectProperties();
+ if ( ! $properties ) {
+ return $properties;
+ }
+
+ $evaluated = $this->sharedObject()->evaluatedProperties ?? null;
+ if ( ! $evaluated ) {
+ return $properties;
+ }
+
+ return array_values( array_diff( $properties, $evaluated ) );
+ }
+
+ public function markAllAsEvaluatedItems(): bool {
+ return $this->addEvaluatedItems( range( 0, count( $this->currentData() ) ) );
+ }
+
+ /**
+ * @param int $count
+ */
+ public function markCountAsEvaluatedItems( $count ): bool {
+ if ( ! $count ) {
+ return false;
+ }
+
+ return $this->addEvaluatedItems( range( 0, $count ) );
+ }
+
+ /**
+ * @param mixed[]|null $items
+ */
+ public function addEvaluatedItems( $items ): bool {
+ if ( ! $items || ! ( $this->currentDataType() === 'array' ) || ! $this->trackUnevaluated() ) {
+ return false;
+ }
+
+ $shared = $this->sharedObject();
+
+ if ( ! isset( $shared->evaluatedItems ) ) {
+ $shared->evaluatedItems = $items;
+ } else {
+ $shared->evaluatedItems = array_values( array_unique( array_merge( $shared->evaluatedItems, $items ), SORT_NUMERIC ) );
+ }
+
+ return true;
+ }
+
+ public function getEvaluatedItems() {
+ return $this->sharedObject()->evaluatedItems ?? null;
+ }
+
+ public function getUnevaluatedItems() {
+ if ( $this->currentDataType() !== 'array' ) {
+ return null;
+ }
+
+ $items = array_keys( $this->currentData() );
+ if ( ! $items ) {
+ return $items;
+ }
+
+ $evaluated = $this->sharedObject()->evaluatedItems ?? null;
+ if ( ! $evaluated ) {
+ return $items;
+ }
+
+ return array_values( array_diff( $items, $evaluated ) );
+ }
+
+ /**
+ * @param \Opis\JsonSchema\Schema $schema
+ * @param int|null $maxErrors
+ * @param bool $reset_on_error_only
+ * @param \ArrayObject|null $array
+ */
+ public function validateSchemaWithoutEvaluated(
+ $schema,
+ $maxErrors = null,
+ $reset_on_error_only = false,
+ $array = null
+ ) {
+ $currentMaxErrors = $this->maxErrors;
+
+ $this->maxErrors = $maxErrors ?? $currentMaxErrors;
+
+ if ( $this->trackUnevaluated() ) {
+ $shared = $this->sharedObject();
+
+ $props = $shared->evaluatedProperties ?? null;
+ $items = $shared->evaluatedItems ?? null;
+
+ $error = $schema->validate( $this );
+
+ if ( $array ) {
+ $value = null;
+
+ if ( $shared->evaluatedProperties ?? null ) {
+ if ( $props ) {
+ if ( $diff = array_diff( $shared->evaluatedProperties, $props ) ) {
+ $value['properties'] = $diff;
+ }
+ } else {
+ $value['properties'] = $shared->evaluatedProperties;
+ }
+ }
+
+ if ( $shared->evaluatedItems ?? null ) {
+ if ( $items ) {
+ if ( $diff = array_diff( $shared->evaluatedItems, $items ) ) {
+ $value['items'] = $diff;
+ }
+ } else {
+ $value['items'] = $shared->evaluatedItems;
+ }
+ }
+
+ if ( $value ) {
+ $array[] = $value;
+ }
+ }
+
+ if ( $reset_on_error_only ) {
+ if ( $error ) {
+ $shared->evaluatedProperties = $props;
+ $shared->evaluatedItems = $items;
+ }
+ } else {
+ $shared->evaluatedProperties = $props;
+ $shared->evaluatedItems = $items;
+ }
+ } else {
+ $error = $schema->validate( $this );
+ }
+
+ $this->maxErrors = $currentMaxErrors;
+
+ return $error;
+ }
}
diff --git a/src/opis/json-schema/src/ValidationResult.php b/src/opis/json-schema/src/ValidationResult.php
index 2c687ac6..33f0f98f 100644
--- a/src/opis/json-schema/src/ValidationResult.php
+++ b/src/opis/json-schema/src/ValidationResult.php
@@ -1,5 +1,6 @@
error = $error;
- }
-
- public function error()
- {
- return $this->error;
- }
-
- public function isValid(): bool
- {
- return $this->error === null;
- }
-
- public function hasError(): bool
- {
- return $this->error !== null;
- }
-
- public function __toString(): string
- {
- if ($this->error) {
- return $this->error->message();
- }
- return '';
- }
+class ValidationResult {
+
+ /**
+ * @var \Opis\JsonSchema\Errors\ValidationError|null
+ */
+ protected $error;
+
+ public function __construct( $error ) {
+ $this->error = $error;
+ }
+
+ public function error() {
+ return $this->error;
+ }
+
+ public function isValid(): bool {
+ return $this->error === null;
+ }
+
+ public function hasError(): bool {
+ return $this->error !== null;
+ }
+
+ public function __toString(): string {
+ if ( $this->error ) {
+ return $this->error->message();
+ }
+ return '';
+ }
}
diff --git a/src/opis/json-schema/src/Validator.php b/src/opis/json-schema/src/Validator.php
index 316179ab..ff71cac3 100644
--- a/src/opis/json-schema/src/Validator.php
+++ b/src/opis/json-schema/src/Validator.php
@@ -1,5 +1,6 @@
loader = $loader ?? new SchemaLoader(new SchemaParser(), new SchemaResolver(), true);
- $this->maxErrors = $max_errors;
- }
-
- /**
- * @param $data
- * @param bool|string|Uri|Schema|object $schema
- * @param array|null $globals
- * @param array|null $slots
- * @return ValidationResult
- */
- public function validate($data, $schema, $globals = null, $slots = null): ValidationResult
- {
- if (is_string($schema)) {
- if ($uri = Uri::parse($schema, true)) {
- $schema = $uri;
- } else {
- $schema = json_decode($schema, false);
- }
- }
-
- $error = null;
- if (is_bool($schema)) {
- $error = $this->dataValidation($data, $schema, $globals, $slots);
- } elseif (is_object($schema)) {
- if ($schema instanceof Uri) {
- $error = $this->uriValidation($data, $schema, $globals, $slots);
- } elseif ($schema instanceof Schema) {
- $error = $this->schemaValidation($data, $schema, $globals, $slots);
- } else {
- $error = $this->dataValidation($data, $schema, $globals, $slots);
- }
- } else {
- throw new InvalidArgumentException("Invalid schema");
- }
-
- return new ValidationResult($error);
- }
-
- /**
- * @param $data
- * @param Uri|string $uri
- * @param array|null $globals
- * @param array|null $slots
- * @return null|ValidationError
- */
- public function uriValidation($data, $uri, $globals = null, $slots = null)
- {
- if (is_string($uri)) {
- $uri = Uri::parse($uri, true);
- }
-
- if (!($uri instanceof Uri)) {
- throw new InvalidArgumentException("Invalid uri");
- }
-
- if ($uri->fragment() === null) {
- $uri = Uri::merge($uri, null, true);
- }
-
- $schema = $this->loader->loadSchemaById($uri);
-
- if ($schema === null) {
- throw new RuntimeException("Schema not found: $uri");
- }
-
- return $this->schemaValidation($data, $schema, $globals, $slots);
- }
-
- /**
- * @param $data
- * @param string|object|bool $schema
- * @param array|null $globals
- * @param array|null $slots
- * @param string|null $id
- * @param string|null $draft
- * @return ValidationError|null
- */
- public function dataValidation(
- $data,
- $schema,
- $globals = null,
- $slots = null,
- $id = null,
- $draft = null
- )
- {
- if (is_string($schema)) {
- $schema = json_decode($schema, false);
- }
-
- if ($schema === true) {
- return null;
- }
-
- if ($schema === false) {
- $schema = $this->loader->loadBooleanSchema(false, $id, $draft);
- } else {
- if (!is_object($schema)) {
- throw new InvalidArgumentException("Invalid schema");
- }
-
- $schema = $this->loader->loadObjectSchema($schema, $id, $draft);
- }
-
- return $this->schemaValidation($data, $schema, $globals, $slots);
- }
-
- /**
- * @param $data
- * @param Schema $schema
- * @param array|null $globals
- * @param array|null $slots
- * @return null|ValidationError
- */
- public function schemaValidation(
- $data,
- $schema,
- $globals = null,
- $slots = null
- )
- {
- return $schema->validate($this->createContext($data, $globals, $slots));
- }
-
- /**
- * @param $data
- * @param array|null $globals
- * @param array|null $slots
- * @return ValidationContext
- */
- public function createContext($data, $globals = null, $slots = null): ValidationContext
- {
- if ($slots) {
- $slots = $this->parseSlots($slots);
- }
-
- return new ValidationContext($data, $this->loader, null, null, $globals ?? [], $slots, $this->maxErrors);
- }
-
- /**
- * @return SchemaParser
- */
- public function parser(): SchemaParser
- {
- return $this->loader->parser();
- }
-
- /**
- * @param SchemaParser $parser
- * @return Validator
- */
- public function setParser($parser): self
- {
- $this->loader->setParser($parser);
-
- return $this;
- }
-
- /**
- * @return SchemaResolver|null
- */
- public function resolver()
- {
- return $this->loader->resolver();
- }
-
- /**
- * @param SchemaResolver|null $resolver
- * @return Validator
- */
- public function setResolver($resolver): self
- {
- $this->loader->setResolver($resolver);
-
- return $this;
- }
-
- /**
- * @return SchemaLoader
- */
- public function loader(): SchemaLoader
- {
- return $this->loader;
- }
-
- /**
- * @param SchemaLoader $loader
- * @return Validator
- */
- public function setLoader($loader): self
- {
- $this->loader = $loader;
-
- return $this;
- }
-
- /**
- * @return int
- */
- public function getMaxErrors(): int
- {
- return $this->maxErrors;
- }
-
- /**
- * @param int $max_errors
- * @return Validator
- */
- public function setMaxErrors($max_errors): self
- {
- $this->maxErrors = $max_errors;
-
- return $this;
- }
-
- /**
- * @param array $slots
- * @return array
- */
- protected function parseSlots($slots): array
- {
- foreach ($slots as $name => &$value) {
- if (!is_string($name)) {
- unset($slots[$name]);
- continue;
- }
-
- if (is_string($value)) {
- $value = Uri::parse($value, true);
- }
-
- if ($value instanceof Uri) {
- $value = $this->loader->loadSchemaById($value);
- } elseif (is_bool($value)) {
- $value = $this->loader->loadBooleanSchema($value);
- }
-
- if (!is_object($value)) {
- unset($slots[$name]);
- }
-
- unset($value);
- }
-
- return $slots;
- }
+class Validator {
+
+ /**
+ * @var \Opis\JsonSchema\SchemaLoader
+ */
+ protected $loader;
+ /**
+ * @var int
+ */
+ protected $maxErrors = 1;
+
+ /**
+ * @param SchemaLoader|null $loader
+ * @param int $max_errors
+ */
+ public function __construct( $loader = null, int $max_errors = 1 ) {
+ $this->loader = $loader ?? new SchemaLoader( new SchemaParser(), new SchemaResolver(), true );
+ $this->maxErrors = $max_errors;
+ }
+
+ /**
+ * @param $data
+ * @param bool|string|Uri|Schema|object $schema
+ * @param array|null $globals
+ * @param array|null $slots
+ * @return ValidationResult
+ */
+ public function validate( $data, $schema, $globals = null, $slots = null ): ValidationResult {
+ if ( is_string( $schema ) ) {
+ if ( $uri = Uri::parse( $schema, true ) ) {
+ $schema = $uri;
+ } else {
+ $schema = json_decode( $schema, false );
+ }
+ }
+
+ $error = null;
+ if ( is_bool( $schema ) ) {
+ $error = $this->dataValidation( $data, $schema, $globals, $slots );
+ } elseif ( is_object( $schema ) ) {
+ if ( $schema instanceof Uri ) {
+ $error = $this->uriValidation( $data, $schema, $globals, $slots );
+ } elseif ( $schema instanceof Schema ) {
+ $error = $this->schemaValidation( $data, $schema, $globals, $slots );
+ } else {
+ $error = $this->dataValidation( $data, $schema, $globals, $slots );
+ }
+ } else {
+ throw new InvalidArgumentException( 'Invalid schema' );
+ }
+
+ return new ValidationResult( $error );
+ }
+
+ /**
+ * @param $data
+ * @param Uri|string $uri
+ * @param array|null $globals
+ * @param array|null $slots
+ * @return null|ValidationError
+ */
+ public function uriValidation( $data, $uri, $globals = null, $slots = null ) {
+ if ( is_string( $uri ) ) {
+ $uri = Uri::parse( $uri, true );
+ }
+
+ if ( ! ( $uri instanceof Uri ) ) {
+ throw new InvalidArgumentException( 'Invalid uri' );
+ }
+
+ if ( $uri->fragment() === null ) {
+ $uri = Uri::merge( $uri, null, true );
+ }
+
+ $schema = $this->loader->loadSchemaById( $uri );
+
+ if ( $schema === null ) {
+ throw new RuntimeException( "Schema not found: $uri" );
+ }
+
+ return $this->schemaValidation( $data, $schema, $globals, $slots );
+ }
+
+ /**
+ * @param $data
+ * @param string|object|bool $schema
+ * @param array|null $globals
+ * @param array|null $slots
+ * @param string|null $id
+ * @param string|null $draft
+ * @return ValidationError|null
+ */
+ public function dataValidation(
+ $data,
+ $schema,
+ $globals = null,
+ $slots = null,
+ $id = null,
+ $draft = null
+ ) {
+ if ( is_string( $schema ) ) {
+ $schema = json_decode( $schema, false );
+ }
+
+ if ( $schema === true ) {
+ return null;
+ }
+
+ if ( $schema === false ) {
+ $schema = $this->loader->loadBooleanSchema( false, $id, $draft );
+ } else {
+ if ( ! is_object( $schema ) ) {
+ throw new InvalidArgumentException( 'Invalid schema' );
+ }
+
+ $schema = $this->loader->loadObjectSchema( $schema, $id, $draft );
+ }
+
+ return $this->schemaValidation( $data, $schema, $globals, $slots );
+ }
+
+ /**
+ * @param $data
+ * @param Schema $schema
+ * @param array|null $globals
+ * @param array|null $slots
+ * @return null|ValidationError
+ */
+ public function schemaValidation(
+ $data,
+ $schema,
+ $globals = null,
+ $slots = null
+ ) {
+ return $schema->validate( $this->createContext( $data, $globals, $slots ) );
+ }
+
+ /**
+ * @param $data
+ * @param array|null $globals
+ * @param array|null $slots
+ * @return ValidationContext
+ */
+ public function createContext( $data, $globals = null, $slots = null ): ValidationContext {
+ if ( $slots ) {
+ $slots = $this->parseSlots( $slots );
+ }
+
+ return new ValidationContext( $data, $this->loader, null, null, $globals ?? array(), $slots, $this->maxErrors );
+ }
+
+ /**
+ * @return SchemaParser
+ */
+ public function parser(): SchemaParser {
+ return $this->loader->parser();
+ }
+
+ /**
+ * @param SchemaParser $parser
+ * @return Validator
+ */
+ public function setParser( $parser ): self {
+ $this->loader->setParser( $parser );
+
+ return $this;
+ }
+
+ /**
+ * @return SchemaResolver|null
+ */
+ public function resolver() {
+ return $this->loader->resolver();
+ }
+
+ /**
+ * @param SchemaResolver|null $resolver
+ * @return Validator
+ */
+ public function setResolver( $resolver ): self {
+ $this->loader->setResolver( $resolver );
+
+ return $this;
+ }
+
+ /**
+ * @return SchemaLoader
+ */
+ public function loader(): SchemaLoader {
+ return $this->loader;
+ }
+
+ /**
+ * @param SchemaLoader $loader
+ * @return Validator
+ */
+ public function setLoader( $loader ): self {
+ $this->loader = $loader;
+
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxErrors(): int {
+ return $this->maxErrors;
+ }
+
+ /**
+ * @param int $max_errors
+ * @return Validator
+ */
+ public function setMaxErrors( $max_errors ): self {
+ $this->maxErrors = $max_errors;
+
+ return $this;
+ }
+
+ /**
+ * @param array $slots
+ * @return array
+ */
+ protected function parseSlots( $slots ): array {
+ foreach ( $slots as $name => &$value ) {
+ if ( ! is_string( $name ) ) {
+ unset( $slots[ $name ] );
+ continue;
+ }
+
+ if ( is_string( $value ) ) {
+ $value = Uri::parse( $value, true );
+ }
+
+ if ( $value instanceof Uri ) {
+ $value = $this->loader->loadSchemaById( $value );
+ } elseif ( is_bool( $value ) ) {
+ $value = $this->loader->loadBooleanSchema( $value );
+ }
+
+ if ( ! is_object( $value ) ) {
+ unset( $slots[ $name ] );
+ }
+
+ unset( $value );
+ }
+
+ return $slots;
+ }
}
diff --git a/src/opis/json-schema/src/Variables.php b/src/opis/json-schema/src/Variables.php
index 9837173e..23dbbc5b 100644
--- a/src/opis/json-schema/src/Variables.php
+++ b/src/opis/json-schema/src/Variables.php
@@ -1,5 +1,6 @@
pointer = $pointer;
- $this->each = $each;
- $this->hasDefault = func_num_args() === 3;
- $this->defaultValue = $default;
- }
-
- /**
- * @return JsonPointer
- */
- public function pointer(): JsonPointer
- {
- return $this->pointer;
- }
-
- /**
- * @return null|Variables
- */
- public function each()
- {
- return $this->each;
- }
-
- /**
- * @return bool
- */
- public function hasDefaultValue(): bool
- {
- return $this->hasDefault;
- }
-
- /**
- * @return mixed|null
- */
- public function defaultValue()
- {
- return $this->defaultValue;
- }
-
- /**
- * @inheritDoc
- * @param mixed[] $path
- */
- public function resolve($data, $path = [])
- {
- $resolved = $this->pointer->data($data, $path, $this);
- if ($resolved === $this) {
- return $this->defaultValue;
- }
-
- if ($this->each && (is_array($resolved) || is_object($resolved))) {
- $path = $this->pointer->absolutePath($path);
- foreach ($resolved as $key => &$value) {
- $path[] = $key;
- $value = $this->each->resolve($data, $path);
- array_pop($path);
- unset($value);
- }
- }
-
- return $resolved;
- }
+final class RefVariablesContainer implements Variables {
+
+
+ /**
+ * @var \Opis\JsonSchema\JsonPointer
+ */
+ private $pointer;
+
+ /**
+ * @var \Opis\JsonSchema\Variables|null
+ */
+ private $each;
+
+ /**
+ * @var bool
+ */
+ private $hasDefault;
+
+ /** @var mixed */
+ private $defaultValue;
+
+ /**
+ * @param JsonPointer $pointer
+ * @param Variables|null $each
+ * @param mixed $default
+ */
+ public function __construct( JsonPointer $pointer, $each = null, $default = null ) {
+ $this->pointer = $pointer;
+ $this->each = $each;
+ $this->hasDefault = func_num_args() === 3;
+ $this->defaultValue = $default;
+ }
+
+ /**
+ * @return JsonPointer
+ */
+ public function pointer(): JsonPointer {
+ return $this->pointer;
+ }
+
+ /**
+ * @return null|Variables
+ */
+ public function each() {
+ return $this->each;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasDefaultValue(): bool {
+ return $this->hasDefault;
+ }
+
+ /**
+ * @return mixed|null
+ */
+ public function defaultValue() {
+ return $this->defaultValue;
+ }
+
+ /**
+ * @inheritDoc
+ * @param mixed[] $path
+ */
+ public function resolve( $data, $path = array() ) {
+ $resolved = $this->pointer->data( $data, $path, $this );
+ if ( $resolved === $this ) {
+ return $this->defaultValue;
+ }
+
+ if ( $this->each && ( is_array( $resolved ) || is_object( $resolved ) ) ) {
+ $path = $this->pointer->absolutePath( $path );
+ foreach ( $resolved as $key => &$value ) {
+ $path[] = $key;
+ $value = $this->each->resolve( $data, $path );
+ array_pop( $path );
+ unset( $value );
+ }
+ }
+
+ return $resolved;
+ }
}
diff --git a/src/opis/json-schema/src/Variables/VariablesContainer.php b/src/opis/json-schema/src/Variables/VariablesContainer.php
index 0a627d3c..70a406ca 100644
--- a/src/opis/json-schema/src/Variables/VariablesContainer.php
+++ b/src/opis/json-schema/src/Variables/VariablesContainer.php
@@ -1,5 +1,6 @@
keys = [
- 'ref' => $ref_key,
- 'each' => $each_key,
- 'default' => $default_key,
- ];
-
- if ($lazy) {
- $this->vars = $data;
- } else {
- $this->parsed = true;
- $this->vars = $this->parse($data);
- }
- }
-
- /**
- * @inheritdoc
- * @param mixed[] $path
- */
- public function resolve($data, $path = [])
- {
- if (!$this->parsed) {
- $this->vars = $this->parse($this->vars);
- $this->parsed = true;
- }
-
- if (!$this->hasRefs) {
- // Nothing to resolve
- return $this->vars;
- }
-
- return $this->deepClone($this->vars, $data, $path);
- }
-
- /**
- * @param $vars
- * @param $data
- * @param string[]|int[] $path
- * @return array|object|mixed
- */
- private function deepClone($vars, $data, array $path)
- {
- $toObject = false;
- if (is_object($vars)) {
- if ($vars instanceof Variables) {
- return $vars->resolve($data, $path);
- }
- $vars = get_object_vars($vars);
- $toObject = true;
- } elseif (!is_array($vars)) {
- return $vars;
- }
-
- foreach ($vars as &$var) {
- if ($var !== null && !is_scalar($var)) {
- $var = $this->deepClone($var, $data, $path);
- }
- unset($var);
- }
-
- return $toObject ? (object)$vars : $vars;
- }
-
- /**
- * @param mixed $data
- * @return mixed
- */
- private function parse($data)
- {
- if (is_array($data)) {
- return array_map([$this, 'parse'], $data);
- }
-
- if (!is_object($data)) {
- return $data;
- }
-
- if ($vars = $this->parseRef($data)) {
- $this->hasRefs = true;
-
- return $vars;
- }
-
- return (object)array_map([$this, 'parse'], get_object_vars($data));
- }
-
- /**
- * @param object $data
- * @return null|Variables
- */
- private function parseRef($data)
- {
- if (!property_exists($data, $this->keys['ref'])) {
- return null;
- }
-
- $ref = $data->{$this->keys['ref']};
- if (!is_string($ref)) {
- return null;
- }
-
- $pointer = JsonPointer::parse($ref);
- if ($pointer === null) {
- return null;
- }
-
- $each = null;
- if (property_exists($data, $this->keys['each']) && is_object($data->{$this->keys['each']})) {
- $each = new self($data->{$this->keys['each']}, !$this->parsed, $this->keys['ref'], $this->keys['each'], $this->keys['default']);
- }
-
- if (property_exists($data, $this->keys['default'])) {
- return new RefVariablesContainer($pointer, $each, $data->{$this->keys['default']});
- }
-
- return new RefVariablesContainer($pointer, $each);
- }
+final class VariablesContainer implements Variables {
+
+
+ /**
+ * @var array|object|Variables|null
+ */
+ private $vars;
+
+ /**
+ * @var bool
+ */
+ private $parsed = false;
+
+ /**
+ * @var bool
+ */
+ private $hasRefs = false;
+
+ /** @var string[] */
+ private $keys;
+
+ /**
+ * @param array|object $data
+ * @param bool $lazy
+ * @param string $ref_key
+ * @param string $each_key
+ * @param string $default_key
+ */
+ public function __construct( $data, bool $lazy = true, string $ref_key = '$ref', string $each_key = '$each', string $default_key = 'default' ) {
+ $this->keys = array(
+ 'ref' => $ref_key,
+ 'each' => $each_key,
+ 'default' => $default_key,
+ );
+
+ if ( $lazy ) {
+ $this->vars = $data;
+ } else {
+ $this->parsed = true;
+ $this->vars = $this->parse( $data );
+ }
+ }
+
+ /**
+ * @inheritdoc
+ * @param mixed[] $path
+ */
+ public function resolve( $data, $path = array() ) {
+ if ( ! $this->parsed ) {
+ $this->vars = $this->parse( $this->vars );
+ $this->parsed = true;
+ }
+
+ if ( ! $this->hasRefs ) {
+ // Nothing to resolve
+ return $this->vars;
+ }
+
+ return $this->deepClone( $this->vars, $data, $path );
+ }
+
+ /**
+ * @param $vars
+ * @param $data
+ * @param string[]|int[] $path
+ * @return array|object|mixed
+ */
+ private function deepClone( $vars, $data, array $path ) {
+ $toObject = false;
+ if ( is_object( $vars ) ) {
+ if ( $vars instanceof Variables ) {
+ return $vars->resolve( $data, $path );
+ }
+ $vars = get_object_vars( $vars );
+ $toObject = true;
+ } elseif ( ! is_array( $vars ) ) {
+ return $vars;
+ }
+
+ foreach ( $vars as &$var ) {
+ if ( $var !== null && ! is_scalar( $var ) ) {
+ $var = $this->deepClone( $var, $data, $path );
+ }
+ unset( $var );
+ }
+
+ return $toObject ? (object) $vars : $vars;
+ }
+
+ /**
+ * @param mixed $data
+ * @return mixed
+ */
+ private function parse( $data ) {
+ if ( is_array( $data ) ) {
+ return array_map( array( $this, 'parse' ), $data );
+ }
+
+ if ( ! is_object( $data ) ) {
+ return $data;
+ }
+
+ if ( $vars = $this->parseRef( $data ) ) {
+ $this->hasRefs = true;
+
+ return $vars;
+ }
+
+ return (object) array_map( array( $this, 'parse' ), get_object_vars( $data ) );
+ }
+
+ /**
+ * @param object $data
+ * @return null|Variables
+ */
+ private function parseRef( $data ) {
+ if ( ! property_exists( $data, $this->keys['ref'] ) ) {
+ return null;
+ }
+
+ $ref = $data->{$this->keys['ref']};
+ if ( ! is_string( $ref ) ) {
+ return null;
+ }
+
+ $pointer = JsonPointer::parse( $ref );
+ if ( $pointer === null ) {
+ return null;
+ }
+
+ $each = null;
+ if ( property_exists( $data, $this->keys['each'] ) && is_object( $data->{$this->keys['each']} ) ) {
+ $each = new self( $data->{$this->keys['each']}, ! $this->parsed, $this->keys['ref'], $this->keys['each'], $this->keys['default'] );
+ }
+
+ if ( property_exists( $data, $this->keys['default'] ) ) {
+ return new RefVariablesContainer( $pointer, $each, $data->{$this->keys['default']} );
+ }
+
+ return new RefVariablesContainer( $pointer, $each );
+ }
}
diff --git a/src/opis/string/res/ascii.php b/src/opis/string/res/ascii.php
index 000a19fc..b0a5f0a9 100644
--- a/src/opis/string/res/ascii.php
+++ b/src/opis/string/res/ascii.php
@@ -1,751 +1,751 @@
0x28,
-0xAA => 0x61,
-0xB0 => 0x30,
-0xB2 => 0x32,
-0xB3 => 0x33,
-0xB5 => 0x75,
-0xB9 => 0x31,
-0xBA => 0x6F,
-0xC0 => 0x41,
-0xC1 => 0x41,
-0xC2 => 0x41,
-0xC3 => 0x41,
-0xC4 => 0x41,
-0xC5 => 0x41,
-0xC6 => 0x41,
-0xC7 => 0x43,
-0xC8 => 0x45,
-0xC9 => 0x45,
-0xCA => 0x45,
-0xCB => 0x45,
-0xCC => 0x49,
-0xCD => 0x49,
-0xCE => 0x49,
-0xCF => 0x49,
-0xD0 => 0x44,
-0xD1 => 0x4E,
-0xD2 => 0x4F,
-0xD3 => 0x4F,
-0xD4 => 0x4F,
-0xD5 => 0x4F,
-0xD6 => 0x4F,
-0xD8 => 0x4F,
-0xD9 => 0x55,
-0xDA => 0x55,
-0xDB => 0x55,
-0xDC => 0x55,
-0xDD => 0x59,
-0xDE => 0x54,
-0xDF => 0x73,
-0xE0 => 0x61,
-0xE1 => 0x61,
-0xE2 => 0x61,
-0xE3 => 0x61,
-0xE4 => 0x61,
-0xE5 => 0x61,
-0xE6 => 0x61,
-0xE7 => 0x63,
-0xE8 => 0x65,
-0xE9 => 0x65,
-0xEA => 0x65,
-0xEB => 0x65,
-0xEC => 0x69,
-0xED => 0x69,
-0xEE => 0x69,
-0xEF => 0x69,
-0xF0 => 0x64,
-0xF1 => 0x6E,
-0xF2 => 0x6F,
-0xF3 => 0x6F,
-0xF4 => 0x6F,
-0xF5 => 0x6F,
-0xF6 => 0x6F,
-0xF8 => 0x6F,
-0xF9 => 0x75,
-0xFA => 0x75,
-0xFB => 0x75,
-0xFC => 0x75,
-0xFD => 0x79,
-0xFE => 0x74,
-0xFF => 0x79,
-0x100 => 0x41,
-0x101 => 0x61,
-0x102 => 0x41,
-0x103 => 0x61,
-0x104 => 0x41,
-0x105 => 0x61,
-0x106 => 0x43,
-0x107 => 0x63,
-0x108 => 0x43,
-0x109 => 0x63,
-0x10A => 0x43,
-0x10B => 0x63,
-0x10C => 0x43,
-0x10D => 0x63,
-0x10E => 0x44,
-0x10F => 0x64,
-0x110 => 0x44,
-0x111 => 0x64,
-0x112 => 0x45,
-0x113 => 0x65,
-0x114 => 0x45,
-0x115 => 0x65,
-0x116 => 0x45,
-0x117 => 0x65,
-0x118 => 0x45,
-0x119 => 0x65,
-0x11A => 0x45,
-0x11B => 0x65,
-0x11C => 0x47,
-0x11D => 0x67,
-0x11E => 0x47,
-0x11F => 0x67,
-0x120 => 0x47,
-0x121 => 0x67,
-0x122 => 0x47,
-0x123 => 0x67,
-0x124 => 0x48,
-0x125 => 0x68,
-0x126 => 0x48,
-0x127 => 0x68,
-0x128 => 0x49,
-0x129 => 0x69,
-0x12A => 0x49,
-0x12B => 0x69,
-0x12C => 0x49,
-0x12D => 0x69,
-0x12E => 0x49,
-0x12F => 0x69,
-0x130 => 0x49,
-0x131 => 0x69,
-0x132 => 0x49,
-0x133 => 0x69,
-0x134 => 0x4A,
-0x135 => 0x6A,
-0x136 => 0x6B,
-0x137 => 0x6B,
-0x138 => 0x6B,
-0x139 => 0x4C,
-0x13A => 0x6C,
-0x13B => 0x4C,
-0x13C => 0x6C,
-0x13D => 0x4C,
-0x13E => 0x6C,
-0x13F => 0x4C,
-0x140 => 0x6C,
-0x141 => 0x4C,
-0x142 => 0x6C,
-0x143 => 0x4E,
-0x144 => 0x6E,
-0x145 => 0x4E,
-0x146 => 0x6E,
-0x147 => 0x4E,
-0x148 => 0x6E,
-0x149 => 0x6E,
-0x14A => 0x4E,
-0x14B => 0x6E,
-0x14C => 0x4F,
-0x14D => 0x6F,
-0x14E => 0x4F,
-0x14F => 0x6F,
-0x150 => 0x4F,
-0x151 => 0x6F,
-0x152 => 0x4F,
-0x153 => 0x6F,
-0x154 => 0x52,
-0x155 => 0x72,
-0x156 => 0x52,
-0x157 => 0x72,
-0x158 => 0x52,
-0x159 => 0x72,
-0x15A => 0x53,
-0x15B => 0x73,
-0x15C => 0x53,
-0x15D => 0x73,
-0x15E => 0x53,
-0x15F => 0x73,
-0x160 => 0x53,
-0x161 => 0x73,
-0x162 => 0x54,
-0x163 => 0x74,
-0x164 => 0x54,
-0x165 => 0x74,
-0x166 => 0x54,
-0x167 => 0x74,
-0x168 => 0x55,
-0x169 => 0x75,
-0x16A => 0x55,
-0x16B => 0x75,
-0x16C => 0x55,
-0x16D => 0x75,
-0x16E => 0x55,
-0x16F => 0x75,
-0x170 => 0x55,
-0x171 => 0x75,
-0x172 => 0x55,
-0x173 => 0x75,
-0x174 => 0x57,
-0x175 => 0x77,
-0x176 => 0x59,
-0x177 => 0x79,
-0x178 => 0x59,
-0x179 => 0x5A,
-0x17A => 0x7A,
-0x17B => 0x5A,
-0x17C => 0x7A,
-0x17D => 0x5A,
-0x17E => 0x7A,
-0x17F => 0x73,
-0x189 => 0x44,
-0x18A => 0x44,
-0x18B => 0x44,
-0x18C => 0x64,
-0x18F => 0x45,
-0x192 => 0x66,
-0x1A0 => 0x4F,
-0x1A1 => 0x6F,
-0x1AF => 0x55,
-0x1B0 => 0x75,
-0x1CD => 0x41,
-0x1CE => 0x61,
-0x1CF => 0x49,
-0x1D0 => 0x69,
-0x1D1 => 0x4F,
-0x1D2 => 0x6F,
-0x1D3 => 0x55,
-0x1D4 => 0x75,
-0x1D5 => 0x55,
-0x1D6 => 0x75,
-0x1D7 => 0x55,
-0x1D8 => 0x75,
-0x1D9 => 0x55,
-0x1DA => 0x75,
-0x1DB => 0x55,
-0x1DC => 0x75,
-0x1FA => 0x41,
-0x1FB => 0x61,
-0x1FC => 0x41,
-0x1FD => 0x61,
-0x1FE => 0x4F,
-0x1FF => 0x6F,
-0x218 => 0x53,
-0x219 => 0x73,
-0x21A => 0x54,
-0x21B => 0x74,
-0x221 => 0x64,
-0x256 => 0x64,
-0x257 => 0x64,
-0x259 => 0x65,
-0x386 => 0x41,
-0x388 => 0x45,
-0x389 => 0x48,
-0x38A => 0x49,
-0x38C => 0x4F,
-0x38E => 0x59,
-0x38F => 0x57,
-0x390 => 0x69,
-0x391 => 0x41,
-0x392 => 0x42,
-0x393 => 0x47,
-0x394 => 0x44,
-0x395 => 0x45,
-0x396 => 0x5A,
-0x397 => 0x48,
-0x398 => 0x4F,
-0x399 => 0x49,
-0x39A => 0x4B,
-0x39B => 0x4C,
-0x39C => 0x4D,
-0x39D => 0x4E,
-0x39E => 0x58,
-0x39F => 0x4F,
-0x3A0 => 0x50,
-0x3A1 => 0x52,
-0x3A3 => 0x53,
-0x3A4 => 0x54,
-0x3A5 => 0x59,
-0x3A6 => 0x46,
-0x3A7 => 0x58,
-0x3A8 => 0x50,
-0x3A9 => 0x57,
-0x3AA => 0x49,
-0x3AB => 0x59,
-0x3AC => 0x61,
-0x3AD => 0x65,
-0x3AE => 0x68,
-0x3AF => 0x69,
-0x3B0 => 0x79,
-0x3B1 => 0x61,
-0x3B2 => 0x62,
-0x3B3 => 0x67,
-0x3B4 => 0x64,
-0x3B5 => 0x65,
-0x3B6 => 0x7A,
-0x3B7 => 0x68,
-0x3B8 => 0x6F,
-0x3B9 => 0x69,
-0x3BA => 0x6B,
-0x3BB => 0x6C,
-0x3BC => 0x6D,
-0x3BD => 0x6E,
-0x3BE => 0x78,
-0x3BF => 0x6F,
-0x3C0 => 0x70,
-0x3C1 => 0x72,
-0x3C2 => 0x73,
-0x3C3 => 0x73,
-0x3C4 => 0x74,
-0x3C5 => 0x79,
-0x3C6 => 0x66,
-0x3C7 => 0x78,
-0x3C8 => 0x70,
-0x3C9 => 0x77,
-0x3CA => 0x69,
-0x3CB => 0x79,
-0x3CC => 0x6F,
-0x3CD => 0x79,
-0x3CE => 0x77,
-0x3D0 => 0x76,
-0x3D1 => 0x74,
-0x3D2 => 0x49,
-0x401 => 0x45,
-0x402 => 0x44,
-0x404 => 0x45,
-0x406 => 0x49,
-0x407 => 0x49,
-0x408 => 0x6A,
-0x409 => 0x4C,
-0x40A => 0x4E,
-0x40F => 0x44,
-0x410 => 0x41,
-0x411 => 0x42,
-0x412 => 0x56,
-0x413 => 0x47,
-0x414 => 0x44,
-0x415 => 0x45,
-0x416 => 0x5A,
-0x417 => 0x5A,
-0x418 => 0x49,
-0x419 => 0x59,
-0x41A => 0x4B,
-0x41B => 0x4C,
-0x41C => 0x4D,
-0x41D => 0x4E,
-0x41E => 0x4F,
-0x41F => 0x50,
-0x420 => 0x52,
-0x421 => 0x53,
-0x422 => 0x54,
-0x423 => 0x55,
-0x424 => 0x46,
-0x425 => 0x4B,
-0x426 => 0x54,
-0x427 => 0x43,
-0x428 => 0x53,
-0x429 => 0x53,
-0x42A => 0x62,
-0x42B => 0x59,
-0x42C => 0x62,
-0x42D => 0x45,
-0x42E => 0x59,
-0x42F => 0x59,
-0x430 => 0x61,
-0x431 => 0x62,
-0x432 => 0x76,
-0x433 => 0x67,
-0x434 => 0x64,
-0x435 => 0x65,
-0x436 => 0x7A,
-0x437 => 0x7A,
-0x438 => 0x69,
-0x439 => 0x79,
-0x43A => 0x6B,
-0x43B => 0x6C,
-0x43C => 0x6D,
-0x43D => 0x6E,
-0x43E => 0x6F,
-0x43F => 0x70,
-0x440 => 0x72,
-0x441 => 0x73,
-0x442 => 0x74,
-0x443 => 0x75,
-0x444 => 0x66,
-0x445 => 0x6B,
-0x446 => 0x74,
-0x447 => 0x63,
-0x448 => 0x73,
-0x449 => 0x73,
-0x44B => 0x79,
-0x44D => 0x65,
-0x44E => 0x79,
-0x44F => 0x79,
-0x451 => 0x65,
-0x452 => 0x64,
-0x454 => 0x65,
-0x456 => 0x69,
-0x457 => 0x69,
-0x458 => 0x6A,
-0x459 => 0x6C,
-0x45A => 0x6E,
-0x45F => 0x64,
-0x490 => 0x47,
-0x491 => 0x67,
-0x4E8 => 0x4F,
-0x622 => 0x61,
-0x623 => 0x61,
-0x624 => 0x6F,
-0x625 => 0x65,
-0x626 => 0x65,
-0x627 => 0x61,
-0x628 => 0x62,
-0x62A => 0x74,
-0x62B => 0x74,
-0x62C => 0x6A,
-0x62D => 0x68,
-0x62E => 0x6B,
-0x62F => 0x64,
-0x630 => 0x74,
-0x631 => 0x72,
-0x632 => 0x7A,
-0x633 => 0x73,
-0x634 => 0x73,
-0x635 => 0x73,
-0x636 => 0x64,
-0x637 => 0x74,
-0x638 => 0x74,
-0x639 => 0x61,
-0x63A => 0x67,
-0x641 => 0x66,
-0x642 => 0x6B,
-0x643 => 0x6B,
-0x644 => 0x6C,
-0x645 => 0x6D,
-0x646 => 0x6E,
-0x647 => 0x68,
-0x648 => 0x6F,
-0x64A => 0x79,
-0x664 => 0x34,
-0x665 => 0x35,
-0x666 => 0x36,
-0x67E => 0x70,
-0x686 => 0x63,
-0x698 => 0x7A,
-0x6A9 => 0x6B,
-0x6AF => 0x67,
-0x6CC => 0x69,
-0x6F0 => 0x30,
-0x6F1 => 0x31,
-0x6F2 => 0x32,
-0x6F3 => 0x33,
-0x6F4 => 0x34,
-0x6F5 => 0x35,
-0x6F6 => 0x36,
-0x6F7 => 0x37,
-0x6F8 => 0x38,
-0x6F9 => 0x39,
-0x905 => 0x61,
-0x906 => 0x61,
-0x907 => 0x69,
-0x908 => 0x69,
-0x909 => 0x75,
-0x90A => 0x75,
-0x90D => 0x65,
-0x90F => 0x65,
-0x910 => 0x61,
-0x911 => 0x6F,
-0x912 => 0x6F,
-0x913 => 0x6F,
-0x92C => 0x42,
-0x932 => 0x4C,
-0x1000 => 0x6B,
-0x1002 => 0x67,
-0x1005 => 0x73,
-0x1007 => 0x7A,
-0x1009 => 0x75,
-0x100A => 0x69,
-0x100B => 0x74,
-0x100D => 0x64,
-0x1010 => 0x74,
-0x1012 => 0x64,
-0x1014 => 0x6E,
-0x1015 => 0x70,
-0x1017 => 0x62,
-0x1019 => 0x6D,
-0x101A => 0x79,
-0x101C => 0x6C,
-0x101D => 0x77,
-0x101F => 0x68,
-0x1021 => 0x61,
-0x1023 => 0x69,
-0x1027 => 0x65,
-0x102B => 0x61,
-0x102C => 0x61,
-0x102D => 0x6F,
-0x102E => 0x69,
-0x102F => 0x75,
-0x1030 => 0x75,
-0x1031 => 0x65,
-0x1032 => 0x65,
-0x103D => 0x77,
-0x103E => 0x68,
-0x10D0 => 0x61,
-0x10D1 => 0x62,
-0x10D2 => 0x67,
-0x10D3 => 0x64,
-0x10D4 => 0x65,
-0x10D5 => 0x76,
-0x10D6 => 0x7A,
-0x10D7 => 0x74,
-0x10D8 => 0x69,
-0x10D9 => 0x6B,
-0x10DA => 0x6C,
-0x10DB => 0x6D,
-0x10DC => 0x6E,
-0x10DD => 0x6F,
-0x10DE => 0x70,
-0x10DF => 0x7A,
-0x10E0 => 0x72,
-0x10E1 => 0x73,
-0x10E2 => 0x74,
-0x10E3 => 0x75,
-0x10E4 => 0x66,
-0x10E5 => 0x6B,
-0x10E6 => 0x67,
-0x10E7 => 0x71,
-0x10E8 => 0x73,
-0x10E9 => 0x63,
-0x10EA => 0x74,
-0x10EB => 0x64,
-0x10EC => 0x74,
-0x10ED => 0x63,
-0x10EE => 0x6B,
-0x10EF => 0x6A,
-0x10F0 => 0x68,
-0x1D05 => 0x44,
-0x1D06 => 0x44,
-0x1D6D => 0x64,
-0x1D81 => 0x64,
-0x1D91 => 0x64,
-0x1E9E => 0x53,
-0x1EA0 => 0x41,
-0x1EA1 => 0x61,
-0x1EA2 => 0x41,
-0x1EA3 => 0x61,
-0x1EA4 => 0x41,
-0x1EA5 => 0x61,
-0x1EA6 => 0x41,
-0x1EA7 => 0x61,
-0x1EA8 => 0x41,
-0x1EA9 => 0x61,
-0x1EAA => 0x41,
-0x1EAB => 0x61,
-0x1EAC => 0x41,
-0x1EAD => 0x61,
-0x1EAE => 0x41,
-0x1EAF => 0x61,
-0x1EB0 => 0x41,
-0x1EB1 => 0x61,
-0x1EB2 => 0x41,
-0x1EB3 => 0x61,
-0x1EB4 => 0x41,
-0x1EB5 => 0x61,
-0x1EB6 => 0x41,
-0x1EB7 => 0x61,
-0x1EB8 => 0x45,
-0x1EB9 => 0x65,
-0x1EBA => 0x45,
-0x1EBB => 0x65,
-0x1EBC => 0x45,
-0x1EBD => 0x65,
-0x1EBE => 0x45,
-0x1EBF => 0x65,
-0x1EC0 => 0x45,
-0x1EC1 => 0x65,
-0x1EC2 => 0x45,
-0x1EC3 => 0x65,
-0x1EC4 => 0x45,
-0x1EC5 => 0x65,
-0x1EC6 => 0x45,
-0x1EC7 => 0x65,
-0x1EC8 => 0x49,
-0x1EC9 => 0x69,
-0x1ECA => 0x49,
-0x1ECB => 0x69,
-0x1ECC => 0x4F,
-0x1ECD => 0x6F,
-0x1ECE => 0x4F,
-0x1ECF => 0x6F,
-0x1ED0 => 0x4F,
-0x1ED1 => 0x6F,
-0x1ED2 => 0x4F,
-0x1ED3 => 0x6F,
-0x1ED4 => 0x4F,
-0x1ED5 => 0x6F,
-0x1ED6 => 0x4F,
-0x1ED7 => 0x6F,
-0x1ED8 => 0x4F,
-0x1ED9 => 0x6F,
-0x1EDA => 0x4F,
-0x1EDB => 0x6F,
-0x1EDC => 0x4F,
-0x1EDD => 0x6F,
-0x1EDE => 0x4F,
-0x1EDF => 0x6F,
-0x1EE0 => 0x4F,
-0x1EE1 => 0x6F,
-0x1EE2 => 0x4F,
-0x1EE3 => 0x6F,
-0x1EE4 => 0x55,
-0x1EE5 => 0x75,
-0x1EE6 => 0x55,
-0x1EE7 => 0x75,
-0x1EE8 => 0x55,
-0x1EE9 => 0x75,
-0x1EEA => 0x55,
-0x1EEB => 0x75,
-0x1EEC => 0x55,
-0x1EED => 0x75,
-0x1EEE => 0x55,
-0x1EEF => 0x75,
-0x1EF0 => 0x55,
-0x1EF1 => 0x75,
-0x1EF2 => 0x59,
-0x1EF3 => 0x79,
-0x1EF4 => 0x59,
-0x1EF5 => 0x79,
-0x1EF6 => 0x59,
-0x1EF7 => 0x79,
-0x1EF8 => 0x59,
-0x1EF9 => 0x79,
-0x1F00 => 0x61,
-0x1F01 => 0x61,
-0x1F02 => 0x61,
-0x1F03 => 0x61,
-0x1F04 => 0x61,
-0x1F05 => 0x61,
-0x1F06 => 0x61,
-0x1F07 => 0x61,
-0x1F08 => 0x41,
-0x1F09 => 0x41,
-0x1F0A => 0x41,
-0x1F0B => 0x41,
-0x1F0C => 0x41,
-0x1F0D => 0x41,
-0x1F0E => 0x41,
-0x1F0F => 0x41,
-0x1F10 => 0x65,
-0x1F11 => 0x65,
-0x1F12 => 0x65,
-0x1F13 => 0x65,
-0x1F14 => 0x65,
-0x1F15 => 0x65,
-0x1F18 => 0x45,
-0x1F19 => 0x45,
-0x1F1A => 0x45,
-0x1F1B => 0x45,
-0x1F1C => 0x45,
-0x1F1D => 0x45,
-0x1F30 => 0x69,
-0x1F31 => 0x69,
-0x1F32 => 0x69,
-0x1F33 => 0x69,
-0x1F34 => 0x69,
-0x1F35 => 0x69,
-0x1F36 => 0x69,
-0x1F37 => 0x69,
-0x1F38 => 0x49,
-0x1F39 => 0x49,
-0x1F3B => 0x49,
-0x1F3C => 0x49,
-0x1F3D => 0x49,
-0x1F3E => 0x49,
-0x1F3F => 0x49,
-0x1F40 => 0x6F,
-0x1F41 => 0x6F,
-0x1F42 => 0x6F,
-0x1F43 => 0x6F,
-0x1F44 => 0x6F,
-0x1F45 => 0x6F,
-0x1F48 => 0x4F,
-0x1F49 => 0x4F,
-0x1F4A => 0x4F,
-0x1F4B => 0x4F,
-0x1F4C => 0x4F,
-0x1F4D => 0x4F,
-0x1F70 => 0x61,
-0x1F72 => 0x65,
-0x1F76 => 0x69,
-0x1F78 => 0x6F,
-0x1F80 => 0x61,
-0x1F81 => 0x61,
-0x1F82 => 0x61,
-0x1F83 => 0x61,
-0x1F84 => 0x61,
-0x1F85 => 0x61,
-0x1F86 => 0x61,
-0x1F87 => 0x61,
-0x1F88 => 0x41,
-0x1F89 => 0x41,
-0x1F8A => 0x41,
-0x1F8B => 0x41,
-0x1F8C => 0x41,
-0x1F8D => 0x41,
-0x1F8E => 0x41,
-0x1F8F => 0x41,
-0x1FB0 => 0x61,
-0x1FB1 => 0x61,
-0x1FB2 => 0x61,
-0x1FB3 => 0x61,
-0x1FB4 => 0x61,
-0x1FB6 => 0x61,
-0x1FB7 => 0x61,
-0x1FB8 => 0x41,
-0x1FB9 => 0x41,
-0x1FBA => 0x41,
-0x1FBC => 0x41,
-0x1FC8 => 0x45,
-0x1FD0 => 0x69,
-0x1FD1 => 0x69,
-0x1FD2 => 0x69,
-0x1FD6 => 0x69,
-0x1FD7 => 0x69,
-0x1FD8 => 0x49,
-0x1FD9 => 0x49,
-0x1FDA => 0x49,
-0x1FE8 => 0x59,
-0x1FE9 => 0x59,
-0x1FEA => 0x59,
-0x1FF8 => 0x4F,
-0x2000 => 0x20,
-0x2001 => 0x20,
-0x2002 => 0x20,
-0x2003 => 0x20,
-0x2004 => 0x20,
-0x2005 => 0x20,
-0x2006 => 0x20,
-0x2007 => 0x20,
-0x2008 => 0x20,
-0x2009 => 0x20,
-0x200A => 0x20,
-0x202F => 0x20,
-0x205F => 0x20,
-0x2074 => 0x34,
-0x2075 => 0x35,
-0x2076 => 0x36,
-0x2077 => 0x37,
-0x2078 => 0x38,
-0x2079 => 0x39,
-0x2080 => 0x30,
-0x2081 => 0x31,
-0x2082 => 0x32,
-0x2083 => 0x33,
-0x2084 => 0x34,
-0x2085 => 0x35,
-0x2086 => 0x36,
-0x2087 => 0x37,
-0x2088 => 0x38,
-0x2089 => 0x39,
-0x3000 => 0x20,
-];
+return array(
+ 0xA9 => 0x28,
+ 0xAA => 0x61,
+ 0xB0 => 0x30,
+ 0xB2 => 0x32,
+ 0xB3 => 0x33,
+ 0xB5 => 0x75,
+ 0xB9 => 0x31,
+ 0xBA => 0x6F,
+ 0xC0 => 0x41,
+ 0xC1 => 0x41,
+ 0xC2 => 0x41,
+ 0xC3 => 0x41,
+ 0xC4 => 0x41,
+ 0xC5 => 0x41,
+ 0xC6 => 0x41,
+ 0xC7 => 0x43,
+ 0xC8 => 0x45,
+ 0xC9 => 0x45,
+ 0xCA => 0x45,
+ 0xCB => 0x45,
+ 0xCC => 0x49,
+ 0xCD => 0x49,
+ 0xCE => 0x49,
+ 0xCF => 0x49,
+ 0xD0 => 0x44,
+ 0xD1 => 0x4E,
+ 0xD2 => 0x4F,
+ 0xD3 => 0x4F,
+ 0xD4 => 0x4F,
+ 0xD5 => 0x4F,
+ 0xD6 => 0x4F,
+ 0xD8 => 0x4F,
+ 0xD9 => 0x55,
+ 0xDA => 0x55,
+ 0xDB => 0x55,
+ 0xDC => 0x55,
+ 0xDD => 0x59,
+ 0xDE => 0x54,
+ 0xDF => 0x73,
+ 0xE0 => 0x61,
+ 0xE1 => 0x61,
+ 0xE2 => 0x61,
+ 0xE3 => 0x61,
+ 0xE4 => 0x61,
+ 0xE5 => 0x61,
+ 0xE6 => 0x61,
+ 0xE7 => 0x63,
+ 0xE8 => 0x65,
+ 0xE9 => 0x65,
+ 0xEA => 0x65,
+ 0xEB => 0x65,
+ 0xEC => 0x69,
+ 0xED => 0x69,
+ 0xEE => 0x69,
+ 0xEF => 0x69,
+ 0xF0 => 0x64,
+ 0xF1 => 0x6E,
+ 0xF2 => 0x6F,
+ 0xF3 => 0x6F,
+ 0xF4 => 0x6F,
+ 0xF5 => 0x6F,
+ 0xF6 => 0x6F,
+ 0xF8 => 0x6F,
+ 0xF9 => 0x75,
+ 0xFA => 0x75,
+ 0xFB => 0x75,
+ 0xFC => 0x75,
+ 0xFD => 0x79,
+ 0xFE => 0x74,
+ 0xFF => 0x79,
+ 0x100 => 0x41,
+ 0x101 => 0x61,
+ 0x102 => 0x41,
+ 0x103 => 0x61,
+ 0x104 => 0x41,
+ 0x105 => 0x61,
+ 0x106 => 0x43,
+ 0x107 => 0x63,
+ 0x108 => 0x43,
+ 0x109 => 0x63,
+ 0x10A => 0x43,
+ 0x10B => 0x63,
+ 0x10C => 0x43,
+ 0x10D => 0x63,
+ 0x10E => 0x44,
+ 0x10F => 0x64,
+ 0x110 => 0x44,
+ 0x111 => 0x64,
+ 0x112 => 0x45,
+ 0x113 => 0x65,
+ 0x114 => 0x45,
+ 0x115 => 0x65,
+ 0x116 => 0x45,
+ 0x117 => 0x65,
+ 0x118 => 0x45,
+ 0x119 => 0x65,
+ 0x11A => 0x45,
+ 0x11B => 0x65,
+ 0x11C => 0x47,
+ 0x11D => 0x67,
+ 0x11E => 0x47,
+ 0x11F => 0x67,
+ 0x120 => 0x47,
+ 0x121 => 0x67,
+ 0x122 => 0x47,
+ 0x123 => 0x67,
+ 0x124 => 0x48,
+ 0x125 => 0x68,
+ 0x126 => 0x48,
+ 0x127 => 0x68,
+ 0x128 => 0x49,
+ 0x129 => 0x69,
+ 0x12A => 0x49,
+ 0x12B => 0x69,
+ 0x12C => 0x49,
+ 0x12D => 0x69,
+ 0x12E => 0x49,
+ 0x12F => 0x69,
+ 0x130 => 0x49,
+ 0x131 => 0x69,
+ 0x132 => 0x49,
+ 0x133 => 0x69,
+ 0x134 => 0x4A,
+ 0x135 => 0x6A,
+ 0x136 => 0x6B,
+ 0x137 => 0x6B,
+ 0x138 => 0x6B,
+ 0x139 => 0x4C,
+ 0x13A => 0x6C,
+ 0x13B => 0x4C,
+ 0x13C => 0x6C,
+ 0x13D => 0x4C,
+ 0x13E => 0x6C,
+ 0x13F => 0x4C,
+ 0x140 => 0x6C,
+ 0x141 => 0x4C,
+ 0x142 => 0x6C,
+ 0x143 => 0x4E,
+ 0x144 => 0x6E,
+ 0x145 => 0x4E,
+ 0x146 => 0x6E,
+ 0x147 => 0x4E,
+ 0x148 => 0x6E,
+ 0x149 => 0x6E,
+ 0x14A => 0x4E,
+ 0x14B => 0x6E,
+ 0x14C => 0x4F,
+ 0x14D => 0x6F,
+ 0x14E => 0x4F,
+ 0x14F => 0x6F,
+ 0x150 => 0x4F,
+ 0x151 => 0x6F,
+ 0x152 => 0x4F,
+ 0x153 => 0x6F,
+ 0x154 => 0x52,
+ 0x155 => 0x72,
+ 0x156 => 0x52,
+ 0x157 => 0x72,
+ 0x158 => 0x52,
+ 0x159 => 0x72,
+ 0x15A => 0x53,
+ 0x15B => 0x73,
+ 0x15C => 0x53,
+ 0x15D => 0x73,
+ 0x15E => 0x53,
+ 0x15F => 0x73,
+ 0x160 => 0x53,
+ 0x161 => 0x73,
+ 0x162 => 0x54,
+ 0x163 => 0x74,
+ 0x164 => 0x54,
+ 0x165 => 0x74,
+ 0x166 => 0x54,
+ 0x167 => 0x74,
+ 0x168 => 0x55,
+ 0x169 => 0x75,
+ 0x16A => 0x55,
+ 0x16B => 0x75,
+ 0x16C => 0x55,
+ 0x16D => 0x75,
+ 0x16E => 0x55,
+ 0x16F => 0x75,
+ 0x170 => 0x55,
+ 0x171 => 0x75,
+ 0x172 => 0x55,
+ 0x173 => 0x75,
+ 0x174 => 0x57,
+ 0x175 => 0x77,
+ 0x176 => 0x59,
+ 0x177 => 0x79,
+ 0x178 => 0x59,
+ 0x179 => 0x5A,
+ 0x17A => 0x7A,
+ 0x17B => 0x5A,
+ 0x17C => 0x7A,
+ 0x17D => 0x5A,
+ 0x17E => 0x7A,
+ 0x17F => 0x73,
+ 0x189 => 0x44,
+ 0x18A => 0x44,
+ 0x18B => 0x44,
+ 0x18C => 0x64,
+ 0x18F => 0x45,
+ 0x192 => 0x66,
+ 0x1A0 => 0x4F,
+ 0x1A1 => 0x6F,
+ 0x1AF => 0x55,
+ 0x1B0 => 0x75,
+ 0x1CD => 0x41,
+ 0x1CE => 0x61,
+ 0x1CF => 0x49,
+ 0x1D0 => 0x69,
+ 0x1D1 => 0x4F,
+ 0x1D2 => 0x6F,
+ 0x1D3 => 0x55,
+ 0x1D4 => 0x75,
+ 0x1D5 => 0x55,
+ 0x1D6 => 0x75,
+ 0x1D7 => 0x55,
+ 0x1D8 => 0x75,
+ 0x1D9 => 0x55,
+ 0x1DA => 0x75,
+ 0x1DB => 0x55,
+ 0x1DC => 0x75,
+ 0x1FA => 0x41,
+ 0x1FB => 0x61,
+ 0x1FC => 0x41,
+ 0x1FD => 0x61,
+ 0x1FE => 0x4F,
+ 0x1FF => 0x6F,
+ 0x218 => 0x53,
+ 0x219 => 0x73,
+ 0x21A => 0x54,
+ 0x21B => 0x74,
+ 0x221 => 0x64,
+ 0x256 => 0x64,
+ 0x257 => 0x64,
+ 0x259 => 0x65,
+ 0x386 => 0x41,
+ 0x388 => 0x45,
+ 0x389 => 0x48,
+ 0x38A => 0x49,
+ 0x38C => 0x4F,
+ 0x38E => 0x59,
+ 0x38F => 0x57,
+ 0x390 => 0x69,
+ 0x391 => 0x41,
+ 0x392 => 0x42,
+ 0x393 => 0x47,
+ 0x394 => 0x44,
+ 0x395 => 0x45,
+ 0x396 => 0x5A,
+ 0x397 => 0x48,
+ 0x398 => 0x4F,
+ 0x399 => 0x49,
+ 0x39A => 0x4B,
+ 0x39B => 0x4C,
+ 0x39C => 0x4D,
+ 0x39D => 0x4E,
+ 0x39E => 0x58,
+ 0x39F => 0x4F,
+ 0x3A0 => 0x50,
+ 0x3A1 => 0x52,
+ 0x3A3 => 0x53,
+ 0x3A4 => 0x54,
+ 0x3A5 => 0x59,
+ 0x3A6 => 0x46,
+ 0x3A7 => 0x58,
+ 0x3A8 => 0x50,
+ 0x3A9 => 0x57,
+ 0x3AA => 0x49,
+ 0x3AB => 0x59,
+ 0x3AC => 0x61,
+ 0x3AD => 0x65,
+ 0x3AE => 0x68,
+ 0x3AF => 0x69,
+ 0x3B0 => 0x79,
+ 0x3B1 => 0x61,
+ 0x3B2 => 0x62,
+ 0x3B3 => 0x67,
+ 0x3B4 => 0x64,
+ 0x3B5 => 0x65,
+ 0x3B6 => 0x7A,
+ 0x3B7 => 0x68,
+ 0x3B8 => 0x6F,
+ 0x3B9 => 0x69,
+ 0x3BA => 0x6B,
+ 0x3BB => 0x6C,
+ 0x3BC => 0x6D,
+ 0x3BD => 0x6E,
+ 0x3BE => 0x78,
+ 0x3BF => 0x6F,
+ 0x3C0 => 0x70,
+ 0x3C1 => 0x72,
+ 0x3C2 => 0x73,
+ 0x3C3 => 0x73,
+ 0x3C4 => 0x74,
+ 0x3C5 => 0x79,
+ 0x3C6 => 0x66,
+ 0x3C7 => 0x78,
+ 0x3C8 => 0x70,
+ 0x3C9 => 0x77,
+ 0x3CA => 0x69,
+ 0x3CB => 0x79,
+ 0x3CC => 0x6F,
+ 0x3CD => 0x79,
+ 0x3CE => 0x77,
+ 0x3D0 => 0x76,
+ 0x3D1 => 0x74,
+ 0x3D2 => 0x49,
+ 0x401 => 0x45,
+ 0x402 => 0x44,
+ 0x404 => 0x45,
+ 0x406 => 0x49,
+ 0x407 => 0x49,
+ 0x408 => 0x6A,
+ 0x409 => 0x4C,
+ 0x40A => 0x4E,
+ 0x40F => 0x44,
+ 0x410 => 0x41,
+ 0x411 => 0x42,
+ 0x412 => 0x56,
+ 0x413 => 0x47,
+ 0x414 => 0x44,
+ 0x415 => 0x45,
+ 0x416 => 0x5A,
+ 0x417 => 0x5A,
+ 0x418 => 0x49,
+ 0x419 => 0x59,
+ 0x41A => 0x4B,
+ 0x41B => 0x4C,
+ 0x41C => 0x4D,
+ 0x41D => 0x4E,
+ 0x41E => 0x4F,
+ 0x41F => 0x50,
+ 0x420 => 0x52,
+ 0x421 => 0x53,
+ 0x422 => 0x54,
+ 0x423 => 0x55,
+ 0x424 => 0x46,
+ 0x425 => 0x4B,
+ 0x426 => 0x54,
+ 0x427 => 0x43,
+ 0x428 => 0x53,
+ 0x429 => 0x53,
+ 0x42A => 0x62,
+ 0x42B => 0x59,
+ 0x42C => 0x62,
+ 0x42D => 0x45,
+ 0x42E => 0x59,
+ 0x42F => 0x59,
+ 0x430 => 0x61,
+ 0x431 => 0x62,
+ 0x432 => 0x76,
+ 0x433 => 0x67,
+ 0x434 => 0x64,
+ 0x435 => 0x65,
+ 0x436 => 0x7A,
+ 0x437 => 0x7A,
+ 0x438 => 0x69,
+ 0x439 => 0x79,
+ 0x43A => 0x6B,
+ 0x43B => 0x6C,
+ 0x43C => 0x6D,
+ 0x43D => 0x6E,
+ 0x43E => 0x6F,
+ 0x43F => 0x70,
+ 0x440 => 0x72,
+ 0x441 => 0x73,
+ 0x442 => 0x74,
+ 0x443 => 0x75,
+ 0x444 => 0x66,
+ 0x445 => 0x6B,
+ 0x446 => 0x74,
+ 0x447 => 0x63,
+ 0x448 => 0x73,
+ 0x449 => 0x73,
+ 0x44B => 0x79,
+ 0x44D => 0x65,
+ 0x44E => 0x79,
+ 0x44F => 0x79,
+ 0x451 => 0x65,
+ 0x452 => 0x64,
+ 0x454 => 0x65,
+ 0x456 => 0x69,
+ 0x457 => 0x69,
+ 0x458 => 0x6A,
+ 0x459 => 0x6C,
+ 0x45A => 0x6E,
+ 0x45F => 0x64,
+ 0x490 => 0x47,
+ 0x491 => 0x67,
+ 0x4E8 => 0x4F,
+ 0x622 => 0x61,
+ 0x623 => 0x61,
+ 0x624 => 0x6F,
+ 0x625 => 0x65,
+ 0x626 => 0x65,
+ 0x627 => 0x61,
+ 0x628 => 0x62,
+ 0x62A => 0x74,
+ 0x62B => 0x74,
+ 0x62C => 0x6A,
+ 0x62D => 0x68,
+ 0x62E => 0x6B,
+ 0x62F => 0x64,
+ 0x630 => 0x74,
+ 0x631 => 0x72,
+ 0x632 => 0x7A,
+ 0x633 => 0x73,
+ 0x634 => 0x73,
+ 0x635 => 0x73,
+ 0x636 => 0x64,
+ 0x637 => 0x74,
+ 0x638 => 0x74,
+ 0x639 => 0x61,
+ 0x63A => 0x67,
+ 0x641 => 0x66,
+ 0x642 => 0x6B,
+ 0x643 => 0x6B,
+ 0x644 => 0x6C,
+ 0x645 => 0x6D,
+ 0x646 => 0x6E,
+ 0x647 => 0x68,
+ 0x648 => 0x6F,
+ 0x64A => 0x79,
+ 0x664 => 0x34,
+ 0x665 => 0x35,
+ 0x666 => 0x36,
+ 0x67E => 0x70,
+ 0x686 => 0x63,
+ 0x698 => 0x7A,
+ 0x6A9 => 0x6B,
+ 0x6AF => 0x67,
+ 0x6CC => 0x69,
+ 0x6F0 => 0x30,
+ 0x6F1 => 0x31,
+ 0x6F2 => 0x32,
+ 0x6F3 => 0x33,
+ 0x6F4 => 0x34,
+ 0x6F5 => 0x35,
+ 0x6F6 => 0x36,
+ 0x6F7 => 0x37,
+ 0x6F8 => 0x38,
+ 0x6F9 => 0x39,
+ 0x905 => 0x61,
+ 0x906 => 0x61,
+ 0x907 => 0x69,
+ 0x908 => 0x69,
+ 0x909 => 0x75,
+ 0x90A => 0x75,
+ 0x90D => 0x65,
+ 0x90F => 0x65,
+ 0x910 => 0x61,
+ 0x911 => 0x6F,
+ 0x912 => 0x6F,
+ 0x913 => 0x6F,
+ 0x92C => 0x42,
+ 0x932 => 0x4C,
+ 0x1000 => 0x6B,
+ 0x1002 => 0x67,
+ 0x1005 => 0x73,
+ 0x1007 => 0x7A,
+ 0x1009 => 0x75,
+ 0x100A => 0x69,
+ 0x100B => 0x74,
+ 0x100D => 0x64,
+ 0x1010 => 0x74,
+ 0x1012 => 0x64,
+ 0x1014 => 0x6E,
+ 0x1015 => 0x70,
+ 0x1017 => 0x62,
+ 0x1019 => 0x6D,
+ 0x101A => 0x79,
+ 0x101C => 0x6C,
+ 0x101D => 0x77,
+ 0x101F => 0x68,
+ 0x1021 => 0x61,
+ 0x1023 => 0x69,
+ 0x1027 => 0x65,
+ 0x102B => 0x61,
+ 0x102C => 0x61,
+ 0x102D => 0x6F,
+ 0x102E => 0x69,
+ 0x102F => 0x75,
+ 0x1030 => 0x75,
+ 0x1031 => 0x65,
+ 0x1032 => 0x65,
+ 0x103D => 0x77,
+ 0x103E => 0x68,
+ 0x10D0 => 0x61,
+ 0x10D1 => 0x62,
+ 0x10D2 => 0x67,
+ 0x10D3 => 0x64,
+ 0x10D4 => 0x65,
+ 0x10D5 => 0x76,
+ 0x10D6 => 0x7A,
+ 0x10D7 => 0x74,
+ 0x10D8 => 0x69,
+ 0x10D9 => 0x6B,
+ 0x10DA => 0x6C,
+ 0x10DB => 0x6D,
+ 0x10DC => 0x6E,
+ 0x10DD => 0x6F,
+ 0x10DE => 0x70,
+ 0x10DF => 0x7A,
+ 0x10E0 => 0x72,
+ 0x10E1 => 0x73,
+ 0x10E2 => 0x74,
+ 0x10E3 => 0x75,
+ 0x10E4 => 0x66,
+ 0x10E5 => 0x6B,
+ 0x10E6 => 0x67,
+ 0x10E7 => 0x71,
+ 0x10E8 => 0x73,
+ 0x10E9 => 0x63,
+ 0x10EA => 0x74,
+ 0x10EB => 0x64,
+ 0x10EC => 0x74,
+ 0x10ED => 0x63,
+ 0x10EE => 0x6B,
+ 0x10EF => 0x6A,
+ 0x10F0 => 0x68,
+ 0x1D05 => 0x44,
+ 0x1D06 => 0x44,
+ 0x1D6D => 0x64,
+ 0x1D81 => 0x64,
+ 0x1D91 => 0x64,
+ 0x1E9E => 0x53,
+ 0x1EA0 => 0x41,
+ 0x1EA1 => 0x61,
+ 0x1EA2 => 0x41,
+ 0x1EA3 => 0x61,
+ 0x1EA4 => 0x41,
+ 0x1EA5 => 0x61,
+ 0x1EA6 => 0x41,
+ 0x1EA7 => 0x61,
+ 0x1EA8 => 0x41,
+ 0x1EA9 => 0x61,
+ 0x1EAA => 0x41,
+ 0x1EAB => 0x61,
+ 0x1EAC => 0x41,
+ 0x1EAD => 0x61,
+ 0x1EAE => 0x41,
+ 0x1EAF => 0x61,
+ 0x1EB0 => 0x41,
+ 0x1EB1 => 0x61,
+ 0x1EB2 => 0x41,
+ 0x1EB3 => 0x61,
+ 0x1EB4 => 0x41,
+ 0x1EB5 => 0x61,
+ 0x1EB6 => 0x41,
+ 0x1EB7 => 0x61,
+ 0x1EB8 => 0x45,
+ 0x1EB9 => 0x65,
+ 0x1EBA => 0x45,
+ 0x1EBB => 0x65,
+ 0x1EBC => 0x45,
+ 0x1EBD => 0x65,
+ 0x1EBE => 0x45,
+ 0x1EBF => 0x65,
+ 0x1EC0 => 0x45,
+ 0x1EC1 => 0x65,
+ 0x1EC2 => 0x45,
+ 0x1EC3 => 0x65,
+ 0x1EC4 => 0x45,
+ 0x1EC5 => 0x65,
+ 0x1EC6 => 0x45,
+ 0x1EC7 => 0x65,
+ 0x1EC8 => 0x49,
+ 0x1EC9 => 0x69,
+ 0x1ECA => 0x49,
+ 0x1ECB => 0x69,
+ 0x1ECC => 0x4F,
+ 0x1ECD => 0x6F,
+ 0x1ECE => 0x4F,
+ 0x1ECF => 0x6F,
+ 0x1ED0 => 0x4F,
+ 0x1ED1 => 0x6F,
+ 0x1ED2 => 0x4F,
+ 0x1ED3 => 0x6F,
+ 0x1ED4 => 0x4F,
+ 0x1ED5 => 0x6F,
+ 0x1ED6 => 0x4F,
+ 0x1ED7 => 0x6F,
+ 0x1ED8 => 0x4F,
+ 0x1ED9 => 0x6F,
+ 0x1EDA => 0x4F,
+ 0x1EDB => 0x6F,
+ 0x1EDC => 0x4F,
+ 0x1EDD => 0x6F,
+ 0x1EDE => 0x4F,
+ 0x1EDF => 0x6F,
+ 0x1EE0 => 0x4F,
+ 0x1EE1 => 0x6F,
+ 0x1EE2 => 0x4F,
+ 0x1EE3 => 0x6F,
+ 0x1EE4 => 0x55,
+ 0x1EE5 => 0x75,
+ 0x1EE6 => 0x55,
+ 0x1EE7 => 0x75,
+ 0x1EE8 => 0x55,
+ 0x1EE9 => 0x75,
+ 0x1EEA => 0x55,
+ 0x1EEB => 0x75,
+ 0x1EEC => 0x55,
+ 0x1EED => 0x75,
+ 0x1EEE => 0x55,
+ 0x1EEF => 0x75,
+ 0x1EF0 => 0x55,
+ 0x1EF1 => 0x75,
+ 0x1EF2 => 0x59,
+ 0x1EF3 => 0x79,
+ 0x1EF4 => 0x59,
+ 0x1EF5 => 0x79,
+ 0x1EF6 => 0x59,
+ 0x1EF7 => 0x79,
+ 0x1EF8 => 0x59,
+ 0x1EF9 => 0x79,
+ 0x1F00 => 0x61,
+ 0x1F01 => 0x61,
+ 0x1F02 => 0x61,
+ 0x1F03 => 0x61,
+ 0x1F04 => 0x61,
+ 0x1F05 => 0x61,
+ 0x1F06 => 0x61,
+ 0x1F07 => 0x61,
+ 0x1F08 => 0x41,
+ 0x1F09 => 0x41,
+ 0x1F0A => 0x41,
+ 0x1F0B => 0x41,
+ 0x1F0C => 0x41,
+ 0x1F0D => 0x41,
+ 0x1F0E => 0x41,
+ 0x1F0F => 0x41,
+ 0x1F10 => 0x65,
+ 0x1F11 => 0x65,
+ 0x1F12 => 0x65,
+ 0x1F13 => 0x65,
+ 0x1F14 => 0x65,
+ 0x1F15 => 0x65,
+ 0x1F18 => 0x45,
+ 0x1F19 => 0x45,
+ 0x1F1A => 0x45,
+ 0x1F1B => 0x45,
+ 0x1F1C => 0x45,
+ 0x1F1D => 0x45,
+ 0x1F30 => 0x69,
+ 0x1F31 => 0x69,
+ 0x1F32 => 0x69,
+ 0x1F33 => 0x69,
+ 0x1F34 => 0x69,
+ 0x1F35 => 0x69,
+ 0x1F36 => 0x69,
+ 0x1F37 => 0x69,
+ 0x1F38 => 0x49,
+ 0x1F39 => 0x49,
+ 0x1F3B => 0x49,
+ 0x1F3C => 0x49,
+ 0x1F3D => 0x49,
+ 0x1F3E => 0x49,
+ 0x1F3F => 0x49,
+ 0x1F40 => 0x6F,
+ 0x1F41 => 0x6F,
+ 0x1F42 => 0x6F,
+ 0x1F43 => 0x6F,
+ 0x1F44 => 0x6F,
+ 0x1F45 => 0x6F,
+ 0x1F48 => 0x4F,
+ 0x1F49 => 0x4F,
+ 0x1F4A => 0x4F,
+ 0x1F4B => 0x4F,
+ 0x1F4C => 0x4F,
+ 0x1F4D => 0x4F,
+ 0x1F70 => 0x61,
+ 0x1F72 => 0x65,
+ 0x1F76 => 0x69,
+ 0x1F78 => 0x6F,
+ 0x1F80 => 0x61,
+ 0x1F81 => 0x61,
+ 0x1F82 => 0x61,
+ 0x1F83 => 0x61,
+ 0x1F84 => 0x61,
+ 0x1F85 => 0x61,
+ 0x1F86 => 0x61,
+ 0x1F87 => 0x61,
+ 0x1F88 => 0x41,
+ 0x1F89 => 0x41,
+ 0x1F8A => 0x41,
+ 0x1F8B => 0x41,
+ 0x1F8C => 0x41,
+ 0x1F8D => 0x41,
+ 0x1F8E => 0x41,
+ 0x1F8F => 0x41,
+ 0x1FB0 => 0x61,
+ 0x1FB1 => 0x61,
+ 0x1FB2 => 0x61,
+ 0x1FB3 => 0x61,
+ 0x1FB4 => 0x61,
+ 0x1FB6 => 0x61,
+ 0x1FB7 => 0x61,
+ 0x1FB8 => 0x41,
+ 0x1FB9 => 0x41,
+ 0x1FBA => 0x41,
+ 0x1FBC => 0x41,
+ 0x1FC8 => 0x45,
+ 0x1FD0 => 0x69,
+ 0x1FD1 => 0x69,
+ 0x1FD2 => 0x69,
+ 0x1FD6 => 0x69,
+ 0x1FD7 => 0x69,
+ 0x1FD8 => 0x49,
+ 0x1FD9 => 0x49,
+ 0x1FDA => 0x49,
+ 0x1FE8 => 0x59,
+ 0x1FE9 => 0x59,
+ 0x1FEA => 0x59,
+ 0x1FF8 => 0x4F,
+ 0x2000 => 0x20,
+ 0x2001 => 0x20,
+ 0x2002 => 0x20,
+ 0x2003 => 0x20,
+ 0x2004 => 0x20,
+ 0x2005 => 0x20,
+ 0x2006 => 0x20,
+ 0x2007 => 0x20,
+ 0x2008 => 0x20,
+ 0x2009 => 0x20,
+ 0x200A => 0x20,
+ 0x202F => 0x20,
+ 0x205F => 0x20,
+ 0x2074 => 0x34,
+ 0x2075 => 0x35,
+ 0x2076 => 0x36,
+ 0x2077 => 0x37,
+ 0x2078 => 0x38,
+ 0x2079 => 0x39,
+ 0x2080 => 0x30,
+ 0x2081 => 0x31,
+ 0x2082 => 0x32,
+ 0x2083 => 0x33,
+ 0x2084 => 0x34,
+ 0x2085 => 0x35,
+ 0x2086 => 0x36,
+ 0x2087 => 0x37,
+ 0x2088 => 0x38,
+ 0x2089 => 0x39,
+ 0x3000 => 0x20,
+);
diff --git a/src/opis/string/res/fold.php b/src/opis/string/res/fold.php
index e93f9819..efda4601 100644
--- a/src/opis/string/res/fold.php
+++ b/src/opis/string/res/fold.php
@@ -1,1417 +1,1417 @@
0x61,
-0x42 => 0x62,
-0x43 => 0x63,
-0x44 => 0x64,
-0x45 => 0x65,
-0x46 => 0x66,
-0x47 => 0x67,
-0x48 => 0x68,
-0x49 => 0x69,
-0x4A => 0x6A,
-0x4B => 0x6B,
-0x4C => 0x6C,
-0x4D => 0x6D,
-0x4E => 0x6E,
-0x4F => 0x6F,
-0x50 => 0x70,
-0x51 => 0x71,
-0x52 => 0x72,
-0x53 => 0x73,
-0x54 => 0x74,
-0x55 => 0x75,
-0x56 => 0x76,
-0x57 => 0x77,
-0x58 => 0x78,
-0x59 => 0x79,
-0x5A => 0x7A,
-0xB5 => 0x3BC,
-0xC0 => 0xE0,
-0xC1 => 0xE1,
-0xC2 => 0xE2,
-0xC3 => 0xE3,
-0xC4 => 0xE4,
-0xC5 => 0xE5,
-0xC6 => 0xE6,
-0xC7 => 0xE7,
-0xC8 => 0xE8,
-0xC9 => 0xE9,
-0xCA => 0xEA,
-0xCB => 0xEB,
-0xCC => 0xEC,
-0xCD => 0xED,
-0xCE => 0xEE,
-0xCF => 0xEF,
-0xD0 => 0xF0,
-0xD1 => 0xF1,
-0xD2 => 0xF2,
-0xD3 => 0xF3,
-0xD4 => 0xF4,
-0xD5 => 0xF5,
-0xD6 => 0xF6,
-0xD8 => 0xF8,
-0xD9 => 0xF9,
-0xDA => 0xFA,
-0xDB => 0xFB,
-0xDC => 0xFC,
-0xDD => 0xFD,
-0xDE => 0xFE,
-0x100 => 0x101,
-0x102 => 0x103,
-0x104 => 0x105,
-0x106 => 0x107,
-0x108 => 0x109,
-0x10A => 0x10B,
-0x10C => 0x10D,
-0x10E => 0x10F,
-0x110 => 0x111,
-0x112 => 0x113,
-0x114 => 0x115,
-0x116 => 0x117,
-0x118 => 0x119,
-0x11A => 0x11B,
-0x11C => 0x11D,
-0x11E => 0x11F,
-0x120 => 0x121,
-0x122 => 0x123,
-0x124 => 0x125,
-0x126 => 0x127,
-0x128 => 0x129,
-0x12A => 0x12B,
-0x12C => 0x12D,
-0x12E => 0x12F,
-0x132 => 0x133,
-0x134 => 0x135,
-0x136 => 0x137,
-0x139 => 0x13A,
-0x13B => 0x13C,
-0x13D => 0x13E,
-0x13F => 0x140,
-0x141 => 0x142,
-0x143 => 0x144,
-0x145 => 0x146,
-0x147 => 0x148,
-0x14A => 0x14B,
-0x14C => 0x14D,
-0x14E => 0x14F,
-0x150 => 0x151,
-0x152 => 0x153,
-0x154 => 0x155,
-0x156 => 0x157,
-0x158 => 0x159,
-0x15A => 0x15B,
-0x15C => 0x15D,
-0x15E => 0x15F,
-0x160 => 0x161,
-0x162 => 0x163,
-0x164 => 0x165,
-0x166 => 0x167,
-0x168 => 0x169,
-0x16A => 0x16B,
-0x16C => 0x16D,
-0x16E => 0x16F,
-0x170 => 0x171,
-0x172 => 0x173,
-0x174 => 0x175,
-0x176 => 0x177,
-0x178 => 0xFF,
-0x179 => 0x17A,
-0x17B => 0x17C,
-0x17D => 0x17E,
-0x17F => 0x73,
-0x181 => 0x253,
-0x182 => 0x183,
-0x184 => 0x185,
-0x186 => 0x254,
-0x187 => 0x188,
-0x189 => 0x256,
-0x18A => 0x257,
-0x18B => 0x18C,
-0x18E => 0x1DD,
-0x18F => 0x259,
-0x190 => 0x25B,
-0x191 => 0x192,
-0x193 => 0x260,
-0x194 => 0x263,
-0x196 => 0x269,
-0x197 => 0x268,
-0x198 => 0x199,
-0x19C => 0x26F,
-0x19D => 0x272,
-0x19F => 0x275,
-0x1A0 => 0x1A1,
-0x1A2 => 0x1A3,
-0x1A4 => 0x1A5,
-0x1A6 => 0x280,
-0x1A7 => 0x1A8,
-0x1A9 => 0x283,
-0x1AC => 0x1AD,
-0x1AE => 0x288,
-0x1AF => 0x1B0,
-0x1B1 => 0x28A,
-0x1B2 => 0x28B,
-0x1B3 => 0x1B4,
-0x1B5 => 0x1B6,
-0x1B7 => 0x292,
-0x1B8 => 0x1B9,
-0x1BC => 0x1BD,
-0x1C4 => 0x1C6,
-0x1C5 => 0x1C6,
-0x1C7 => 0x1C9,
-0x1C8 => 0x1C9,
-0x1CA => 0x1CC,
-0x1CB => 0x1CC,
-0x1CD => 0x1CE,
-0x1CF => 0x1D0,
-0x1D1 => 0x1D2,
-0x1D3 => 0x1D4,
-0x1D5 => 0x1D6,
-0x1D7 => 0x1D8,
-0x1D9 => 0x1DA,
-0x1DB => 0x1DC,
-0x1DE => 0x1DF,
-0x1E0 => 0x1E1,
-0x1E2 => 0x1E3,
-0x1E4 => 0x1E5,
-0x1E6 => 0x1E7,
-0x1E8 => 0x1E9,
-0x1EA => 0x1EB,
-0x1EC => 0x1ED,
-0x1EE => 0x1EF,
-0x1F1 => 0x1F3,
-0x1F2 => 0x1F3,
-0x1F4 => 0x1F5,
-0x1F6 => 0x195,
-0x1F7 => 0x1BF,
-0x1F8 => 0x1F9,
-0x1FA => 0x1FB,
-0x1FC => 0x1FD,
-0x1FE => 0x1FF,
-0x200 => 0x201,
-0x202 => 0x203,
-0x204 => 0x205,
-0x206 => 0x207,
-0x208 => 0x209,
-0x20A => 0x20B,
-0x20C => 0x20D,
-0x20E => 0x20F,
-0x210 => 0x211,
-0x212 => 0x213,
-0x214 => 0x215,
-0x216 => 0x217,
-0x218 => 0x219,
-0x21A => 0x21B,
-0x21C => 0x21D,
-0x21E => 0x21F,
-0x220 => 0x19E,
-0x222 => 0x223,
-0x224 => 0x225,
-0x226 => 0x227,
-0x228 => 0x229,
-0x22A => 0x22B,
-0x22C => 0x22D,
-0x22E => 0x22F,
-0x230 => 0x231,
-0x232 => 0x233,
-0x23A => 0x2C65,
-0x23B => 0x23C,
-0x23D => 0x19A,
-0x23E => 0x2C66,
-0x241 => 0x242,
-0x243 => 0x180,
-0x244 => 0x289,
-0x245 => 0x28C,
-0x246 => 0x247,
-0x248 => 0x249,
-0x24A => 0x24B,
-0x24C => 0x24D,
-0x24E => 0x24F,
-0x345 => 0x3B9,
-0x370 => 0x371,
-0x372 => 0x373,
-0x376 => 0x377,
-0x37F => 0x3F3,
-0x386 => 0x3AC,
-0x388 => 0x3AD,
-0x389 => 0x3AE,
-0x38A => 0x3AF,
-0x38C => 0x3CC,
-0x38E => 0x3CD,
-0x38F => 0x3CE,
-0x391 => 0x3B1,
-0x392 => 0x3B2,
-0x393 => 0x3B3,
-0x394 => 0x3B4,
-0x395 => 0x3B5,
-0x396 => 0x3B6,
-0x397 => 0x3B7,
-0x398 => 0x3B8,
-0x399 => 0x3B9,
-0x39A => 0x3BA,
-0x39B => 0x3BB,
-0x39C => 0x3BC,
-0x39D => 0x3BD,
-0x39E => 0x3BE,
-0x39F => 0x3BF,
-0x3A0 => 0x3C0,
-0x3A1 => 0x3C1,
-0x3A3 => 0x3C3,
-0x3A4 => 0x3C4,
-0x3A5 => 0x3C5,
-0x3A6 => 0x3C6,
-0x3A7 => 0x3C7,
-0x3A8 => 0x3C8,
-0x3A9 => 0x3C9,
-0x3AA => 0x3CA,
-0x3AB => 0x3CB,
-0x3C2 => 0x3C3,
-0x3CF => 0x3D7,
-0x3D0 => 0x3B2,
-0x3D1 => 0x3B8,
-0x3D5 => 0x3C6,
-0x3D6 => 0x3C0,
-0x3D8 => 0x3D9,
-0x3DA => 0x3DB,
-0x3DC => 0x3DD,
-0x3DE => 0x3DF,
-0x3E0 => 0x3E1,
-0x3E2 => 0x3E3,
-0x3E4 => 0x3E5,
-0x3E6 => 0x3E7,
-0x3E8 => 0x3E9,
-0x3EA => 0x3EB,
-0x3EC => 0x3ED,
-0x3EE => 0x3EF,
-0x3F0 => 0x3BA,
-0x3F1 => 0x3C1,
-0x3F4 => 0x3B8,
-0x3F5 => 0x3B5,
-0x3F7 => 0x3F8,
-0x3F9 => 0x3F2,
-0x3FA => 0x3FB,
-0x3FD => 0x37B,
-0x3FE => 0x37C,
-0x3FF => 0x37D,
-0x400 => 0x450,
-0x401 => 0x451,
-0x402 => 0x452,
-0x403 => 0x453,
-0x404 => 0x454,
-0x405 => 0x455,
-0x406 => 0x456,
-0x407 => 0x457,
-0x408 => 0x458,
-0x409 => 0x459,
-0x40A => 0x45A,
-0x40B => 0x45B,
-0x40C => 0x45C,
-0x40D => 0x45D,
-0x40E => 0x45E,
-0x40F => 0x45F,
-0x410 => 0x430,
-0x411 => 0x431,
-0x412 => 0x432,
-0x413 => 0x433,
-0x414 => 0x434,
-0x415 => 0x435,
-0x416 => 0x436,
-0x417 => 0x437,
-0x418 => 0x438,
-0x419 => 0x439,
-0x41A => 0x43A,
-0x41B => 0x43B,
-0x41C => 0x43C,
-0x41D => 0x43D,
-0x41E => 0x43E,
-0x41F => 0x43F,
-0x420 => 0x440,
-0x421 => 0x441,
-0x422 => 0x442,
-0x423 => 0x443,
-0x424 => 0x444,
-0x425 => 0x445,
-0x426 => 0x446,
-0x427 => 0x447,
-0x428 => 0x448,
-0x429 => 0x449,
-0x42A => 0x44A,
-0x42B => 0x44B,
-0x42C => 0x44C,
-0x42D => 0x44D,
-0x42E => 0x44E,
-0x42F => 0x44F,
-0x460 => 0x461,
-0x462 => 0x463,
-0x464 => 0x465,
-0x466 => 0x467,
-0x468 => 0x469,
-0x46A => 0x46B,
-0x46C => 0x46D,
-0x46E => 0x46F,
-0x470 => 0x471,
-0x472 => 0x473,
-0x474 => 0x475,
-0x476 => 0x477,
-0x478 => 0x479,
-0x47A => 0x47B,
-0x47C => 0x47D,
-0x47E => 0x47F,
-0x480 => 0x481,
-0x48A => 0x48B,
-0x48C => 0x48D,
-0x48E => 0x48F,
-0x490 => 0x491,
-0x492 => 0x493,
-0x494 => 0x495,
-0x496 => 0x497,
-0x498 => 0x499,
-0x49A => 0x49B,
-0x49C => 0x49D,
-0x49E => 0x49F,
-0x4A0 => 0x4A1,
-0x4A2 => 0x4A3,
-0x4A4 => 0x4A5,
-0x4A6 => 0x4A7,
-0x4A8 => 0x4A9,
-0x4AA => 0x4AB,
-0x4AC => 0x4AD,
-0x4AE => 0x4AF,
-0x4B0 => 0x4B1,
-0x4B2 => 0x4B3,
-0x4B4 => 0x4B5,
-0x4B6 => 0x4B7,
-0x4B8 => 0x4B9,
-0x4BA => 0x4BB,
-0x4BC => 0x4BD,
-0x4BE => 0x4BF,
-0x4C0 => 0x4CF,
-0x4C1 => 0x4C2,
-0x4C3 => 0x4C4,
-0x4C5 => 0x4C6,
-0x4C7 => 0x4C8,
-0x4C9 => 0x4CA,
-0x4CB => 0x4CC,
-0x4CD => 0x4CE,
-0x4D0 => 0x4D1,
-0x4D2 => 0x4D3,
-0x4D4 => 0x4D5,
-0x4D6 => 0x4D7,
-0x4D8 => 0x4D9,
-0x4DA => 0x4DB,
-0x4DC => 0x4DD,
-0x4DE => 0x4DF,
-0x4E0 => 0x4E1,
-0x4E2 => 0x4E3,
-0x4E4 => 0x4E5,
-0x4E6 => 0x4E7,
-0x4E8 => 0x4E9,
-0x4EA => 0x4EB,
-0x4EC => 0x4ED,
-0x4EE => 0x4EF,
-0x4F0 => 0x4F1,
-0x4F2 => 0x4F3,
-0x4F4 => 0x4F5,
-0x4F6 => 0x4F7,
-0x4F8 => 0x4F9,
-0x4FA => 0x4FB,
-0x4FC => 0x4FD,
-0x4FE => 0x4FF,
-0x500 => 0x501,
-0x502 => 0x503,
-0x504 => 0x505,
-0x506 => 0x507,
-0x508 => 0x509,
-0x50A => 0x50B,
-0x50C => 0x50D,
-0x50E => 0x50F,
-0x510 => 0x511,
-0x512 => 0x513,
-0x514 => 0x515,
-0x516 => 0x517,
-0x518 => 0x519,
-0x51A => 0x51B,
-0x51C => 0x51D,
-0x51E => 0x51F,
-0x520 => 0x521,
-0x522 => 0x523,
-0x524 => 0x525,
-0x526 => 0x527,
-0x528 => 0x529,
-0x52A => 0x52B,
-0x52C => 0x52D,
-0x52E => 0x52F,
-0x531 => 0x561,
-0x532 => 0x562,
-0x533 => 0x563,
-0x534 => 0x564,
-0x535 => 0x565,
-0x536 => 0x566,
-0x537 => 0x567,
-0x538 => 0x568,
-0x539 => 0x569,
-0x53A => 0x56A,
-0x53B => 0x56B,
-0x53C => 0x56C,
-0x53D => 0x56D,
-0x53E => 0x56E,
-0x53F => 0x56F,
-0x540 => 0x570,
-0x541 => 0x571,
-0x542 => 0x572,
-0x543 => 0x573,
-0x544 => 0x574,
-0x545 => 0x575,
-0x546 => 0x576,
-0x547 => 0x577,
-0x548 => 0x578,
-0x549 => 0x579,
-0x54A => 0x57A,
-0x54B => 0x57B,
-0x54C => 0x57C,
-0x54D => 0x57D,
-0x54E => 0x57E,
-0x54F => 0x57F,
-0x550 => 0x580,
-0x551 => 0x581,
-0x552 => 0x582,
-0x553 => 0x583,
-0x554 => 0x584,
-0x555 => 0x585,
-0x556 => 0x586,
-0x10A0 => 0x2D00,
-0x10A1 => 0x2D01,
-0x10A2 => 0x2D02,
-0x10A3 => 0x2D03,
-0x10A4 => 0x2D04,
-0x10A5 => 0x2D05,
-0x10A6 => 0x2D06,
-0x10A7 => 0x2D07,
-0x10A8 => 0x2D08,
-0x10A9 => 0x2D09,
-0x10AA => 0x2D0A,
-0x10AB => 0x2D0B,
-0x10AC => 0x2D0C,
-0x10AD => 0x2D0D,
-0x10AE => 0x2D0E,
-0x10AF => 0x2D0F,
-0x10B0 => 0x2D10,
-0x10B1 => 0x2D11,
-0x10B2 => 0x2D12,
-0x10B3 => 0x2D13,
-0x10B4 => 0x2D14,
-0x10B5 => 0x2D15,
-0x10B6 => 0x2D16,
-0x10B7 => 0x2D17,
-0x10B8 => 0x2D18,
-0x10B9 => 0x2D19,
-0x10BA => 0x2D1A,
-0x10BB => 0x2D1B,
-0x10BC => 0x2D1C,
-0x10BD => 0x2D1D,
-0x10BE => 0x2D1E,
-0x10BF => 0x2D1F,
-0x10C0 => 0x2D20,
-0x10C1 => 0x2D21,
-0x10C2 => 0x2D22,
-0x10C3 => 0x2D23,
-0x10C4 => 0x2D24,
-0x10C5 => 0x2D25,
-0x10C7 => 0x2D27,
-0x10CD => 0x2D2D,
-0x13F8 => 0x13F0,
-0x13F9 => 0x13F1,
-0x13FA => 0x13F2,
-0x13FB => 0x13F3,
-0x13FC => 0x13F4,
-0x13FD => 0x13F5,
-0x1C80 => 0x432,
-0x1C81 => 0x434,
-0x1C82 => 0x43E,
-0x1C83 => 0x441,
-0x1C84 => 0x442,
-0x1C85 => 0x442,
-0x1C86 => 0x44A,
-0x1C87 => 0x463,
-0x1C88 => 0xA64B,
-0x1C90 => 0x10D0,
-0x1C91 => 0x10D1,
-0x1C92 => 0x10D2,
-0x1C93 => 0x10D3,
-0x1C94 => 0x10D4,
-0x1C95 => 0x10D5,
-0x1C96 => 0x10D6,
-0x1C97 => 0x10D7,
-0x1C98 => 0x10D8,
-0x1C99 => 0x10D9,
-0x1C9A => 0x10DA,
-0x1C9B => 0x10DB,
-0x1C9C => 0x10DC,
-0x1C9D => 0x10DD,
-0x1C9E => 0x10DE,
-0x1C9F => 0x10DF,
-0x1CA0 => 0x10E0,
-0x1CA1 => 0x10E1,
-0x1CA2 => 0x10E2,
-0x1CA3 => 0x10E3,
-0x1CA4 => 0x10E4,
-0x1CA5 => 0x10E5,
-0x1CA6 => 0x10E6,
-0x1CA7 => 0x10E7,
-0x1CA8 => 0x10E8,
-0x1CA9 => 0x10E9,
-0x1CAA => 0x10EA,
-0x1CAB => 0x10EB,
-0x1CAC => 0x10EC,
-0x1CAD => 0x10ED,
-0x1CAE => 0x10EE,
-0x1CAF => 0x10EF,
-0x1CB0 => 0x10F0,
-0x1CB1 => 0x10F1,
-0x1CB2 => 0x10F2,
-0x1CB3 => 0x10F3,
-0x1CB4 => 0x10F4,
-0x1CB5 => 0x10F5,
-0x1CB6 => 0x10F6,
-0x1CB7 => 0x10F7,
-0x1CB8 => 0x10F8,
-0x1CB9 => 0x10F9,
-0x1CBA => 0x10FA,
-0x1CBD => 0x10FD,
-0x1CBE => 0x10FE,
-0x1CBF => 0x10FF,
-0x1E00 => 0x1E01,
-0x1E02 => 0x1E03,
-0x1E04 => 0x1E05,
-0x1E06 => 0x1E07,
-0x1E08 => 0x1E09,
-0x1E0A => 0x1E0B,
-0x1E0C => 0x1E0D,
-0x1E0E => 0x1E0F,
-0x1E10 => 0x1E11,
-0x1E12 => 0x1E13,
-0x1E14 => 0x1E15,
-0x1E16 => 0x1E17,
-0x1E18 => 0x1E19,
-0x1E1A => 0x1E1B,
-0x1E1C => 0x1E1D,
-0x1E1E => 0x1E1F,
-0x1E20 => 0x1E21,
-0x1E22 => 0x1E23,
-0x1E24 => 0x1E25,
-0x1E26 => 0x1E27,
-0x1E28 => 0x1E29,
-0x1E2A => 0x1E2B,
-0x1E2C => 0x1E2D,
-0x1E2E => 0x1E2F,
-0x1E30 => 0x1E31,
-0x1E32 => 0x1E33,
-0x1E34 => 0x1E35,
-0x1E36 => 0x1E37,
-0x1E38 => 0x1E39,
-0x1E3A => 0x1E3B,
-0x1E3C => 0x1E3D,
-0x1E3E => 0x1E3F,
-0x1E40 => 0x1E41,
-0x1E42 => 0x1E43,
-0x1E44 => 0x1E45,
-0x1E46 => 0x1E47,
-0x1E48 => 0x1E49,
-0x1E4A => 0x1E4B,
-0x1E4C => 0x1E4D,
-0x1E4E => 0x1E4F,
-0x1E50 => 0x1E51,
-0x1E52 => 0x1E53,
-0x1E54 => 0x1E55,
-0x1E56 => 0x1E57,
-0x1E58 => 0x1E59,
-0x1E5A => 0x1E5B,
-0x1E5C => 0x1E5D,
-0x1E5E => 0x1E5F,
-0x1E60 => 0x1E61,
-0x1E62 => 0x1E63,
-0x1E64 => 0x1E65,
-0x1E66 => 0x1E67,
-0x1E68 => 0x1E69,
-0x1E6A => 0x1E6B,
-0x1E6C => 0x1E6D,
-0x1E6E => 0x1E6F,
-0x1E70 => 0x1E71,
-0x1E72 => 0x1E73,
-0x1E74 => 0x1E75,
-0x1E76 => 0x1E77,
-0x1E78 => 0x1E79,
-0x1E7A => 0x1E7B,
-0x1E7C => 0x1E7D,
-0x1E7E => 0x1E7F,
-0x1E80 => 0x1E81,
-0x1E82 => 0x1E83,
-0x1E84 => 0x1E85,
-0x1E86 => 0x1E87,
-0x1E88 => 0x1E89,
-0x1E8A => 0x1E8B,
-0x1E8C => 0x1E8D,
-0x1E8E => 0x1E8F,
-0x1E90 => 0x1E91,
-0x1E92 => 0x1E93,
-0x1E94 => 0x1E95,
-0x1E9B => 0x1E61,
-0x1E9E => 0xDF,
-0x1EA0 => 0x1EA1,
-0x1EA2 => 0x1EA3,
-0x1EA4 => 0x1EA5,
-0x1EA6 => 0x1EA7,
-0x1EA8 => 0x1EA9,
-0x1EAA => 0x1EAB,
-0x1EAC => 0x1EAD,
-0x1EAE => 0x1EAF,
-0x1EB0 => 0x1EB1,
-0x1EB2 => 0x1EB3,
-0x1EB4 => 0x1EB5,
-0x1EB6 => 0x1EB7,
-0x1EB8 => 0x1EB9,
-0x1EBA => 0x1EBB,
-0x1EBC => 0x1EBD,
-0x1EBE => 0x1EBF,
-0x1EC0 => 0x1EC1,
-0x1EC2 => 0x1EC3,
-0x1EC4 => 0x1EC5,
-0x1EC6 => 0x1EC7,
-0x1EC8 => 0x1EC9,
-0x1ECA => 0x1ECB,
-0x1ECC => 0x1ECD,
-0x1ECE => 0x1ECF,
-0x1ED0 => 0x1ED1,
-0x1ED2 => 0x1ED3,
-0x1ED4 => 0x1ED5,
-0x1ED6 => 0x1ED7,
-0x1ED8 => 0x1ED9,
-0x1EDA => 0x1EDB,
-0x1EDC => 0x1EDD,
-0x1EDE => 0x1EDF,
-0x1EE0 => 0x1EE1,
-0x1EE2 => 0x1EE3,
-0x1EE4 => 0x1EE5,
-0x1EE6 => 0x1EE7,
-0x1EE8 => 0x1EE9,
-0x1EEA => 0x1EEB,
-0x1EEC => 0x1EED,
-0x1EEE => 0x1EEF,
-0x1EF0 => 0x1EF1,
-0x1EF2 => 0x1EF3,
-0x1EF4 => 0x1EF5,
-0x1EF6 => 0x1EF7,
-0x1EF8 => 0x1EF9,
-0x1EFA => 0x1EFB,
-0x1EFC => 0x1EFD,
-0x1EFE => 0x1EFF,
-0x1F08 => 0x1F00,
-0x1F09 => 0x1F01,
-0x1F0A => 0x1F02,
-0x1F0B => 0x1F03,
-0x1F0C => 0x1F04,
-0x1F0D => 0x1F05,
-0x1F0E => 0x1F06,
-0x1F0F => 0x1F07,
-0x1F18 => 0x1F10,
-0x1F19 => 0x1F11,
-0x1F1A => 0x1F12,
-0x1F1B => 0x1F13,
-0x1F1C => 0x1F14,
-0x1F1D => 0x1F15,
-0x1F28 => 0x1F20,
-0x1F29 => 0x1F21,
-0x1F2A => 0x1F22,
-0x1F2B => 0x1F23,
-0x1F2C => 0x1F24,
-0x1F2D => 0x1F25,
-0x1F2E => 0x1F26,
-0x1F2F => 0x1F27,
-0x1F38 => 0x1F30,
-0x1F39 => 0x1F31,
-0x1F3A => 0x1F32,
-0x1F3B => 0x1F33,
-0x1F3C => 0x1F34,
-0x1F3D => 0x1F35,
-0x1F3E => 0x1F36,
-0x1F3F => 0x1F37,
-0x1F48 => 0x1F40,
-0x1F49 => 0x1F41,
-0x1F4A => 0x1F42,
-0x1F4B => 0x1F43,
-0x1F4C => 0x1F44,
-0x1F4D => 0x1F45,
-0x1F59 => 0x1F51,
-0x1F5B => 0x1F53,
-0x1F5D => 0x1F55,
-0x1F5F => 0x1F57,
-0x1F68 => 0x1F60,
-0x1F69 => 0x1F61,
-0x1F6A => 0x1F62,
-0x1F6B => 0x1F63,
-0x1F6C => 0x1F64,
-0x1F6D => 0x1F65,
-0x1F6E => 0x1F66,
-0x1F6F => 0x1F67,
-0x1F88 => 0x1F80,
-0x1F89 => 0x1F81,
-0x1F8A => 0x1F82,
-0x1F8B => 0x1F83,
-0x1F8C => 0x1F84,
-0x1F8D => 0x1F85,
-0x1F8E => 0x1F86,
-0x1F8F => 0x1F87,
-0x1F98 => 0x1F90,
-0x1F99 => 0x1F91,
-0x1F9A => 0x1F92,
-0x1F9B => 0x1F93,
-0x1F9C => 0x1F94,
-0x1F9D => 0x1F95,
-0x1F9E => 0x1F96,
-0x1F9F => 0x1F97,
-0x1FA8 => 0x1FA0,
-0x1FA9 => 0x1FA1,
-0x1FAA => 0x1FA2,
-0x1FAB => 0x1FA3,
-0x1FAC => 0x1FA4,
-0x1FAD => 0x1FA5,
-0x1FAE => 0x1FA6,
-0x1FAF => 0x1FA7,
-0x1FB8 => 0x1FB0,
-0x1FB9 => 0x1FB1,
-0x1FBA => 0x1F70,
-0x1FBB => 0x1F71,
-0x1FBC => 0x1FB3,
-0x1FBE => 0x3B9,
-0x1FC8 => 0x1F72,
-0x1FC9 => 0x1F73,
-0x1FCA => 0x1F74,
-0x1FCB => 0x1F75,
-0x1FCC => 0x1FC3,
-0x1FD8 => 0x1FD0,
-0x1FD9 => 0x1FD1,
-0x1FDA => 0x1F76,
-0x1FDB => 0x1F77,
-0x1FE8 => 0x1FE0,
-0x1FE9 => 0x1FE1,
-0x1FEA => 0x1F7A,
-0x1FEB => 0x1F7B,
-0x1FEC => 0x1FE5,
-0x1FF8 => 0x1F78,
-0x1FF9 => 0x1F79,
-0x1FFA => 0x1F7C,
-0x1FFB => 0x1F7D,
-0x1FFC => 0x1FF3,
-0x2126 => 0x3C9,
-0x212A => 0x6B,
-0x212B => 0xE5,
-0x2132 => 0x214E,
-0x2160 => 0x2170,
-0x2161 => 0x2171,
-0x2162 => 0x2172,
-0x2163 => 0x2173,
-0x2164 => 0x2174,
-0x2165 => 0x2175,
-0x2166 => 0x2176,
-0x2167 => 0x2177,
-0x2168 => 0x2178,
-0x2169 => 0x2179,
-0x216A => 0x217A,
-0x216B => 0x217B,
-0x216C => 0x217C,
-0x216D => 0x217D,
-0x216E => 0x217E,
-0x216F => 0x217F,
-0x2183 => 0x2184,
-0x24B6 => 0x24D0,
-0x24B7 => 0x24D1,
-0x24B8 => 0x24D2,
-0x24B9 => 0x24D3,
-0x24BA => 0x24D4,
-0x24BB => 0x24D5,
-0x24BC => 0x24D6,
-0x24BD => 0x24D7,
-0x24BE => 0x24D8,
-0x24BF => 0x24D9,
-0x24C0 => 0x24DA,
-0x24C1 => 0x24DB,
-0x24C2 => 0x24DC,
-0x24C3 => 0x24DD,
-0x24C4 => 0x24DE,
-0x24C5 => 0x24DF,
-0x24C6 => 0x24E0,
-0x24C7 => 0x24E1,
-0x24C8 => 0x24E2,
-0x24C9 => 0x24E3,
-0x24CA => 0x24E4,
-0x24CB => 0x24E5,
-0x24CC => 0x24E6,
-0x24CD => 0x24E7,
-0x24CE => 0x24E8,
-0x24CF => 0x24E9,
-0x2C00 => 0x2C30,
-0x2C01 => 0x2C31,
-0x2C02 => 0x2C32,
-0x2C03 => 0x2C33,
-0x2C04 => 0x2C34,
-0x2C05 => 0x2C35,
-0x2C06 => 0x2C36,
-0x2C07 => 0x2C37,
-0x2C08 => 0x2C38,
-0x2C09 => 0x2C39,
-0x2C0A => 0x2C3A,
-0x2C0B => 0x2C3B,
-0x2C0C => 0x2C3C,
-0x2C0D => 0x2C3D,
-0x2C0E => 0x2C3E,
-0x2C0F => 0x2C3F,
-0x2C10 => 0x2C40,
-0x2C11 => 0x2C41,
-0x2C12 => 0x2C42,
-0x2C13 => 0x2C43,
-0x2C14 => 0x2C44,
-0x2C15 => 0x2C45,
-0x2C16 => 0x2C46,
-0x2C17 => 0x2C47,
-0x2C18 => 0x2C48,
-0x2C19 => 0x2C49,
-0x2C1A => 0x2C4A,
-0x2C1B => 0x2C4B,
-0x2C1C => 0x2C4C,
-0x2C1D => 0x2C4D,
-0x2C1E => 0x2C4E,
-0x2C1F => 0x2C4F,
-0x2C20 => 0x2C50,
-0x2C21 => 0x2C51,
-0x2C22 => 0x2C52,
-0x2C23 => 0x2C53,
-0x2C24 => 0x2C54,
-0x2C25 => 0x2C55,
-0x2C26 => 0x2C56,
-0x2C27 => 0x2C57,
-0x2C28 => 0x2C58,
-0x2C29 => 0x2C59,
-0x2C2A => 0x2C5A,
-0x2C2B => 0x2C5B,
-0x2C2C => 0x2C5C,
-0x2C2D => 0x2C5D,
-0x2C2E => 0x2C5E,
-0x2C60 => 0x2C61,
-0x2C62 => 0x26B,
-0x2C63 => 0x1D7D,
-0x2C64 => 0x27D,
-0x2C67 => 0x2C68,
-0x2C69 => 0x2C6A,
-0x2C6B => 0x2C6C,
-0x2C6D => 0x251,
-0x2C6E => 0x271,
-0x2C6F => 0x250,
-0x2C70 => 0x252,
-0x2C72 => 0x2C73,
-0x2C75 => 0x2C76,
-0x2C7E => 0x23F,
-0x2C7F => 0x240,
-0x2C80 => 0x2C81,
-0x2C82 => 0x2C83,
-0x2C84 => 0x2C85,
-0x2C86 => 0x2C87,
-0x2C88 => 0x2C89,
-0x2C8A => 0x2C8B,
-0x2C8C => 0x2C8D,
-0x2C8E => 0x2C8F,
-0x2C90 => 0x2C91,
-0x2C92 => 0x2C93,
-0x2C94 => 0x2C95,
-0x2C96 => 0x2C97,
-0x2C98 => 0x2C99,
-0x2C9A => 0x2C9B,
-0x2C9C => 0x2C9D,
-0x2C9E => 0x2C9F,
-0x2CA0 => 0x2CA1,
-0x2CA2 => 0x2CA3,
-0x2CA4 => 0x2CA5,
-0x2CA6 => 0x2CA7,
-0x2CA8 => 0x2CA9,
-0x2CAA => 0x2CAB,
-0x2CAC => 0x2CAD,
-0x2CAE => 0x2CAF,
-0x2CB0 => 0x2CB1,
-0x2CB2 => 0x2CB3,
-0x2CB4 => 0x2CB5,
-0x2CB6 => 0x2CB7,
-0x2CB8 => 0x2CB9,
-0x2CBA => 0x2CBB,
-0x2CBC => 0x2CBD,
-0x2CBE => 0x2CBF,
-0x2CC0 => 0x2CC1,
-0x2CC2 => 0x2CC3,
-0x2CC4 => 0x2CC5,
-0x2CC6 => 0x2CC7,
-0x2CC8 => 0x2CC9,
-0x2CCA => 0x2CCB,
-0x2CCC => 0x2CCD,
-0x2CCE => 0x2CCF,
-0x2CD0 => 0x2CD1,
-0x2CD2 => 0x2CD3,
-0x2CD4 => 0x2CD5,
-0x2CD6 => 0x2CD7,
-0x2CD8 => 0x2CD9,
-0x2CDA => 0x2CDB,
-0x2CDC => 0x2CDD,
-0x2CDE => 0x2CDF,
-0x2CE0 => 0x2CE1,
-0x2CE2 => 0x2CE3,
-0x2CEB => 0x2CEC,
-0x2CED => 0x2CEE,
-0x2CF2 => 0x2CF3,
-0xA640 => 0xA641,
-0xA642 => 0xA643,
-0xA644 => 0xA645,
-0xA646 => 0xA647,
-0xA648 => 0xA649,
-0xA64A => 0xA64B,
-0xA64C => 0xA64D,
-0xA64E => 0xA64F,
-0xA650 => 0xA651,
-0xA652 => 0xA653,
-0xA654 => 0xA655,
-0xA656 => 0xA657,
-0xA658 => 0xA659,
-0xA65A => 0xA65B,
-0xA65C => 0xA65D,
-0xA65E => 0xA65F,
-0xA660 => 0xA661,
-0xA662 => 0xA663,
-0xA664 => 0xA665,
-0xA666 => 0xA667,
-0xA668 => 0xA669,
-0xA66A => 0xA66B,
-0xA66C => 0xA66D,
-0xA680 => 0xA681,
-0xA682 => 0xA683,
-0xA684 => 0xA685,
-0xA686 => 0xA687,
-0xA688 => 0xA689,
-0xA68A => 0xA68B,
-0xA68C => 0xA68D,
-0xA68E => 0xA68F,
-0xA690 => 0xA691,
-0xA692 => 0xA693,
-0xA694 => 0xA695,
-0xA696 => 0xA697,
-0xA698 => 0xA699,
-0xA69A => 0xA69B,
-0xA722 => 0xA723,
-0xA724 => 0xA725,
-0xA726 => 0xA727,
-0xA728 => 0xA729,
-0xA72A => 0xA72B,
-0xA72C => 0xA72D,
-0xA72E => 0xA72F,
-0xA732 => 0xA733,
-0xA734 => 0xA735,
-0xA736 => 0xA737,
-0xA738 => 0xA739,
-0xA73A => 0xA73B,
-0xA73C => 0xA73D,
-0xA73E => 0xA73F,
-0xA740 => 0xA741,
-0xA742 => 0xA743,
-0xA744 => 0xA745,
-0xA746 => 0xA747,
-0xA748 => 0xA749,
-0xA74A => 0xA74B,
-0xA74C => 0xA74D,
-0xA74E => 0xA74F,
-0xA750 => 0xA751,
-0xA752 => 0xA753,
-0xA754 => 0xA755,
-0xA756 => 0xA757,
-0xA758 => 0xA759,
-0xA75A => 0xA75B,
-0xA75C => 0xA75D,
-0xA75E => 0xA75F,
-0xA760 => 0xA761,
-0xA762 => 0xA763,
-0xA764 => 0xA765,
-0xA766 => 0xA767,
-0xA768 => 0xA769,
-0xA76A => 0xA76B,
-0xA76C => 0xA76D,
-0xA76E => 0xA76F,
-0xA779 => 0xA77A,
-0xA77B => 0xA77C,
-0xA77D => 0x1D79,
-0xA77E => 0xA77F,
-0xA780 => 0xA781,
-0xA782 => 0xA783,
-0xA784 => 0xA785,
-0xA786 => 0xA787,
-0xA78B => 0xA78C,
-0xA78D => 0x265,
-0xA790 => 0xA791,
-0xA792 => 0xA793,
-0xA796 => 0xA797,
-0xA798 => 0xA799,
-0xA79A => 0xA79B,
-0xA79C => 0xA79D,
-0xA79E => 0xA79F,
-0xA7A0 => 0xA7A1,
-0xA7A2 => 0xA7A3,
-0xA7A4 => 0xA7A5,
-0xA7A6 => 0xA7A7,
-0xA7A8 => 0xA7A9,
-0xA7AA => 0x266,
-0xA7AB => 0x25C,
-0xA7AC => 0x261,
-0xA7AD => 0x26C,
-0xA7AE => 0x26A,
-0xA7B0 => 0x29E,
-0xA7B1 => 0x287,
-0xA7B2 => 0x29D,
-0xA7B3 => 0xAB53,
-0xA7B4 => 0xA7B5,
-0xA7B6 => 0xA7B7,
-0xA7B8 => 0xA7B9,
-0xA7BA => 0xA7BB,
-0xA7BC => 0xA7BD,
-0xA7BE => 0xA7BF,
-0xA7C2 => 0xA7C3,
-0xA7C4 => 0xA794,
-0xA7C5 => 0x282,
-0xA7C6 => 0x1D8E,
-0xA7C7 => 0xA7C8,
-0xA7C9 => 0xA7CA,
-0xA7F5 => 0xA7F6,
-0xAB70 => 0x13A0,
-0xAB71 => 0x13A1,
-0xAB72 => 0x13A2,
-0xAB73 => 0x13A3,
-0xAB74 => 0x13A4,
-0xAB75 => 0x13A5,
-0xAB76 => 0x13A6,
-0xAB77 => 0x13A7,
-0xAB78 => 0x13A8,
-0xAB79 => 0x13A9,
-0xAB7A => 0x13AA,
-0xAB7B => 0x13AB,
-0xAB7C => 0x13AC,
-0xAB7D => 0x13AD,
-0xAB7E => 0x13AE,
-0xAB7F => 0x13AF,
-0xAB80 => 0x13B0,
-0xAB81 => 0x13B1,
-0xAB82 => 0x13B2,
-0xAB83 => 0x13B3,
-0xAB84 => 0x13B4,
-0xAB85 => 0x13B5,
-0xAB86 => 0x13B6,
-0xAB87 => 0x13B7,
-0xAB88 => 0x13B8,
-0xAB89 => 0x13B9,
-0xAB8A => 0x13BA,
-0xAB8B => 0x13BB,
-0xAB8C => 0x13BC,
-0xAB8D => 0x13BD,
-0xAB8E => 0x13BE,
-0xAB8F => 0x13BF,
-0xAB90 => 0x13C0,
-0xAB91 => 0x13C1,
-0xAB92 => 0x13C2,
-0xAB93 => 0x13C3,
-0xAB94 => 0x13C4,
-0xAB95 => 0x13C5,
-0xAB96 => 0x13C6,
-0xAB97 => 0x13C7,
-0xAB98 => 0x13C8,
-0xAB99 => 0x13C9,
-0xAB9A => 0x13CA,
-0xAB9B => 0x13CB,
-0xAB9C => 0x13CC,
-0xAB9D => 0x13CD,
-0xAB9E => 0x13CE,
-0xAB9F => 0x13CF,
-0xABA0 => 0x13D0,
-0xABA1 => 0x13D1,
-0xABA2 => 0x13D2,
-0xABA3 => 0x13D3,
-0xABA4 => 0x13D4,
-0xABA5 => 0x13D5,
-0xABA6 => 0x13D6,
-0xABA7 => 0x13D7,
-0xABA8 => 0x13D8,
-0xABA9 => 0x13D9,
-0xABAA => 0x13DA,
-0xABAB => 0x13DB,
-0xABAC => 0x13DC,
-0xABAD => 0x13DD,
-0xABAE => 0x13DE,
-0xABAF => 0x13DF,
-0xABB0 => 0x13E0,
-0xABB1 => 0x13E1,
-0xABB2 => 0x13E2,
-0xABB3 => 0x13E3,
-0xABB4 => 0x13E4,
-0xABB5 => 0x13E5,
-0xABB6 => 0x13E6,
-0xABB7 => 0x13E7,
-0xABB8 => 0x13E8,
-0xABB9 => 0x13E9,
-0xABBA => 0x13EA,
-0xABBB => 0x13EB,
-0xABBC => 0x13EC,
-0xABBD => 0x13ED,
-0xABBE => 0x13EE,
-0xABBF => 0x13EF,
-0xFF21 => 0xFF41,
-0xFF22 => 0xFF42,
-0xFF23 => 0xFF43,
-0xFF24 => 0xFF44,
-0xFF25 => 0xFF45,
-0xFF26 => 0xFF46,
-0xFF27 => 0xFF47,
-0xFF28 => 0xFF48,
-0xFF29 => 0xFF49,
-0xFF2A => 0xFF4A,
-0xFF2B => 0xFF4B,
-0xFF2C => 0xFF4C,
-0xFF2D => 0xFF4D,
-0xFF2E => 0xFF4E,
-0xFF2F => 0xFF4F,
-0xFF30 => 0xFF50,
-0xFF31 => 0xFF51,
-0xFF32 => 0xFF52,
-0xFF33 => 0xFF53,
-0xFF34 => 0xFF54,
-0xFF35 => 0xFF55,
-0xFF36 => 0xFF56,
-0xFF37 => 0xFF57,
-0xFF38 => 0xFF58,
-0xFF39 => 0xFF59,
-0xFF3A => 0xFF5A,
-0x10400 => 0x10428,
-0x10401 => 0x10429,
-0x10402 => 0x1042A,
-0x10403 => 0x1042B,
-0x10404 => 0x1042C,
-0x10405 => 0x1042D,
-0x10406 => 0x1042E,
-0x10407 => 0x1042F,
-0x10408 => 0x10430,
-0x10409 => 0x10431,
-0x1040A => 0x10432,
-0x1040B => 0x10433,
-0x1040C => 0x10434,
-0x1040D => 0x10435,
-0x1040E => 0x10436,
-0x1040F => 0x10437,
-0x10410 => 0x10438,
-0x10411 => 0x10439,
-0x10412 => 0x1043A,
-0x10413 => 0x1043B,
-0x10414 => 0x1043C,
-0x10415 => 0x1043D,
-0x10416 => 0x1043E,
-0x10417 => 0x1043F,
-0x10418 => 0x10440,
-0x10419 => 0x10441,
-0x1041A => 0x10442,
-0x1041B => 0x10443,
-0x1041C => 0x10444,
-0x1041D => 0x10445,
-0x1041E => 0x10446,
-0x1041F => 0x10447,
-0x10420 => 0x10448,
-0x10421 => 0x10449,
-0x10422 => 0x1044A,
-0x10423 => 0x1044B,
-0x10424 => 0x1044C,
-0x10425 => 0x1044D,
-0x10426 => 0x1044E,
-0x10427 => 0x1044F,
-0x104B0 => 0x104D8,
-0x104B1 => 0x104D9,
-0x104B2 => 0x104DA,
-0x104B3 => 0x104DB,
-0x104B4 => 0x104DC,
-0x104B5 => 0x104DD,
-0x104B6 => 0x104DE,
-0x104B7 => 0x104DF,
-0x104B8 => 0x104E0,
-0x104B9 => 0x104E1,
-0x104BA => 0x104E2,
-0x104BB => 0x104E3,
-0x104BC => 0x104E4,
-0x104BD => 0x104E5,
-0x104BE => 0x104E6,
-0x104BF => 0x104E7,
-0x104C0 => 0x104E8,
-0x104C1 => 0x104E9,
-0x104C2 => 0x104EA,
-0x104C3 => 0x104EB,
-0x104C4 => 0x104EC,
-0x104C5 => 0x104ED,
-0x104C6 => 0x104EE,
-0x104C7 => 0x104EF,
-0x104C8 => 0x104F0,
-0x104C9 => 0x104F1,
-0x104CA => 0x104F2,
-0x104CB => 0x104F3,
-0x104CC => 0x104F4,
-0x104CD => 0x104F5,
-0x104CE => 0x104F6,
-0x104CF => 0x104F7,
-0x104D0 => 0x104F8,
-0x104D1 => 0x104F9,
-0x104D2 => 0x104FA,
-0x104D3 => 0x104FB,
-0x10C80 => 0x10CC0,
-0x10C81 => 0x10CC1,
-0x10C82 => 0x10CC2,
-0x10C83 => 0x10CC3,
-0x10C84 => 0x10CC4,
-0x10C85 => 0x10CC5,
-0x10C86 => 0x10CC6,
-0x10C87 => 0x10CC7,
-0x10C88 => 0x10CC8,
-0x10C89 => 0x10CC9,
-0x10C8A => 0x10CCA,
-0x10C8B => 0x10CCB,
-0x10C8C => 0x10CCC,
-0x10C8D => 0x10CCD,
-0x10C8E => 0x10CCE,
-0x10C8F => 0x10CCF,
-0x10C90 => 0x10CD0,
-0x10C91 => 0x10CD1,
-0x10C92 => 0x10CD2,
-0x10C93 => 0x10CD3,
-0x10C94 => 0x10CD4,
-0x10C95 => 0x10CD5,
-0x10C96 => 0x10CD6,
-0x10C97 => 0x10CD7,
-0x10C98 => 0x10CD8,
-0x10C99 => 0x10CD9,
-0x10C9A => 0x10CDA,
-0x10C9B => 0x10CDB,
-0x10C9C => 0x10CDC,
-0x10C9D => 0x10CDD,
-0x10C9E => 0x10CDE,
-0x10C9F => 0x10CDF,
-0x10CA0 => 0x10CE0,
-0x10CA1 => 0x10CE1,
-0x10CA2 => 0x10CE2,
-0x10CA3 => 0x10CE3,
-0x10CA4 => 0x10CE4,
-0x10CA5 => 0x10CE5,
-0x10CA6 => 0x10CE6,
-0x10CA7 => 0x10CE7,
-0x10CA8 => 0x10CE8,
-0x10CA9 => 0x10CE9,
-0x10CAA => 0x10CEA,
-0x10CAB => 0x10CEB,
-0x10CAC => 0x10CEC,
-0x10CAD => 0x10CED,
-0x10CAE => 0x10CEE,
-0x10CAF => 0x10CEF,
-0x10CB0 => 0x10CF0,
-0x10CB1 => 0x10CF1,
-0x10CB2 => 0x10CF2,
-0x118A0 => 0x118C0,
-0x118A1 => 0x118C1,
-0x118A2 => 0x118C2,
-0x118A3 => 0x118C3,
-0x118A4 => 0x118C4,
-0x118A5 => 0x118C5,
-0x118A6 => 0x118C6,
-0x118A7 => 0x118C7,
-0x118A8 => 0x118C8,
-0x118A9 => 0x118C9,
-0x118AA => 0x118CA,
-0x118AB => 0x118CB,
-0x118AC => 0x118CC,
-0x118AD => 0x118CD,
-0x118AE => 0x118CE,
-0x118AF => 0x118CF,
-0x118B0 => 0x118D0,
-0x118B1 => 0x118D1,
-0x118B2 => 0x118D2,
-0x118B3 => 0x118D3,
-0x118B4 => 0x118D4,
-0x118B5 => 0x118D5,
-0x118B6 => 0x118D6,
-0x118B7 => 0x118D7,
-0x118B8 => 0x118D8,
-0x118B9 => 0x118D9,
-0x118BA => 0x118DA,
-0x118BB => 0x118DB,
-0x118BC => 0x118DC,
-0x118BD => 0x118DD,
-0x118BE => 0x118DE,
-0x118BF => 0x118DF,
-0x16E40 => 0x16E60,
-0x16E41 => 0x16E61,
-0x16E42 => 0x16E62,
-0x16E43 => 0x16E63,
-0x16E44 => 0x16E64,
-0x16E45 => 0x16E65,
-0x16E46 => 0x16E66,
-0x16E47 => 0x16E67,
-0x16E48 => 0x16E68,
-0x16E49 => 0x16E69,
-0x16E4A => 0x16E6A,
-0x16E4B => 0x16E6B,
-0x16E4C => 0x16E6C,
-0x16E4D => 0x16E6D,
-0x16E4E => 0x16E6E,
-0x16E4F => 0x16E6F,
-0x16E50 => 0x16E70,
-0x16E51 => 0x16E71,
-0x16E52 => 0x16E72,
-0x16E53 => 0x16E73,
-0x16E54 => 0x16E74,
-0x16E55 => 0x16E75,
-0x16E56 => 0x16E76,
-0x16E57 => 0x16E77,
-0x16E58 => 0x16E78,
-0x16E59 => 0x16E79,
-0x16E5A => 0x16E7A,
-0x16E5B => 0x16E7B,
-0x16E5C => 0x16E7C,
-0x16E5D => 0x16E7D,
-0x16E5E => 0x16E7E,
-0x16E5F => 0x16E7F,
-0x1E900 => 0x1E922,
-0x1E901 => 0x1E923,
-0x1E902 => 0x1E924,
-0x1E903 => 0x1E925,
-0x1E904 => 0x1E926,
-0x1E905 => 0x1E927,
-0x1E906 => 0x1E928,
-0x1E907 => 0x1E929,
-0x1E908 => 0x1E92A,
-0x1E909 => 0x1E92B,
-0x1E90A => 0x1E92C,
-0x1E90B => 0x1E92D,
-0x1E90C => 0x1E92E,
-0x1E90D => 0x1E92F,
-0x1E90E => 0x1E930,
-0x1E90F => 0x1E931,
-0x1E910 => 0x1E932,
-0x1E911 => 0x1E933,
-0x1E912 => 0x1E934,
-0x1E913 => 0x1E935,
-0x1E914 => 0x1E936,
-0x1E915 => 0x1E937,
-0x1E916 => 0x1E938,
-0x1E917 => 0x1E939,
-0x1E918 => 0x1E93A,
-0x1E919 => 0x1E93B,
-0x1E91A => 0x1E93C,
-0x1E91B => 0x1E93D,
-0x1E91C => 0x1E93E,
-0x1E91D => 0x1E93F,
-0x1E91E => 0x1E940,
-0x1E91F => 0x1E941,
-0x1E920 => 0x1E942,
-0x1E921 => 0x1E943,
-];
+return array(
+ 0x41 => 0x61,
+ 0x42 => 0x62,
+ 0x43 => 0x63,
+ 0x44 => 0x64,
+ 0x45 => 0x65,
+ 0x46 => 0x66,
+ 0x47 => 0x67,
+ 0x48 => 0x68,
+ 0x49 => 0x69,
+ 0x4A => 0x6A,
+ 0x4B => 0x6B,
+ 0x4C => 0x6C,
+ 0x4D => 0x6D,
+ 0x4E => 0x6E,
+ 0x4F => 0x6F,
+ 0x50 => 0x70,
+ 0x51 => 0x71,
+ 0x52 => 0x72,
+ 0x53 => 0x73,
+ 0x54 => 0x74,
+ 0x55 => 0x75,
+ 0x56 => 0x76,
+ 0x57 => 0x77,
+ 0x58 => 0x78,
+ 0x59 => 0x79,
+ 0x5A => 0x7A,
+ 0xB5 => 0x3BC,
+ 0xC0 => 0xE0,
+ 0xC1 => 0xE1,
+ 0xC2 => 0xE2,
+ 0xC3 => 0xE3,
+ 0xC4 => 0xE4,
+ 0xC5 => 0xE5,
+ 0xC6 => 0xE6,
+ 0xC7 => 0xE7,
+ 0xC8 => 0xE8,
+ 0xC9 => 0xE9,
+ 0xCA => 0xEA,
+ 0xCB => 0xEB,
+ 0xCC => 0xEC,
+ 0xCD => 0xED,
+ 0xCE => 0xEE,
+ 0xCF => 0xEF,
+ 0xD0 => 0xF0,
+ 0xD1 => 0xF1,
+ 0xD2 => 0xF2,
+ 0xD3 => 0xF3,
+ 0xD4 => 0xF4,
+ 0xD5 => 0xF5,
+ 0xD6 => 0xF6,
+ 0xD8 => 0xF8,
+ 0xD9 => 0xF9,
+ 0xDA => 0xFA,
+ 0xDB => 0xFB,
+ 0xDC => 0xFC,
+ 0xDD => 0xFD,
+ 0xDE => 0xFE,
+ 0x100 => 0x101,
+ 0x102 => 0x103,
+ 0x104 => 0x105,
+ 0x106 => 0x107,
+ 0x108 => 0x109,
+ 0x10A => 0x10B,
+ 0x10C => 0x10D,
+ 0x10E => 0x10F,
+ 0x110 => 0x111,
+ 0x112 => 0x113,
+ 0x114 => 0x115,
+ 0x116 => 0x117,
+ 0x118 => 0x119,
+ 0x11A => 0x11B,
+ 0x11C => 0x11D,
+ 0x11E => 0x11F,
+ 0x120 => 0x121,
+ 0x122 => 0x123,
+ 0x124 => 0x125,
+ 0x126 => 0x127,
+ 0x128 => 0x129,
+ 0x12A => 0x12B,
+ 0x12C => 0x12D,
+ 0x12E => 0x12F,
+ 0x132 => 0x133,
+ 0x134 => 0x135,
+ 0x136 => 0x137,
+ 0x139 => 0x13A,
+ 0x13B => 0x13C,
+ 0x13D => 0x13E,
+ 0x13F => 0x140,
+ 0x141 => 0x142,
+ 0x143 => 0x144,
+ 0x145 => 0x146,
+ 0x147 => 0x148,
+ 0x14A => 0x14B,
+ 0x14C => 0x14D,
+ 0x14E => 0x14F,
+ 0x150 => 0x151,
+ 0x152 => 0x153,
+ 0x154 => 0x155,
+ 0x156 => 0x157,
+ 0x158 => 0x159,
+ 0x15A => 0x15B,
+ 0x15C => 0x15D,
+ 0x15E => 0x15F,
+ 0x160 => 0x161,
+ 0x162 => 0x163,
+ 0x164 => 0x165,
+ 0x166 => 0x167,
+ 0x168 => 0x169,
+ 0x16A => 0x16B,
+ 0x16C => 0x16D,
+ 0x16E => 0x16F,
+ 0x170 => 0x171,
+ 0x172 => 0x173,
+ 0x174 => 0x175,
+ 0x176 => 0x177,
+ 0x178 => 0xFF,
+ 0x179 => 0x17A,
+ 0x17B => 0x17C,
+ 0x17D => 0x17E,
+ 0x17F => 0x73,
+ 0x181 => 0x253,
+ 0x182 => 0x183,
+ 0x184 => 0x185,
+ 0x186 => 0x254,
+ 0x187 => 0x188,
+ 0x189 => 0x256,
+ 0x18A => 0x257,
+ 0x18B => 0x18C,
+ 0x18E => 0x1DD,
+ 0x18F => 0x259,
+ 0x190 => 0x25B,
+ 0x191 => 0x192,
+ 0x193 => 0x260,
+ 0x194 => 0x263,
+ 0x196 => 0x269,
+ 0x197 => 0x268,
+ 0x198 => 0x199,
+ 0x19C => 0x26F,
+ 0x19D => 0x272,
+ 0x19F => 0x275,
+ 0x1A0 => 0x1A1,
+ 0x1A2 => 0x1A3,
+ 0x1A4 => 0x1A5,
+ 0x1A6 => 0x280,
+ 0x1A7 => 0x1A8,
+ 0x1A9 => 0x283,
+ 0x1AC => 0x1AD,
+ 0x1AE => 0x288,
+ 0x1AF => 0x1B0,
+ 0x1B1 => 0x28A,
+ 0x1B2 => 0x28B,
+ 0x1B3 => 0x1B4,
+ 0x1B5 => 0x1B6,
+ 0x1B7 => 0x292,
+ 0x1B8 => 0x1B9,
+ 0x1BC => 0x1BD,
+ 0x1C4 => 0x1C6,
+ 0x1C5 => 0x1C6,
+ 0x1C7 => 0x1C9,
+ 0x1C8 => 0x1C9,
+ 0x1CA => 0x1CC,
+ 0x1CB => 0x1CC,
+ 0x1CD => 0x1CE,
+ 0x1CF => 0x1D0,
+ 0x1D1 => 0x1D2,
+ 0x1D3 => 0x1D4,
+ 0x1D5 => 0x1D6,
+ 0x1D7 => 0x1D8,
+ 0x1D9 => 0x1DA,
+ 0x1DB => 0x1DC,
+ 0x1DE => 0x1DF,
+ 0x1E0 => 0x1E1,
+ 0x1E2 => 0x1E3,
+ 0x1E4 => 0x1E5,
+ 0x1E6 => 0x1E7,
+ 0x1E8 => 0x1E9,
+ 0x1EA => 0x1EB,
+ 0x1EC => 0x1ED,
+ 0x1EE => 0x1EF,
+ 0x1F1 => 0x1F3,
+ 0x1F2 => 0x1F3,
+ 0x1F4 => 0x1F5,
+ 0x1F6 => 0x195,
+ 0x1F7 => 0x1BF,
+ 0x1F8 => 0x1F9,
+ 0x1FA => 0x1FB,
+ 0x1FC => 0x1FD,
+ 0x1FE => 0x1FF,
+ 0x200 => 0x201,
+ 0x202 => 0x203,
+ 0x204 => 0x205,
+ 0x206 => 0x207,
+ 0x208 => 0x209,
+ 0x20A => 0x20B,
+ 0x20C => 0x20D,
+ 0x20E => 0x20F,
+ 0x210 => 0x211,
+ 0x212 => 0x213,
+ 0x214 => 0x215,
+ 0x216 => 0x217,
+ 0x218 => 0x219,
+ 0x21A => 0x21B,
+ 0x21C => 0x21D,
+ 0x21E => 0x21F,
+ 0x220 => 0x19E,
+ 0x222 => 0x223,
+ 0x224 => 0x225,
+ 0x226 => 0x227,
+ 0x228 => 0x229,
+ 0x22A => 0x22B,
+ 0x22C => 0x22D,
+ 0x22E => 0x22F,
+ 0x230 => 0x231,
+ 0x232 => 0x233,
+ 0x23A => 0x2C65,
+ 0x23B => 0x23C,
+ 0x23D => 0x19A,
+ 0x23E => 0x2C66,
+ 0x241 => 0x242,
+ 0x243 => 0x180,
+ 0x244 => 0x289,
+ 0x245 => 0x28C,
+ 0x246 => 0x247,
+ 0x248 => 0x249,
+ 0x24A => 0x24B,
+ 0x24C => 0x24D,
+ 0x24E => 0x24F,
+ 0x345 => 0x3B9,
+ 0x370 => 0x371,
+ 0x372 => 0x373,
+ 0x376 => 0x377,
+ 0x37F => 0x3F3,
+ 0x386 => 0x3AC,
+ 0x388 => 0x3AD,
+ 0x389 => 0x3AE,
+ 0x38A => 0x3AF,
+ 0x38C => 0x3CC,
+ 0x38E => 0x3CD,
+ 0x38F => 0x3CE,
+ 0x391 => 0x3B1,
+ 0x392 => 0x3B2,
+ 0x393 => 0x3B3,
+ 0x394 => 0x3B4,
+ 0x395 => 0x3B5,
+ 0x396 => 0x3B6,
+ 0x397 => 0x3B7,
+ 0x398 => 0x3B8,
+ 0x399 => 0x3B9,
+ 0x39A => 0x3BA,
+ 0x39B => 0x3BB,
+ 0x39C => 0x3BC,
+ 0x39D => 0x3BD,
+ 0x39E => 0x3BE,
+ 0x39F => 0x3BF,
+ 0x3A0 => 0x3C0,
+ 0x3A1 => 0x3C1,
+ 0x3A3 => 0x3C3,
+ 0x3A4 => 0x3C4,
+ 0x3A5 => 0x3C5,
+ 0x3A6 => 0x3C6,
+ 0x3A7 => 0x3C7,
+ 0x3A8 => 0x3C8,
+ 0x3A9 => 0x3C9,
+ 0x3AA => 0x3CA,
+ 0x3AB => 0x3CB,
+ 0x3C2 => 0x3C3,
+ 0x3CF => 0x3D7,
+ 0x3D0 => 0x3B2,
+ 0x3D1 => 0x3B8,
+ 0x3D5 => 0x3C6,
+ 0x3D6 => 0x3C0,
+ 0x3D8 => 0x3D9,
+ 0x3DA => 0x3DB,
+ 0x3DC => 0x3DD,
+ 0x3DE => 0x3DF,
+ 0x3E0 => 0x3E1,
+ 0x3E2 => 0x3E3,
+ 0x3E4 => 0x3E5,
+ 0x3E6 => 0x3E7,
+ 0x3E8 => 0x3E9,
+ 0x3EA => 0x3EB,
+ 0x3EC => 0x3ED,
+ 0x3EE => 0x3EF,
+ 0x3F0 => 0x3BA,
+ 0x3F1 => 0x3C1,
+ 0x3F4 => 0x3B8,
+ 0x3F5 => 0x3B5,
+ 0x3F7 => 0x3F8,
+ 0x3F9 => 0x3F2,
+ 0x3FA => 0x3FB,
+ 0x3FD => 0x37B,
+ 0x3FE => 0x37C,
+ 0x3FF => 0x37D,
+ 0x400 => 0x450,
+ 0x401 => 0x451,
+ 0x402 => 0x452,
+ 0x403 => 0x453,
+ 0x404 => 0x454,
+ 0x405 => 0x455,
+ 0x406 => 0x456,
+ 0x407 => 0x457,
+ 0x408 => 0x458,
+ 0x409 => 0x459,
+ 0x40A => 0x45A,
+ 0x40B => 0x45B,
+ 0x40C => 0x45C,
+ 0x40D => 0x45D,
+ 0x40E => 0x45E,
+ 0x40F => 0x45F,
+ 0x410 => 0x430,
+ 0x411 => 0x431,
+ 0x412 => 0x432,
+ 0x413 => 0x433,
+ 0x414 => 0x434,
+ 0x415 => 0x435,
+ 0x416 => 0x436,
+ 0x417 => 0x437,
+ 0x418 => 0x438,
+ 0x419 => 0x439,
+ 0x41A => 0x43A,
+ 0x41B => 0x43B,
+ 0x41C => 0x43C,
+ 0x41D => 0x43D,
+ 0x41E => 0x43E,
+ 0x41F => 0x43F,
+ 0x420 => 0x440,
+ 0x421 => 0x441,
+ 0x422 => 0x442,
+ 0x423 => 0x443,
+ 0x424 => 0x444,
+ 0x425 => 0x445,
+ 0x426 => 0x446,
+ 0x427 => 0x447,
+ 0x428 => 0x448,
+ 0x429 => 0x449,
+ 0x42A => 0x44A,
+ 0x42B => 0x44B,
+ 0x42C => 0x44C,
+ 0x42D => 0x44D,
+ 0x42E => 0x44E,
+ 0x42F => 0x44F,
+ 0x460 => 0x461,
+ 0x462 => 0x463,
+ 0x464 => 0x465,
+ 0x466 => 0x467,
+ 0x468 => 0x469,
+ 0x46A => 0x46B,
+ 0x46C => 0x46D,
+ 0x46E => 0x46F,
+ 0x470 => 0x471,
+ 0x472 => 0x473,
+ 0x474 => 0x475,
+ 0x476 => 0x477,
+ 0x478 => 0x479,
+ 0x47A => 0x47B,
+ 0x47C => 0x47D,
+ 0x47E => 0x47F,
+ 0x480 => 0x481,
+ 0x48A => 0x48B,
+ 0x48C => 0x48D,
+ 0x48E => 0x48F,
+ 0x490 => 0x491,
+ 0x492 => 0x493,
+ 0x494 => 0x495,
+ 0x496 => 0x497,
+ 0x498 => 0x499,
+ 0x49A => 0x49B,
+ 0x49C => 0x49D,
+ 0x49E => 0x49F,
+ 0x4A0 => 0x4A1,
+ 0x4A2 => 0x4A3,
+ 0x4A4 => 0x4A5,
+ 0x4A6 => 0x4A7,
+ 0x4A8 => 0x4A9,
+ 0x4AA => 0x4AB,
+ 0x4AC => 0x4AD,
+ 0x4AE => 0x4AF,
+ 0x4B0 => 0x4B1,
+ 0x4B2 => 0x4B3,
+ 0x4B4 => 0x4B5,
+ 0x4B6 => 0x4B7,
+ 0x4B8 => 0x4B9,
+ 0x4BA => 0x4BB,
+ 0x4BC => 0x4BD,
+ 0x4BE => 0x4BF,
+ 0x4C0 => 0x4CF,
+ 0x4C1 => 0x4C2,
+ 0x4C3 => 0x4C4,
+ 0x4C5 => 0x4C6,
+ 0x4C7 => 0x4C8,
+ 0x4C9 => 0x4CA,
+ 0x4CB => 0x4CC,
+ 0x4CD => 0x4CE,
+ 0x4D0 => 0x4D1,
+ 0x4D2 => 0x4D3,
+ 0x4D4 => 0x4D5,
+ 0x4D6 => 0x4D7,
+ 0x4D8 => 0x4D9,
+ 0x4DA => 0x4DB,
+ 0x4DC => 0x4DD,
+ 0x4DE => 0x4DF,
+ 0x4E0 => 0x4E1,
+ 0x4E2 => 0x4E3,
+ 0x4E4 => 0x4E5,
+ 0x4E6 => 0x4E7,
+ 0x4E8 => 0x4E9,
+ 0x4EA => 0x4EB,
+ 0x4EC => 0x4ED,
+ 0x4EE => 0x4EF,
+ 0x4F0 => 0x4F1,
+ 0x4F2 => 0x4F3,
+ 0x4F4 => 0x4F5,
+ 0x4F6 => 0x4F7,
+ 0x4F8 => 0x4F9,
+ 0x4FA => 0x4FB,
+ 0x4FC => 0x4FD,
+ 0x4FE => 0x4FF,
+ 0x500 => 0x501,
+ 0x502 => 0x503,
+ 0x504 => 0x505,
+ 0x506 => 0x507,
+ 0x508 => 0x509,
+ 0x50A => 0x50B,
+ 0x50C => 0x50D,
+ 0x50E => 0x50F,
+ 0x510 => 0x511,
+ 0x512 => 0x513,
+ 0x514 => 0x515,
+ 0x516 => 0x517,
+ 0x518 => 0x519,
+ 0x51A => 0x51B,
+ 0x51C => 0x51D,
+ 0x51E => 0x51F,
+ 0x520 => 0x521,
+ 0x522 => 0x523,
+ 0x524 => 0x525,
+ 0x526 => 0x527,
+ 0x528 => 0x529,
+ 0x52A => 0x52B,
+ 0x52C => 0x52D,
+ 0x52E => 0x52F,
+ 0x531 => 0x561,
+ 0x532 => 0x562,
+ 0x533 => 0x563,
+ 0x534 => 0x564,
+ 0x535 => 0x565,
+ 0x536 => 0x566,
+ 0x537 => 0x567,
+ 0x538 => 0x568,
+ 0x539 => 0x569,
+ 0x53A => 0x56A,
+ 0x53B => 0x56B,
+ 0x53C => 0x56C,
+ 0x53D => 0x56D,
+ 0x53E => 0x56E,
+ 0x53F => 0x56F,
+ 0x540 => 0x570,
+ 0x541 => 0x571,
+ 0x542 => 0x572,
+ 0x543 => 0x573,
+ 0x544 => 0x574,
+ 0x545 => 0x575,
+ 0x546 => 0x576,
+ 0x547 => 0x577,
+ 0x548 => 0x578,
+ 0x549 => 0x579,
+ 0x54A => 0x57A,
+ 0x54B => 0x57B,
+ 0x54C => 0x57C,
+ 0x54D => 0x57D,
+ 0x54E => 0x57E,
+ 0x54F => 0x57F,
+ 0x550 => 0x580,
+ 0x551 => 0x581,
+ 0x552 => 0x582,
+ 0x553 => 0x583,
+ 0x554 => 0x584,
+ 0x555 => 0x585,
+ 0x556 => 0x586,
+ 0x10A0 => 0x2D00,
+ 0x10A1 => 0x2D01,
+ 0x10A2 => 0x2D02,
+ 0x10A3 => 0x2D03,
+ 0x10A4 => 0x2D04,
+ 0x10A5 => 0x2D05,
+ 0x10A6 => 0x2D06,
+ 0x10A7 => 0x2D07,
+ 0x10A8 => 0x2D08,
+ 0x10A9 => 0x2D09,
+ 0x10AA => 0x2D0A,
+ 0x10AB => 0x2D0B,
+ 0x10AC => 0x2D0C,
+ 0x10AD => 0x2D0D,
+ 0x10AE => 0x2D0E,
+ 0x10AF => 0x2D0F,
+ 0x10B0 => 0x2D10,
+ 0x10B1 => 0x2D11,
+ 0x10B2 => 0x2D12,
+ 0x10B3 => 0x2D13,
+ 0x10B4 => 0x2D14,
+ 0x10B5 => 0x2D15,
+ 0x10B6 => 0x2D16,
+ 0x10B7 => 0x2D17,
+ 0x10B8 => 0x2D18,
+ 0x10B9 => 0x2D19,
+ 0x10BA => 0x2D1A,
+ 0x10BB => 0x2D1B,
+ 0x10BC => 0x2D1C,
+ 0x10BD => 0x2D1D,
+ 0x10BE => 0x2D1E,
+ 0x10BF => 0x2D1F,
+ 0x10C0 => 0x2D20,
+ 0x10C1 => 0x2D21,
+ 0x10C2 => 0x2D22,
+ 0x10C3 => 0x2D23,
+ 0x10C4 => 0x2D24,
+ 0x10C5 => 0x2D25,
+ 0x10C7 => 0x2D27,
+ 0x10CD => 0x2D2D,
+ 0x13F8 => 0x13F0,
+ 0x13F9 => 0x13F1,
+ 0x13FA => 0x13F2,
+ 0x13FB => 0x13F3,
+ 0x13FC => 0x13F4,
+ 0x13FD => 0x13F5,
+ 0x1C80 => 0x432,
+ 0x1C81 => 0x434,
+ 0x1C82 => 0x43E,
+ 0x1C83 => 0x441,
+ 0x1C84 => 0x442,
+ 0x1C85 => 0x442,
+ 0x1C86 => 0x44A,
+ 0x1C87 => 0x463,
+ 0x1C88 => 0xA64B,
+ 0x1C90 => 0x10D0,
+ 0x1C91 => 0x10D1,
+ 0x1C92 => 0x10D2,
+ 0x1C93 => 0x10D3,
+ 0x1C94 => 0x10D4,
+ 0x1C95 => 0x10D5,
+ 0x1C96 => 0x10D6,
+ 0x1C97 => 0x10D7,
+ 0x1C98 => 0x10D8,
+ 0x1C99 => 0x10D9,
+ 0x1C9A => 0x10DA,
+ 0x1C9B => 0x10DB,
+ 0x1C9C => 0x10DC,
+ 0x1C9D => 0x10DD,
+ 0x1C9E => 0x10DE,
+ 0x1C9F => 0x10DF,
+ 0x1CA0 => 0x10E0,
+ 0x1CA1 => 0x10E1,
+ 0x1CA2 => 0x10E2,
+ 0x1CA3 => 0x10E3,
+ 0x1CA4 => 0x10E4,
+ 0x1CA5 => 0x10E5,
+ 0x1CA6 => 0x10E6,
+ 0x1CA7 => 0x10E7,
+ 0x1CA8 => 0x10E8,
+ 0x1CA9 => 0x10E9,
+ 0x1CAA => 0x10EA,
+ 0x1CAB => 0x10EB,
+ 0x1CAC => 0x10EC,
+ 0x1CAD => 0x10ED,
+ 0x1CAE => 0x10EE,
+ 0x1CAF => 0x10EF,
+ 0x1CB0 => 0x10F0,
+ 0x1CB1 => 0x10F1,
+ 0x1CB2 => 0x10F2,
+ 0x1CB3 => 0x10F3,
+ 0x1CB4 => 0x10F4,
+ 0x1CB5 => 0x10F5,
+ 0x1CB6 => 0x10F6,
+ 0x1CB7 => 0x10F7,
+ 0x1CB8 => 0x10F8,
+ 0x1CB9 => 0x10F9,
+ 0x1CBA => 0x10FA,
+ 0x1CBD => 0x10FD,
+ 0x1CBE => 0x10FE,
+ 0x1CBF => 0x10FF,
+ 0x1E00 => 0x1E01,
+ 0x1E02 => 0x1E03,
+ 0x1E04 => 0x1E05,
+ 0x1E06 => 0x1E07,
+ 0x1E08 => 0x1E09,
+ 0x1E0A => 0x1E0B,
+ 0x1E0C => 0x1E0D,
+ 0x1E0E => 0x1E0F,
+ 0x1E10 => 0x1E11,
+ 0x1E12 => 0x1E13,
+ 0x1E14 => 0x1E15,
+ 0x1E16 => 0x1E17,
+ 0x1E18 => 0x1E19,
+ 0x1E1A => 0x1E1B,
+ 0x1E1C => 0x1E1D,
+ 0x1E1E => 0x1E1F,
+ 0x1E20 => 0x1E21,
+ 0x1E22 => 0x1E23,
+ 0x1E24 => 0x1E25,
+ 0x1E26 => 0x1E27,
+ 0x1E28 => 0x1E29,
+ 0x1E2A => 0x1E2B,
+ 0x1E2C => 0x1E2D,
+ 0x1E2E => 0x1E2F,
+ 0x1E30 => 0x1E31,
+ 0x1E32 => 0x1E33,
+ 0x1E34 => 0x1E35,
+ 0x1E36 => 0x1E37,
+ 0x1E38 => 0x1E39,
+ 0x1E3A => 0x1E3B,
+ 0x1E3C => 0x1E3D,
+ 0x1E3E => 0x1E3F,
+ 0x1E40 => 0x1E41,
+ 0x1E42 => 0x1E43,
+ 0x1E44 => 0x1E45,
+ 0x1E46 => 0x1E47,
+ 0x1E48 => 0x1E49,
+ 0x1E4A => 0x1E4B,
+ 0x1E4C => 0x1E4D,
+ 0x1E4E => 0x1E4F,
+ 0x1E50 => 0x1E51,
+ 0x1E52 => 0x1E53,
+ 0x1E54 => 0x1E55,
+ 0x1E56 => 0x1E57,
+ 0x1E58 => 0x1E59,
+ 0x1E5A => 0x1E5B,
+ 0x1E5C => 0x1E5D,
+ 0x1E5E => 0x1E5F,
+ 0x1E60 => 0x1E61,
+ 0x1E62 => 0x1E63,
+ 0x1E64 => 0x1E65,
+ 0x1E66 => 0x1E67,
+ 0x1E68 => 0x1E69,
+ 0x1E6A => 0x1E6B,
+ 0x1E6C => 0x1E6D,
+ 0x1E6E => 0x1E6F,
+ 0x1E70 => 0x1E71,
+ 0x1E72 => 0x1E73,
+ 0x1E74 => 0x1E75,
+ 0x1E76 => 0x1E77,
+ 0x1E78 => 0x1E79,
+ 0x1E7A => 0x1E7B,
+ 0x1E7C => 0x1E7D,
+ 0x1E7E => 0x1E7F,
+ 0x1E80 => 0x1E81,
+ 0x1E82 => 0x1E83,
+ 0x1E84 => 0x1E85,
+ 0x1E86 => 0x1E87,
+ 0x1E88 => 0x1E89,
+ 0x1E8A => 0x1E8B,
+ 0x1E8C => 0x1E8D,
+ 0x1E8E => 0x1E8F,
+ 0x1E90 => 0x1E91,
+ 0x1E92 => 0x1E93,
+ 0x1E94 => 0x1E95,
+ 0x1E9B => 0x1E61,
+ 0x1E9E => 0xDF,
+ 0x1EA0 => 0x1EA1,
+ 0x1EA2 => 0x1EA3,
+ 0x1EA4 => 0x1EA5,
+ 0x1EA6 => 0x1EA7,
+ 0x1EA8 => 0x1EA9,
+ 0x1EAA => 0x1EAB,
+ 0x1EAC => 0x1EAD,
+ 0x1EAE => 0x1EAF,
+ 0x1EB0 => 0x1EB1,
+ 0x1EB2 => 0x1EB3,
+ 0x1EB4 => 0x1EB5,
+ 0x1EB6 => 0x1EB7,
+ 0x1EB8 => 0x1EB9,
+ 0x1EBA => 0x1EBB,
+ 0x1EBC => 0x1EBD,
+ 0x1EBE => 0x1EBF,
+ 0x1EC0 => 0x1EC1,
+ 0x1EC2 => 0x1EC3,
+ 0x1EC4 => 0x1EC5,
+ 0x1EC6 => 0x1EC7,
+ 0x1EC8 => 0x1EC9,
+ 0x1ECA => 0x1ECB,
+ 0x1ECC => 0x1ECD,
+ 0x1ECE => 0x1ECF,
+ 0x1ED0 => 0x1ED1,
+ 0x1ED2 => 0x1ED3,
+ 0x1ED4 => 0x1ED5,
+ 0x1ED6 => 0x1ED7,
+ 0x1ED8 => 0x1ED9,
+ 0x1EDA => 0x1EDB,
+ 0x1EDC => 0x1EDD,
+ 0x1EDE => 0x1EDF,
+ 0x1EE0 => 0x1EE1,
+ 0x1EE2 => 0x1EE3,
+ 0x1EE4 => 0x1EE5,
+ 0x1EE6 => 0x1EE7,
+ 0x1EE8 => 0x1EE9,
+ 0x1EEA => 0x1EEB,
+ 0x1EEC => 0x1EED,
+ 0x1EEE => 0x1EEF,
+ 0x1EF0 => 0x1EF1,
+ 0x1EF2 => 0x1EF3,
+ 0x1EF4 => 0x1EF5,
+ 0x1EF6 => 0x1EF7,
+ 0x1EF8 => 0x1EF9,
+ 0x1EFA => 0x1EFB,
+ 0x1EFC => 0x1EFD,
+ 0x1EFE => 0x1EFF,
+ 0x1F08 => 0x1F00,
+ 0x1F09 => 0x1F01,
+ 0x1F0A => 0x1F02,
+ 0x1F0B => 0x1F03,
+ 0x1F0C => 0x1F04,
+ 0x1F0D => 0x1F05,
+ 0x1F0E => 0x1F06,
+ 0x1F0F => 0x1F07,
+ 0x1F18 => 0x1F10,
+ 0x1F19 => 0x1F11,
+ 0x1F1A => 0x1F12,
+ 0x1F1B => 0x1F13,
+ 0x1F1C => 0x1F14,
+ 0x1F1D => 0x1F15,
+ 0x1F28 => 0x1F20,
+ 0x1F29 => 0x1F21,
+ 0x1F2A => 0x1F22,
+ 0x1F2B => 0x1F23,
+ 0x1F2C => 0x1F24,
+ 0x1F2D => 0x1F25,
+ 0x1F2E => 0x1F26,
+ 0x1F2F => 0x1F27,
+ 0x1F38 => 0x1F30,
+ 0x1F39 => 0x1F31,
+ 0x1F3A => 0x1F32,
+ 0x1F3B => 0x1F33,
+ 0x1F3C => 0x1F34,
+ 0x1F3D => 0x1F35,
+ 0x1F3E => 0x1F36,
+ 0x1F3F => 0x1F37,
+ 0x1F48 => 0x1F40,
+ 0x1F49 => 0x1F41,
+ 0x1F4A => 0x1F42,
+ 0x1F4B => 0x1F43,
+ 0x1F4C => 0x1F44,
+ 0x1F4D => 0x1F45,
+ 0x1F59 => 0x1F51,
+ 0x1F5B => 0x1F53,
+ 0x1F5D => 0x1F55,
+ 0x1F5F => 0x1F57,
+ 0x1F68 => 0x1F60,
+ 0x1F69 => 0x1F61,
+ 0x1F6A => 0x1F62,
+ 0x1F6B => 0x1F63,
+ 0x1F6C => 0x1F64,
+ 0x1F6D => 0x1F65,
+ 0x1F6E => 0x1F66,
+ 0x1F6F => 0x1F67,
+ 0x1F88 => 0x1F80,
+ 0x1F89 => 0x1F81,
+ 0x1F8A => 0x1F82,
+ 0x1F8B => 0x1F83,
+ 0x1F8C => 0x1F84,
+ 0x1F8D => 0x1F85,
+ 0x1F8E => 0x1F86,
+ 0x1F8F => 0x1F87,
+ 0x1F98 => 0x1F90,
+ 0x1F99 => 0x1F91,
+ 0x1F9A => 0x1F92,
+ 0x1F9B => 0x1F93,
+ 0x1F9C => 0x1F94,
+ 0x1F9D => 0x1F95,
+ 0x1F9E => 0x1F96,
+ 0x1F9F => 0x1F97,
+ 0x1FA8 => 0x1FA0,
+ 0x1FA9 => 0x1FA1,
+ 0x1FAA => 0x1FA2,
+ 0x1FAB => 0x1FA3,
+ 0x1FAC => 0x1FA4,
+ 0x1FAD => 0x1FA5,
+ 0x1FAE => 0x1FA6,
+ 0x1FAF => 0x1FA7,
+ 0x1FB8 => 0x1FB0,
+ 0x1FB9 => 0x1FB1,
+ 0x1FBA => 0x1F70,
+ 0x1FBB => 0x1F71,
+ 0x1FBC => 0x1FB3,
+ 0x1FBE => 0x3B9,
+ 0x1FC8 => 0x1F72,
+ 0x1FC9 => 0x1F73,
+ 0x1FCA => 0x1F74,
+ 0x1FCB => 0x1F75,
+ 0x1FCC => 0x1FC3,
+ 0x1FD8 => 0x1FD0,
+ 0x1FD9 => 0x1FD1,
+ 0x1FDA => 0x1F76,
+ 0x1FDB => 0x1F77,
+ 0x1FE8 => 0x1FE0,
+ 0x1FE9 => 0x1FE1,
+ 0x1FEA => 0x1F7A,
+ 0x1FEB => 0x1F7B,
+ 0x1FEC => 0x1FE5,
+ 0x1FF8 => 0x1F78,
+ 0x1FF9 => 0x1F79,
+ 0x1FFA => 0x1F7C,
+ 0x1FFB => 0x1F7D,
+ 0x1FFC => 0x1FF3,
+ 0x2126 => 0x3C9,
+ 0x212A => 0x6B,
+ 0x212B => 0xE5,
+ 0x2132 => 0x214E,
+ 0x2160 => 0x2170,
+ 0x2161 => 0x2171,
+ 0x2162 => 0x2172,
+ 0x2163 => 0x2173,
+ 0x2164 => 0x2174,
+ 0x2165 => 0x2175,
+ 0x2166 => 0x2176,
+ 0x2167 => 0x2177,
+ 0x2168 => 0x2178,
+ 0x2169 => 0x2179,
+ 0x216A => 0x217A,
+ 0x216B => 0x217B,
+ 0x216C => 0x217C,
+ 0x216D => 0x217D,
+ 0x216E => 0x217E,
+ 0x216F => 0x217F,
+ 0x2183 => 0x2184,
+ 0x24B6 => 0x24D0,
+ 0x24B7 => 0x24D1,
+ 0x24B8 => 0x24D2,
+ 0x24B9 => 0x24D3,
+ 0x24BA => 0x24D4,
+ 0x24BB => 0x24D5,
+ 0x24BC => 0x24D6,
+ 0x24BD => 0x24D7,
+ 0x24BE => 0x24D8,
+ 0x24BF => 0x24D9,
+ 0x24C0 => 0x24DA,
+ 0x24C1 => 0x24DB,
+ 0x24C2 => 0x24DC,
+ 0x24C3 => 0x24DD,
+ 0x24C4 => 0x24DE,
+ 0x24C5 => 0x24DF,
+ 0x24C6 => 0x24E0,
+ 0x24C7 => 0x24E1,
+ 0x24C8 => 0x24E2,
+ 0x24C9 => 0x24E3,
+ 0x24CA => 0x24E4,
+ 0x24CB => 0x24E5,
+ 0x24CC => 0x24E6,
+ 0x24CD => 0x24E7,
+ 0x24CE => 0x24E8,
+ 0x24CF => 0x24E9,
+ 0x2C00 => 0x2C30,
+ 0x2C01 => 0x2C31,
+ 0x2C02 => 0x2C32,
+ 0x2C03 => 0x2C33,
+ 0x2C04 => 0x2C34,
+ 0x2C05 => 0x2C35,
+ 0x2C06 => 0x2C36,
+ 0x2C07 => 0x2C37,
+ 0x2C08 => 0x2C38,
+ 0x2C09 => 0x2C39,
+ 0x2C0A => 0x2C3A,
+ 0x2C0B => 0x2C3B,
+ 0x2C0C => 0x2C3C,
+ 0x2C0D => 0x2C3D,
+ 0x2C0E => 0x2C3E,
+ 0x2C0F => 0x2C3F,
+ 0x2C10 => 0x2C40,
+ 0x2C11 => 0x2C41,
+ 0x2C12 => 0x2C42,
+ 0x2C13 => 0x2C43,
+ 0x2C14 => 0x2C44,
+ 0x2C15 => 0x2C45,
+ 0x2C16 => 0x2C46,
+ 0x2C17 => 0x2C47,
+ 0x2C18 => 0x2C48,
+ 0x2C19 => 0x2C49,
+ 0x2C1A => 0x2C4A,
+ 0x2C1B => 0x2C4B,
+ 0x2C1C => 0x2C4C,
+ 0x2C1D => 0x2C4D,
+ 0x2C1E => 0x2C4E,
+ 0x2C1F => 0x2C4F,
+ 0x2C20 => 0x2C50,
+ 0x2C21 => 0x2C51,
+ 0x2C22 => 0x2C52,
+ 0x2C23 => 0x2C53,
+ 0x2C24 => 0x2C54,
+ 0x2C25 => 0x2C55,
+ 0x2C26 => 0x2C56,
+ 0x2C27 => 0x2C57,
+ 0x2C28 => 0x2C58,
+ 0x2C29 => 0x2C59,
+ 0x2C2A => 0x2C5A,
+ 0x2C2B => 0x2C5B,
+ 0x2C2C => 0x2C5C,
+ 0x2C2D => 0x2C5D,
+ 0x2C2E => 0x2C5E,
+ 0x2C60 => 0x2C61,
+ 0x2C62 => 0x26B,
+ 0x2C63 => 0x1D7D,
+ 0x2C64 => 0x27D,
+ 0x2C67 => 0x2C68,
+ 0x2C69 => 0x2C6A,
+ 0x2C6B => 0x2C6C,
+ 0x2C6D => 0x251,
+ 0x2C6E => 0x271,
+ 0x2C6F => 0x250,
+ 0x2C70 => 0x252,
+ 0x2C72 => 0x2C73,
+ 0x2C75 => 0x2C76,
+ 0x2C7E => 0x23F,
+ 0x2C7F => 0x240,
+ 0x2C80 => 0x2C81,
+ 0x2C82 => 0x2C83,
+ 0x2C84 => 0x2C85,
+ 0x2C86 => 0x2C87,
+ 0x2C88 => 0x2C89,
+ 0x2C8A => 0x2C8B,
+ 0x2C8C => 0x2C8D,
+ 0x2C8E => 0x2C8F,
+ 0x2C90 => 0x2C91,
+ 0x2C92 => 0x2C93,
+ 0x2C94 => 0x2C95,
+ 0x2C96 => 0x2C97,
+ 0x2C98 => 0x2C99,
+ 0x2C9A => 0x2C9B,
+ 0x2C9C => 0x2C9D,
+ 0x2C9E => 0x2C9F,
+ 0x2CA0 => 0x2CA1,
+ 0x2CA2 => 0x2CA3,
+ 0x2CA4 => 0x2CA5,
+ 0x2CA6 => 0x2CA7,
+ 0x2CA8 => 0x2CA9,
+ 0x2CAA => 0x2CAB,
+ 0x2CAC => 0x2CAD,
+ 0x2CAE => 0x2CAF,
+ 0x2CB0 => 0x2CB1,
+ 0x2CB2 => 0x2CB3,
+ 0x2CB4 => 0x2CB5,
+ 0x2CB6 => 0x2CB7,
+ 0x2CB8 => 0x2CB9,
+ 0x2CBA => 0x2CBB,
+ 0x2CBC => 0x2CBD,
+ 0x2CBE => 0x2CBF,
+ 0x2CC0 => 0x2CC1,
+ 0x2CC2 => 0x2CC3,
+ 0x2CC4 => 0x2CC5,
+ 0x2CC6 => 0x2CC7,
+ 0x2CC8 => 0x2CC9,
+ 0x2CCA => 0x2CCB,
+ 0x2CCC => 0x2CCD,
+ 0x2CCE => 0x2CCF,
+ 0x2CD0 => 0x2CD1,
+ 0x2CD2 => 0x2CD3,
+ 0x2CD4 => 0x2CD5,
+ 0x2CD6 => 0x2CD7,
+ 0x2CD8 => 0x2CD9,
+ 0x2CDA => 0x2CDB,
+ 0x2CDC => 0x2CDD,
+ 0x2CDE => 0x2CDF,
+ 0x2CE0 => 0x2CE1,
+ 0x2CE2 => 0x2CE3,
+ 0x2CEB => 0x2CEC,
+ 0x2CED => 0x2CEE,
+ 0x2CF2 => 0x2CF3,
+ 0xA640 => 0xA641,
+ 0xA642 => 0xA643,
+ 0xA644 => 0xA645,
+ 0xA646 => 0xA647,
+ 0xA648 => 0xA649,
+ 0xA64A => 0xA64B,
+ 0xA64C => 0xA64D,
+ 0xA64E => 0xA64F,
+ 0xA650 => 0xA651,
+ 0xA652 => 0xA653,
+ 0xA654 => 0xA655,
+ 0xA656 => 0xA657,
+ 0xA658 => 0xA659,
+ 0xA65A => 0xA65B,
+ 0xA65C => 0xA65D,
+ 0xA65E => 0xA65F,
+ 0xA660 => 0xA661,
+ 0xA662 => 0xA663,
+ 0xA664 => 0xA665,
+ 0xA666 => 0xA667,
+ 0xA668 => 0xA669,
+ 0xA66A => 0xA66B,
+ 0xA66C => 0xA66D,
+ 0xA680 => 0xA681,
+ 0xA682 => 0xA683,
+ 0xA684 => 0xA685,
+ 0xA686 => 0xA687,
+ 0xA688 => 0xA689,
+ 0xA68A => 0xA68B,
+ 0xA68C => 0xA68D,
+ 0xA68E => 0xA68F,
+ 0xA690 => 0xA691,
+ 0xA692 => 0xA693,
+ 0xA694 => 0xA695,
+ 0xA696 => 0xA697,
+ 0xA698 => 0xA699,
+ 0xA69A => 0xA69B,
+ 0xA722 => 0xA723,
+ 0xA724 => 0xA725,
+ 0xA726 => 0xA727,
+ 0xA728 => 0xA729,
+ 0xA72A => 0xA72B,
+ 0xA72C => 0xA72D,
+ 0xA72E => 0xA72F,
+ 0xA732 => 0xA733,
+ 0xA734 => 0xA735,
+ 0xA736 => 0xA737,
+ 0xA738 => 0xA739,
+ 0xA73A => 0xA73B,
+ 0xA73C => 0xA73D,
+ 0xA73E => 0xA73F,
+ 0xA740 => 0xA741,
+ 0xA742 => 0xA743,
+ 0xA744 => 0xA745,
+ 0xA746 => 0xA747,
+ 0xA748 => 0xA749,
+ 0xA74A => 0xA74B,
+ 0xA74C => 0xA74D,
+ 0xA74E => 0xA74F,
+ 0xA750 => 0xA751,
+ 0xA752 => 0xA753,
+ 0xA754 => 0xA755,
+ 0xA756 => 0xA757,
+ 0xA758 => 0xA759,
+ 0xA75A => 0xA75B,
+ 0xA75C => 0xA75D,
+ 0xA75E => 0xA75F,
+ 0xA760 => 0xA761,
+ 0xA762 => 0xA763,
+ 0xA764 => 0xA765,
+ 0xA766 => 0xA767,
+ 0xA768 => 0xA769,
+ 0xA76A => 0xA76B,
+ 0xA76C => 0xA76D,
+ 0xA76E => 0xA76F,
+ 0xA779 => 0xA77A,
+ 0xA77B => 0xA77C,
+ 0xA77D => 0x1D79,
+ 0xA77E => 0xA77F,
+ 0xA780 => 0xA781,
+ 0xA782 => 0xA783,
+ 0xA784 => 0xA785,
+ 0xA786 => 0xA787,
+ 0xA78B => 0xA78C,
+ 0xA78D => 0x265,
+ 0xA790 => 0xA791,
+ 0xA792 => 0xA793,
+ 0xA796 => 0xA797,
+ 0xA798 => 0xA799,
+ 0xA79A => 0xA79B,
+ 0xA79C => 0xA79D,
+ 0xA79E => 0xA79F,
+ 0xA7A0 => 0xA7A1,
+ 0xA7A2 => 0xA7A3,
+ 0xA7A4 => 0xA7A5,
+ 0xA7A6 => 0xA7A7,
+ 0xA7A8 => 0xA7A9,
+ 0xA7AA => 0x266,
+ 0xA7AB => 0x25C,
+ 0xA7AC => 0x261,
+ 0xA7AD => 0x26C,
+ 0xA7AE => 0x26A,
+ 0xA7B0 => 0x29E,
+ 0xA7B1 => 0x287,
+ 0xA7B2 => 0x29D,
+ 0xA7B3 => 0xAB53,
+ 0xA7B4 => 0xA7B5,
+ 0xA7B6 => 0xA7B7,
+ 0xA7B8 => 0xA7B9,
+ 0xA7BA => 0xA7BB,
+ 0xA7BC => 0xA7BD,
+ 0xA7BE => 0xA7BF,
+ 0xA7C2 => 0xA7C3,
+ 0xA7C4 => 0xA794,
+ 0xA7C5 => 0x282,
+ 0xA7C6 => 0x1D8E,
+ 0xA7C7 => 0xA7C8,
+ 0xA7C9 => 0xA7CA,
+ 0xA7F5 => 0xA7F6,
+ 0xAB70 => 0x13A0,
+ 0xAB71 => 0x13A1,
+ 0xAB72 => 0x13A2,
+ 0xAB73 => 0x13A3,
+ 0xAB74 => 0x13A4,
+ 0xAB75 => 0x13A5,
+ 0xAB76 => 0x13A6,
+ 0xAB77 => 0x13A7,
+ 0xAB78 => 0x13A8,
+ 0xAB79 => 0x13A9,
+ 0xAB7A => 0x13AA,
+ 0xAB7B => 0x13AB,
+ 0xAB7C => 0x13AC,
+ 0xAB7D => 0x13AD,
+ 0xAB7E => 0x13AE,
+ 0xAB7F => 0x13AF,
+ 0xAB80 => 0x13B0,
+ 0xAB81 => 0x13B1,
+ 0xAB82 => 0x13B2,
+ 0xAB83 => 0x13B3,
+ 0xAB84 => 0x13B4,
+ 0xAB85 => 0x13B5,
+ 0xAB86 => 0x13B6,
+ 0xAB87 => 0x13B7,
+ 0xAB88 => 0x13B8,
+ 0xAB89 => 0x13B9,
+ 0xAB8A => 0x13BA,
+ 0xAB8B => 0x13BB,
+ 0xAB8C => 0x13BC,
+ 0xAB8D => 0x13BD,
+ 0xAB8E => 0x13BE,
+ 0xAB8F => 0x13BF,
+ 0xAB90 => 0x13C0,
+ 0xAB91 => 0x13C1,
+ 0xAB92 => 0x13C2,
+ 0xAB93 => 0x13C3,
+ 0xAB94 => 0x13C4,
+ 0xAB95 => 0x13C5,
+ 0xAB96 => 0x13C6,
+ 0xAB97 => 0x13C7,
+ 0xAB98 => 0x13C8,
+ 0xAB99 => 0x13C9,
+ 0xAB9A => 0x13CA,
+ 0xAB9B => 0x13CB,
+ 0xAB9C => 0x13CC,
+ 0xAB9D => 0x13CD,
+ 0xAB9E => 0x13CE,
+ 0xAB9F => 0x13CF,
+ 0xABA0 => 0x13D0,
+ 0xABA1 => 0x13D1,
+ 0xABA2 => 0x13D2,
+ 0xABA3 => 0x13D3,
+ 0xABA4 => 0x13D4,
+ 0xABA5 => 0x13D5,
+ 0xABA6 => 0x13D6,
+ 0xABA7 => 0x13D7,
+ 0xABA8 => 0x13D8,
+ 0xABA9 => 0x13D9,
+ 0xABAA => 0x13DA,
+ 0xABAB => 0x13DB,
+ 0xABAC => 0x13DC,
+ 0xABAD => 0x13DD,
+ 0xABAE => 0x13DE,
+ 0xABAF => 0x13DF,
+ 0xABB0 => 0x13E0,
+ 0xABB1 => 0x13E1,
+ 0xABB2 => 0x13E2,
+ 0xABB3 => 0x13E3,
+ 0xABB4 => 0x13E4,
+ 0xABB5 => 0x13E5,
+ 0xABB6 => 0x13E6,
+ 0xABB7 => 0x13E7,
+ 0xABB8 => 0x13E8,
+ 0xABB9 => 0x13E9,
+ 0xABBA => 0x13EA,
+ 0xABBB => 0x13EB,
+ 0xABBC => 0x13EC,
+ 0xABBD => 0x13ED,
+ 0xABBE => 0x13EE,
+ 0xABBF => 0x13EF,
+ 0xFF21 => 0xFF41,
+ 0xFF22 => 0xFF42,
+ 0xFF23 => 0xFF43,
+ 0xFF24 => 0xFF44,
+ 0xFF25 => 0xFF45,
+ 0xFF26 => 0xFF46,
+ 0xFF27 => 0xFF47,
+ 0xFF28 => 0xFF48,
+ 0xFF29 => 0xFF49,
+ 0xFF2A => 0xFF4A,
+ 0xFF2B => 0xFF4B,
+ 0xFF2C => 0xFF4C,
+ 0xFF2D => 0xFF4D,
+ 0xFF2E => 0xFF4E,
+ 0xFF2F => 0xFF4F,
+ 0xFF30 => 0xFF50,
+ 0xFF31 => 0xFF51,
+ 0xFF32 => 0xFF52,
+ 0xFF33 => 0xFF53,
+ 0xFF34 => 0xFF54,
+ 0xFF35 => 0xFF55,
+ 0xFF36 => 0xFF56,
+ 0xFF37 => 0xFF57,
+ 0xFF38 => 0xFF58,
+ 0xFF39 => 0xFF59,
+ 0xFF3A => 0xFF5A,
+ 0x10400 => 0x10428,
+ 0x10401 => 0x10429,
+ 0x10402 => 0x1042A,
+ 0x10403 => 0x1042B,
+ 0x10404 => 0x1042C,
+ 0x10405 => 0x1042D,
+ 0x10406 => 0x1042E,
+ 0x10407 => 0x1042F,
+ 0x10408 => 0x10430,
+ 0x10409 => 0x10431,
+ 0x1040A => 0x10432,
+ 0x1040B => 0x10433,
+ 0x1040C => 0x10434,
+ 0x1040D => 0x10435,
+ 0x1040E => 0x10436,
+ 0x1040F => 0x10437,
+ 0x10410 => 0x10438,
+ 0x10411 => 0x10439,
+ 0x10412 => 0x1043A,
+ 0x10413 => 0x1043B,
+ 0x10414 => 0x1043C,
+ 0x10415 => 0x1043D,
+ 0x10416 => 0x1043E,
+ 0x10417 => 0x1043F,
+ 0x10418 => 0x10440,
+ 0x10419 => 0x10441,
+ 0x1041A => 0x10442,
+ 0x1041B => 0x10443,
+ 0x1041C => 0x10444,
+ 0x1041D => 0x10445,
+ 0x1041E => 0x10446,
+ 0x1041F => 0x10447,
+ 0x10420 => 0x10448,
+ 0x10421 => 0x10449,
+ 0x10422 => 0x1044A,
+ 0x10423 => 0x1044B,
+ 0x10424 => 0x1044C,
+ 0x10425 => 0x1044D,
+ 0x10426 => 0x1044E,
+ 0x10427 => 0x1044F,
+ 0x104B0 => 0x104D8,
+ 0x104B1 => 0x104D9,
+ 0x104B2 => 0x104DA,
+ 0x104B3 => 0x104DB,
+ 0x104B4 => 0x104DC,
+ 0x104B5 => 0x104DD,
+ 0x104B6 => 0x104DE,
+ 0x104B7 => 0x104DF,
+ 0x104B8 => 0x104E0,
+ 0x104B9 => 0x104E1,
+ 0x104BA => 0x104E2,
+ 0x104BB => 0x104E3,
+ 0x104BC => 0x104E4,
+ 0x104BD => 0x104E5,
+ 0x104BE => 0x104E6,
+ 0x104BF => 0x104E7,
+ 0x104C0 => 0x104E8,
+ 0x104C1 => 0x104E9,
+ 0x104C2 => 0x104EA,
+ 0x104C3 => 0x104EB,
+ 0x104C4 => 0x104EC,
+ 0x104C5 => 0x104ED,
+ 0x104C6 => 0x104EE,
+ 0x104C7 => 0x104EF,
+ 0x104C8 => 0x104F0,
+ 0x104C9 => 0x104F1,
+ 0x104CA => 0x104F2,
+ 0x104CB => 0x104F3,
+ 0x104CC => 0x104F4,
+ 0x104CD => 0x104F5,
+ 0x104CE => 0x104F6,
+ 0x104CF => 0x104F7,
+ 0x104D0 => 0x104F8,
+ 0x104D1 => 0x104F9,
+ 0x104D2 => 0x104FA,
+ 0x104D3 => 0x104FB,
+ 0x10C80 => 0x10CC0,
+ 0x10C81 => 0x10CC1,
+ 0x10C82 => 0x10CC2,
+ 0x10C83 => 0x10CC3,
+ 0x10C84 => 0x10CC4,
+ 0x10C85 => 0x10CC5,
+ 0x10C86 => 0x10CC6,
+ 0x10C87 => 0x10CC7,
+ 0x10C88 => 0x10CC8,
+ 0x10C89 => 0x10CC9,
+ 0x10C8A => 0x10CCA,
+ 0x10C8B => 0x10CCB,
+ 0x10C8C => 0x10CCC,
+ 0x10C8D => 0x10CCD,
+ 0x10C8E => 0x10CCE,
+ 0x10C8F => 0x10CCF,
+ 0x10C90 => 0x10CD0,
+ 0x10C91 => 0x10CD1,
+ 0x10C92 => 0x10CD2,
+ 0x10C93 => 0x10CD3,
+ 0x10C94 => 0x10CD4,
+ 0x10C95 => 0x10CD5,
+ 0x10C96 => 0x10CD6,
+ 0x10C97 => 0x10CD7,
+ 0x10C98 => 0x10CD8,
+ 0x10C99 => 0x10CD9,
+ 0x10C9A => 0x10CDA,
+ 0x10C9B => 0x10CDB,
+ 0x10C9C => 0x10CDC,
+ 0x10C9D => 0x10CDD,
+ 0x10C9E => 0x10CDE,
+ 0x10C9F => 0x10CDF,
+ 0x10CA0 => 0x10CE0,
+ 0x10CA1 => 0x10CE1,
+ 0x10CA2 => 0x10CE2,
+ 0x10CA3 => 0x10CE3,
+ 0x10CA4 => 0x10CE4,
+ 0x10CA5 => 0x10CE5,
+ 0x10CA6 => 0x10CE6,
+ 0x10CA7 => 0x10CE7,
+ 0x10CA8 => 0x10CE8,
+ 0x10CA9 => 0x10CE9,
+ 0x10CAA => 0x10CEA,
+ 0x10CAB => 0x10CEB,
+ 0x10CAC => 0x10CEC,
+ 0x10CAD => 0x10CED,
+ 0x10CAE => 0x10CEE,
+ 0x10CAF => 0x10CEF,
+ 0x10CB0 => 0x10CF0,
+ 0x10CB1 => 0x10CF1,
+ 0x10CB2 => 0x10CF2,
+ 0x118A0 => 0x118C0,
+ 0x118A1 => 0x118C1,
+ 0x118A2 => 0x118C2,
+ 0x118A3 => 0x118C3,
+ 0x118A4 => 0x118C4,
+ 0x118A5 => 0x118C5,
+ 0x118A6 => 0x118C6,
+ 0x118A7 => 0x118C7,
+ 0x118A8 => 0x118C8,
+ 0x118A9 => 0x118C9,
+ 0x118AA => 0x118CA,
+ 0x118AB => 0x118CB,
+ 0x118AC => 0x118CC,
+ 0x118AD => 0x118CD,
+ 0x118AE => 0x118CE,
+ 0x118AF => 0x118CF,
+ 0x118B0 => 0x118D0,
+ 0x118B1 => 0x118D1,
+ 0x118B2 => 0x118D2,
+ 0x118B3 => 0x118D3,
+ 0x118B4 => 0x118D4,
+ 0x118B5 => 0x118D5,
+ 0x118B6 => 0x118D6,
+ 0x118B7 => 0x118D7,
+ 0x118B8 => 0x118D8,
+ 0x118B9 => 0x118D9,
+ 0x118BA => 0x118DA,
+ 0x118BB => 0x118DB,
+ 0x118BC => 0x118DC,
+ 0x118BD => 0x118DD,
+ 0x118BE => 0x118DE,
+ 0x118BF => 0x118DF,
+ 0x16E40 => 0x16E60,
+ 0x16E41 => 0x16E61,
+ 0x16E42 => 0x16E62,
+ 0x16E43 => 0x16E63,
+ 0x16E44 => 0x16E64,
+ 0x16E45 => 0x16E65,
+ 0x16E46 => 0x16E66,
+ 0x16E47 => 0x16E67,
+ 0x16E48 => 0x16E68,
+ 0x16E49 => 0x16E69,
+ 0x16E4A => 0x16E6A,
+ 0x16E4B => 0x16E6B,
+ 0x16E4C => 0x16E6C,
+ 0x16E4D => 0x16E6D,
+ 0x16E4E => 0x16E6E,
+ 0x16E4F => 0x16E6F,
+ 0x16E50 => 0x16E70,
+ 0x16E51 => 0x16E71,
+ 0x16E52 => 0x16E72,
+ 0x16E53 => 0x16E73,
+ 0x16E54 => 0x16E74,
+ 0x16E55 => 0x16E75,
+ 0x16E56 => 0x16E76,
+ 0x16E57 => 0x16E77,
+ 0x16E58 => 0x16E78,
+ 0x16E59 => 0x16E79,
+ 0x16E5A => 0x16E7A,
+ 0x16E5B => 0x16E7B,
+ 0x16E5C => 0x16E7C,
+ 0x16E5D => 0x16E7D,
+ 0x16E5E => 0x16E7E,
+ 0x16E5F => 0x16E7F,
+ 0x1E900 => 0x1E922,
+ 0x1E901 => 0x1E923,
+ 0x1E902 => 0x1E924,
+ 0x1E903 => 0x1E925,
+ 0x1E904 => 0x1E926,
+ 0x1E905 => 0x1E927,
+ 0x1E906 => 0x1E928,
+ 0x1E907 => 0x1E929,
+ 0x1E908 => 0x1E92A,
+ 0x1E909 => 0x1E92B,
+ 0x1E90A => 0x1E92C,
+ 0x1E90B => 0x1E92D,
+ 0x1E90C => 0x1E92E,
+ 0x1E90D => 0x1E92F,
+ 0x1E90E => 0x1E930,
+ 0x1E90F => 0x1E931,
+ 0x1E910 => 0x1E932,
+ 0x1E911 => 0x1E933,
+ 0x1E912 => 0x1E934,
+ 0x1E913 => 0x1E935,
+ 0x1E914 => 0x1E936,
+ 0x1E915 => 0x1E937,
+ 0x1E916 => 0x1E938,
+ 0x1E917 => 0x1E939,
+ 0x1E918 => 0x1E93A,
+ 0x1E919 => 0x1E93B,
+ 0x1E91A => 0x1E93C,
+ 0x1E91B => 0x1E93D,
+ 0x1E91C => 0x1E93E,
+ 0x1E91D => 0x1E93F,
+ 0x1E91E => 0x1E940,
+ 0x1E91F => 0x1E941,
+ 0x1E920 => 0x1E942,
+ 0x1E921 => 0x1E943,
+);
diff --git a/src/opis/string/res/lower.php b/src/opis/string/res/lower.php
index b5697d1d..efe36c2b 100644
--- a/src/opis/string/res/lower.php
+++ b/src/opis/string/res/lower.php
@@ -1,1396 +1,1396 @@
0x61,
-0x42 => 0x62,
-0x43 => 0x63,
-0x44 => 0x64,
-0x45 => 0x65,
-0x46 => 0x66,
-0x47 => 0x67,
-0x48 => 0x68,
-0x49 => 0x69,
-0x4A => 0x6A,
-0x4B => 0x6B,
-0x4C => 0x6C,
-0x4D => 0x6D,
-0x4E => 0x6E,
-0x4F => 0x6F,
-0x50 => 0x70,
-0x51 => 0x71,
-0x52 => 0x72,
-0x53 => 0x73,
-0x54 => 0x74,
-0x55 => 0x75,
-0x56 => 0x76,
-0x57 => 0x77,
-0x58 => 0x78,
-0x59 => 0x79,
-0x5A => 0x7A,
-0xC0 => 0xE0,
-0xC1 => 0xE1,
-0xC2 => 0xE2,
-0xC3 => 0xE3,
-0xC4 => 0xE4,
-0xC5 => 0xE5,
-0xC6 => 0xE6,
-0xC7 => 0xE7,
-0xC8 => 0xE8,
-0xC9 => 0xE9,
-0xCA => 0xEA,
-0xCB => 0xEB,
-0xCC => 0xEC,
-0xCD => 0xED,
-0xCE => 0xEE,
-0xCF => 0xEF,
-0xD0 => 0xF0,
-0xD1 => 0xF1,
-0xD2 => 0xF2,
-0xD3 => 0xF3,
-0xD4 => 0xF4,
-0xD5 => 0xF5,
-0xD6 => 0xF6,
-0xD8 => 0xF8,
-0xD9 => 0xF9,
-0xDA => 0xFA,
-0xDB => 0xFB,
-0xDC => 0xFC,
-0xDD => 0xFD,
-0xDE => 0xFE,
-0x100 => 0x101,
-0x102 => 0x103,
-0x104 => 0x105,
-0x106 => 0x107,
-0x108 => 0x109,
-0x10A => 0x10B,
-0x10C => 0x10D,
-0x10E => 0x10F,
-0x110 => 0x111,
-0x112 => 0x113,
-0x114 => 0x115,
-0x116 => 0x117,
-0x118 => 0x119,
-0x11A => 0x11B,
-0x11C => 0x11D,
-0x11E => 0x11F,
-0x120 => 0x121,
-0x122 => 0x123,
-0x124 => 0x125,
-0x126 => 0x127,
-0x128 => 0x129,
-0x12A => 0x12B,
-0x12C => 0x12D,
-0x12E => 0x12F,
-0x130 => 0x69,
-0x132 => 0x133,
-0x134 => 0x135,
-0x136 => 0x137,
-0x139 => 0x13A,
-0x13B => 0x13C,
-0x13D => 0x13E,
-0x13F => 0x140,
-0x141 => 0x142,
-0x143 => 0x144,
-0x145 => 0x146,
-0x147 => 0x148,
-0x14A => 0x14B,
-0x14C => 0x14D,
-0x14E => 0x14F,
-0x150 => 0x151,
-0x152 => 0x153,
-0x154 => 0x155,
-0x156 => 0x157,
-0x158 => 0x159,
-0x15A => 0x15B,
-0x15C => 0x15D,
-0x15E => 0x15F,
-0x160 => 0x161,
-0x162 => 0x163,
-0x164 => 0x165,
-0x166 => 0x167,
-0x168 => 0x169,
-0x16A => 0x16B,
-0x16C => 0x16D,
-0x16E => 0x16F,
-0x170 => 0x171,
-0x172 => 0x173,
-0x174 => 0x175,
-0x176 => 0x177,
-0x178 => 0xFF,
-0x179 => 0x17A,
-0x17B => 0x17C,
-0x17D => 0x17E,
-0x181 => 0x253,
-0x182 => 0x183,
-0x184 => 0x185,
-0x186 => 0x254,
-0x187 => 0x188,
-0x189 => 0x256,
-0x18A => 0x257,
-0x18B => 0x18C,
-0x18E => 0x1DD,
-0x18F => 0x259,
-0x190 => 0x25B,
-0x191 => 0x192,
-0x193 => 0x260,
-0x194 => 0x263,
-0x196 => 0x269,
-0x197 => 0x268,
-0x198 => 0x199,
-0x19C => 0x26F,
-0x19D => 0x272,
-0x19F => 0x275,
-0x1A0 => 0x1A1,
-0x1A2 => 0x1A3,
-0x1A4 => 0x1A5,
-0x1A6 => 0x280,
-0x1A7 => 0x1A8,
-0x1A9 => 0x283,
-0x1AC => 0x1AD,
-0x1AE => 0x288,
-0x1AF => 0x1B0,
-0x1B1 => 0x28A,
-0x1B2 => 0x28B,
-0x1B3 => 0x1B4,
-0x1B5 => 0x1B6,
-0x1B7 => 0x292,
-0x1B8 => 0x1B9,
-0x1BC => 0x1BD,
-0x1C4 => 0x1C6,
-0x1C5 => 0x1C6,
-0x1C7 => 0x1C9,
-0x1C8 => 0x1C9,
-0x1CA => 0x1CC,
-0x1CB => 0x1CC,
-0x1CD => 0x1CE,
-0x1CF => 0x1D0,
-0x1D1 => 0x1D2,
-0x1D3 => 0x1D4,
-0x1D5 => 0x1D6,
-0x1D7 => 0x1D8,
-0x1D9 => 0x1DA,
-0x1DB => 0x1DC,
-0x1DE => 0x1DF,
-0x1E0 => 0x1E1,
-0x1E2 => 0x1E3,
-0x1E4 => 0x1E5,
-0x1E6 => 0x1E7,
-0x1E8 => 0x1E9,
-0x1EA => 0x1EB,
-0x1EC => 0x1ED,
-0x1EE => 0x1EF,
-0x1F1 => 0x1F3,
-0x1F2 => 0x1F3,
-0x1F4 => 0x1F5,
-0x1F6 => 0x195,
-0x1F7 => 0x1BF,
-0x1F8 => 0x1F9,
-0x1FA => 0x1FB,
-0x1FC => 0x1FD,
-0x1FE => 0x1FF,
-0x200 => 0x201,
-0x202 => 0x203,
-0x204 => 0x205,
-0x206 => 0x207,
-0x208 => 0x209,
-0x20A => 0x20B,
-0x20C => 0x20D,
-0x20E => 0x20F,
-0x210 => 0x211,
-0x212 => 0x213,
-0x214 => 0x215,
-0x216 => 0x217,
-0x218 => 0x219,
-0x21A => 0x21B,
-0x21C => 0x21D,
-0x21E => 0x21F,
-0x220 => 0x19E,
-0x222 => 0x223,
-0x224 => 0x225,
-0x226 => 0x227,
-0x228 => 0x229,
-0x22A => 0x22B,
-0x22C => 0x22D,
-0x22E => 0x22F,
-0x230 => 0x231,
-0x232 => 0x233,
-0x23A => 0x2C65,
-0x23B => 0x23C,
-0x23D => 0x19A,
-0x23E => 0x2C66,
-0x241 => 0x242,
-0x243 => 0x180,
-0x244 => 0x289,
-0x245 => 0x28C,
-0x246 => 0x247,
-0x248 => 0x249,
-0x24A => 0x24B,
-0x24C => 0x24D,
-0x24E => 0x24F,
-0x370 => 0x371,
-0x372 => 0x373,
-0x376 => 0x377,
-0x37F => 0x3F3,
-0x386 => 0x3AC,
-0x388 => 0x3AD,
-0x389 => 0x3AE,
-0x38A => 0x3AF,
-0x38C => 0x3CC,
-0x38E => 0x3CD,
-0x38F => 0x3CE,
-0x391 => 0x3B1,
-0x392 => 0x3B2,
-0x393 => 0x3B3,
-0x394 => 0x3B4,
-0x395 => 0x3B5,
-0x396 => 0x3B6,
-0x397 => 0x3B7,
-0x398 => 0x3B8,
-0x399 => 0x3B9,
-0x39A => 0x3BA,
-0x39B => 0x3BB,
-0x39C => 0x3BC,
-0x39D => 0x3BD,
-0x39E => 0x3BE,
-0x39F => 0x3BF,
-0x3A0 => 0x3C0,
-0x3A1 => 0x3C1,
-0x3A3 => 0x3C3,
-0x3A4 => 0x3C4,
-0x3A5 => 0x3C5,
-0x3A6 => 0x3C6,
-0x3A7 => 0x3C7,
-0x3A8 => 0x3C8,
-0x3A9 => 0x3C9,
-0x3AA => 0x3CA,
-0x3AB => 0x3CB,
-0x3CF => 0x3D7,
-0x3D8 => 0x3D9,
-0x3DA => 0x3DB,
-0x3DC => 0x3DD,
-0x3DE => 0x3DF,
-0x3E0 => 0x3E1,
-0x3E2 => 0x3E3,
-0x3E4 => 0x3E5,
-0x3E6 => 0x3E7,
-0x3E8 => 0x3E9,
-0x3EA => 0x3EB,
-0x3EC => 0x3ED,
-0x3EE => 0x3EF,
-0x3F4 => 0x3B8,
-0x3F7 => 0x3F8,
-0x3F9 => 0x3F2,
-0x3FA => 0x3FB,
-0x3FD => 0x37B,
-0x3FE => 0x37C,
-0x3FF => 0x37D,
-0x400 => 0x450,
-0x401 => 0x451,
-0x402 => 0x452,
-0x403 => 0x453,
-0x404 => 0x454,
-0x405 => 0x455,
-0x406 => 0x456,
-0x407 => 0x457,
-0x408 => 0x458,
-0x409 => 0x459,
-0x40A => 0x45A,
-0x40B => 0x45B,
-0x40C => 0x45C,
-0x40D => 0x45D,
-0x40E => 0x45E,
-0x40F => 0x45F,
-0x410 => 0x430,
-0x411 => 0x431,
-0x412 => 0x432,
-0x413 => 0x433,
-0x414 => 0x434,
-0x415 => 0x435,
-0x416 => 0x436,
-0x417 => 0x437,
-0x418 => 0x438,
-0x419 => 0x439,
-0x41A => 0x43A,
-0x41B => 0x43B,
-0x41C => 0x43C,
-0x41D => 0x43D,
-0x41E => 0x43E,
-0x41F => 0x43F,
-0x420 => 0x440,
-0x421 => 0x441,
-0x422 => 0x442,
-0x423 => 0x443,
-0x424 => 0x444,
-0x425 => 0x445,
-0x426 => 0x446,
-0x427 => 0x447,
-0x428 => 0x448,
-0x429 => 0x449,
-0x42A => 0x44A,
-0x42B => 0x44B,
-0x42C => 0x44C,
-0x42D => 0x44D,
-0x42E => 0x44E,
-0x42F => 0x44F,
-0x460 => 0x461,
-0x462 => 0x463,
-0x464 => 0x465,
-0x466 => 0x467,
-0x468 => 0x469,
-0x46A => 0x46B,
-0x46C => 0x46D,
-0x46E => 0x46F,
-0x470 => 0x471,
-0x472 => 0x473,
-0x474 => 0x475,
-0x476 => 0x477,
-0x478 => 0x479,
-0x47A => 0x47B,
-0x47C => 0x47D,
-0x47E => 0x47F,
-0x480 => 0x481,
-0x48A => 0x48B,
-0x48C => 0x48D,
-0x48E => 0x48F,
-0x490 => 0x491,
-0x492 => 0x493,
-0x494 => 0x495,
-0x496 => 0x497,
-0x498 => 0x499,
-0x49A => 0x49B,
-0x49C => 0x49D,
-0x49E => 0x49F,
-0x4A0 => 0x4A1,
-0x4A2 => 0x4A3,
-0x4A4 => 0x4A5,
-0x4A6 => 0x4A7,
-0x4A8 => 0x4A9,
-0x4AA => 0x4AB,
-0x4AC => 0x4AD,
-0x4AE => 0x4AF,
-0x4B0 => 0x4B1,
-0x4B2 => 0x4B3,
-0x4B4 => 0x4B5,
-0x4B6 => 0x4B7,
-0x4B8 => 0x4B9,
-0x4BA => 0x4BB,
-0x4BC => 0x4BD,
-0x4BE => 0x4BF,
-0x4C0 => 0x4CF,
-0x4C1 => 0x4C2,
-0x4C3 => 0x4C4,
-0x4C5 => 0x4C6,
-0x4C7 => 0x4C8,
-0x4C9 => 0x4CA,
-0x4CB => 0x4CC,
-0x4CD => 0x4CE,
-0x4D0 => 0x4D1,
-0x4D2 => 0x4D3,
-0x4D4 => 0x4D5,
-0x4D6 => 0x4D7,
-0x4D8 => 0x4D9,
-0x4DA => 0x4DB,
-0x4DC => 0x4DD,
-0x4DE => 0x4DF,
-0x4E0 => 0x4E1,
-0x4E2 => 0x4E3,
-0x4E4 => 0x4E5,
-0x4E6 => 0x4E7,
-0x4E8 => 0x4E9,
-0x4EA => 0x4EB,
-0x4EC => 0x4ED,
-0x4EE => 0x4EF,
-0x4F0 => 0x4F1,
-0x4F2 => 0x4F3,
-0x4F4 => 0x4F5,
-0x4F6 => 0x4F7,
-0x4F8 => 0x4F9,
-0x4FA => 0x4FB,
-0x4FC => 0x4FD,
-0x4FE => 0x4FF,
-0x500 => 0x501,
-0x502 => 0x503,
-0x504 => 0x505,
-0x506 => 0x507,
-0x508 => 0x509,
-0x50A => 0x50B,
-0x50C => 0x50D,
-0x50E => 0x50F,
-0x510 => 0x511,
-0x512 => 0x513,
-0x514 => 0x515,
-0x516 => 0x517,
-0x518 => 0x519,
-0x51A => 0x51B,
-0x51C => 0x51D,
-0x51E => 0x51F,
-0x520 => 0x521,
-0x522 => 0x523,
-0x524 => 0x525,
-0x526 => 0x527,
-0x528 => 0x529,
-0x52A => 0x52B,
-0x52C => 0x52D,
-0x52E => 0x52F,
-0x531 => 0x561,
-0x532 => 0x562,
-0x533 => 0x563,
-0x534 => 0x564,
-0x535 => 0x565,
-0x536 => 0x566,
-0x537 => 0x567,
-0x538 => 0x568,
-0x539 => 0x569,
-0x53A => 0x56A,
-0x53B => 0x56B,
-0x53C => 0x56C,
-0x53D => 0x56D,
-0x53E => 0x56E,
-0x53F => 0x56F,
-0x540 => 0x570,
-0x541 => 0x571,
-0x542 => 0x572,
-0x543 => 0x573,
-0x544 => 0x574,
-0x545 => 0x575,
-0x546 => 0x576,
-0x547 => 0x577,
-0x548 => 0x578,
-0x549 => 0x579,
-0x54A => 0x57A,
-0x54B => 0x57B,
-0x54C => 0x57C,
-0x54D => 0x57D,
-0x54E => 0x57E,
-0x54F => 0x57F,
-0x550 => 0x580,
-0x551 => 0x581,
-0x552 => 0x582,
-0x553 => 0x583,
-0x554 => 0x584,
-0x555 => 0x585,
-0x556 => 0x586,
-0x10A0 => 0x2D00,
-0x10A1 => 0x2D01,
-0x10A2 => 0x2D02,
-0x10A3 => 0x2D03,
-0x10A4 => 0x2D04,
-0x10A5 => 0x2D05,
-0x10A6 => 0x2D06,
-0x10A7 => 0x2D07,
-0x10A8 => 0x2D08,
-0x10A9 => 0x2D09,
-0x10AA => 0x2D0A,
-0x10AB => 0x2D0B,
-0x10AC => 0x2D0C,
-0x10AD => 0x2D0D,
-0x10AE => 0x2D0E,
-0x10AF => 0x2D0F,
-0x10B0 => 0x2D10,
-0x10B1 => 0x2D11,
-0x10B2 => 0x2D12,
-0x10B3 => 0x2D13,
-0x10B4 => 0x2D14,
-0x10B5 => 0x2D15,
-0x10B6 => 0x2D16,
-0x10B7 => 0x2D17,
-0x10B8 => 0x2D18,
-0x10B9 => 0x2D19,
-0x10BA => 0x2D1A,
-0x10BB => 0x2D1B,
-0x10BC => 0x2D1C,
-0x10BD => 0x2D1D,
-0x10BE => 0x2D1E,
-0x10BF => 0x2D1F,
-0x10C0 => 0x2D20,
-0x10C1 => 0x2D21,
-0x10C2 => 0x2D22,
-0x10C3 => 0x2D23,
-0x10C4 => 0x2D24,
-0x10C5 => 0x2D25,
-0x10C7 => 0x2D27,
-0x10CD => 0x2D2D,
-0x13A0 => 0xAB70,
-0x13A1 => 0xAB71,
-0x13A2 => 0xAB72,
-0x13A3 => 0xAB73,
-0x13A4 => 0xAB74,
-0x13A5 => 0xAB75,
-0x13A6 => 0xAB76,
-0x13A7 => 0xAB77,
-0x13A8 => 0xAB78,
-0x13A9 => 0xAB79,
-0x13AA => 0xAB7A,
-0x13AB => 0xAB7B,
-0x13AC => 0xAB7C,
-0x13AD => 0xAB7D,
-0x13AE => 0xAB7E,
-0x13AF => 0xAB7F,
-0x13B0 => 0xAB80,
-0x13B1 => 0xAB81,
-0x13B2 => 0xAB82,
-0x13B3 => 0xAB83,
-0x13B4 => 0xAB84,
-0x13B5 => 0xAB85,
-0x13B6 => 0xAB86,
-0x13B7 => 0xAB87,
-0x13B8 => 0xAB88,
-0x13B9 => 0xAB89,
-0x13BA => 0xAB8A,
-0x13BB => 0xAB8B,
-0x13BC => 0xAB8C,
-0x13BD => 0xAB8D,
-0x13BE => 0xAB8E,
-0x13BF => 0xAB8F,
-0x13C0 => 0xAB90,
-0x13C1 => 0xAB91,
-0x13C2 => 0xAB92,
-0x13C3 => 0xAB93,
-0x13C4 => 0xAB94,
-0x13C5 => 0xAB95,
-0x13C6 => 0xAB96,
-0x13C7 => 0xAB97,
-0x13C8 => 0xAB98,
-0x13C9 => 0xAB99,
-0x13CA => 0xAB9A,
-0x13CB => 0xAB9B,
-0x13CC => 0xAB9C,
-0x13CD => 0xAB9D,
-0x13CE => 0xAB9E,
-0x13CF => 0xAB9F,
-0x13D0 => 0xABA0,
-0x13D1 => 0xABA1,
-0x13D2 => 0xABA2,
-0x13D3 => 0xABA3,
-0x13D4 => 0xABA4,
-0x13D5 => 0xABA5,
-0x13D6 => 0xABA6,
-0x13D7 => 0xABA7,
-0x13D8 => 0xABA8,
-0x13D9 => 0xABA9,
-0x13DA => 0xABAA,
-0x13DB => 0xABAB,
-0x13DC => 0xABAC,
-0x13DD => 0xABAD,
-0x13DE => 0xABAE,
-0x13DF => 0xABAF,
-0x13E0 => 0xABB0,
-0x13E1 => 0xABB1,
-0x13E2 => 0xABB2,
-0x13E3 => 0xABB3,
-0x13E4 => 0xABB4,
-0x13E5 => 0xABB5,
-0x13E6 => 0xABB6,
-0x13E7 => 0xABB7,
-0x13E8 => 0xABB8,
-0x13E9 => 0xABB9,
-0x13EA => 0xABBA,
-0x13EB => 0xABBB,
-0x13EC => 0xABBC,
-0x13ED => 0xABBD,
-0x13EE => 0xABBE,
-0x13EF => 0xABBF,
-0x13F0 => 0x13F8,
-0x13F1 => 0x13F9,
-0x13F2 => 0x13FA,
-0x13F3 => 0x13FB,
-0x13F4 => 0x13FC,
-0x13F5 => 0x13FD,
-0x1C90 => 0x10D0,
-0x1C91 => 0x10D1,
-0x1C92 => 0x10D2,
-0x1C93 => 0x10D3,
-0x1C94 => 0x10D4,
-0x1C95 => 0x10D5,
-0x1C96 => 0x10D6,
-0x1C97 => 0x10D7,
-0x1C98 => 0x10D8,
-0x1C99 => 0x10D9,
-0x1C9A => 0x10DA,
-0x1C9B => 0x10DB,
-0x1C9C => 0x10DC,
-0x1C9D => 0x10DD,
-0x1C9E => 0x10DE,
-0x1C9F => 0x10DF,
-0x1CA0 => 0x10E0,
-0x1CA1 => 0x10E1,
-0x1CA2 => 0x10E2,
-0x1CA3 => 0x10E3,
-0x1CA4 => 0x10E4,
-0x1CA5 => 0x10E5,
-0x1CA6 => 0x10E6,
-0x1CA7 => 0x10E7,
-0x1CA8 => 0x10E8,
-0x1CA9 => 0x10E9,
-0x1CAA => 0x10EA,
-0x1CAB => 0x10EB,
-0x1CAC => 0x10EC,
-0x1CAD => 0x10ED,
-0x1CAE => 0x10EE,
-0x1CAF => 0x10EF,
-0x1CB0 => 0x10F0,
-0x1CB1 => 0x10F1,
-0x1CB2 => 0x10F2,
-0x1CB3 => 0x10F3,
-0x1CB4 => 0x10F4,
-0x1CB5 => 0x10F5,
-0x1CB6 => 0x10F6,
-0x1CB7 => 0x10F7,
-0x1CB8 => 0x10F8,
-0x1CB9 => 0x10F9,
-0x1CBA => 0x10FA,
-0x1CBD => 0x10FD,
-0x1CBE => 0x10FE,
-0x1CBF => 0x10FF,
-0x1E00 => 0x1E01,
-0x1E02 => 0x1E03,
-0x1E04 => 0x1E05,
-0x1E06 => 0x1E07,
-0x1E08 => 0x1E09,
-0x1E0A => 0x1E0B,
-0x1E0C => 0x1E0D,
-0x1E0E => 0x1E0F,
-0x1E10 => 0x1E11,
-0x1E12 => 0x1E13,
-0x1E14 => 0x1E15,
-0x1E16 => 0x1E17,
-0x1E18 => 0x1E19,
-0x1E1A => 0x1E1B,
-0x1E1C => 0x1E1D,
-0x1E1E => 0x1E1F,
-0x1E20 => 0x1E21,
-0x1E22 => 0x1E23,
-0x1E24 => 0x1E25,
-0x1E26 => 0x1E27,
-0x1E28 => 0x1E29,
-0x1E2A => 0x1E2B,
-0x1E2C => 0x1E2D,
-0x1E2E => 0x1E2F,
-0x1E30 => 0x1E31,
-0x1E32 => 0x1E33,
-0x1E34 => 0x1E35,
-0x1E36 => 0x1E37,
-0x1E38 => 0x1E39,
-0x1E3A => 0x1E3B,
-0x1E3C => 0x1E3D,
-0x1E3E => 0x1E3F,
-0x1E40 => 0x1E41,
-0x1E42 => 0x1E43,
-0x1E44 => 0x1E45,
-0x1E46 => 0x1E47,
-0x1E48 => 0x1E49,
-0x1E4A => 0x1E4B,
-0x1E4C => 0x1E4D,
-0x1E4E => 0x1E4F,
-0x1E50 => 0x1E51,
-0x1E52 => 0x1E53,
-0x1E54 => 0x1E55,
-0x1E56 => 0x1E57,
-0x1E58 => 0x1E59,
-0x1E5A => 0x1E5B,
-0x1E5C => 0x1E5D,
-0x1E5E => 0x1E5F,
-0x1E60 => 0x1E61,
-0x1E62 => 0x1E63,
-0x1E64 => 0x1E65,
-0x1E66 => 0x1E67,
-0x1E68 => 0x1E69,
-0x1E6A => 0x1E6B,
-0x1E6C => 0x1E6D,
-0x1E6E => 0x1E6F,
-0x1E70 => 0x1E71,
-0x1E72 => 0x1E73,
-0x1E74 => 0x1E75,
-0x1E76 => 0x1E77,
-0x1E78 => 0x1E79,
-0x1E7A => 0x1E7B,
-0x1E7C => 0x1E7D,
-0x1E7E => 0x1E7F,
-0x1E80 => 0x1E81,
-0x1E82 => 0x1E83,
-0x1E84 => 0x1E85,
-0x1E86 => 0x1E87,
-0x1E88 => 0x1E89,
-0x1E8A => 0x1E8B,
-0x1E8C => 0x1E8D,
-0x1E8E => 0x1E8F,
-0x1E90 => 0x1E91,
-0x1E92 => 0x1E93,
-0x1E94 => 0x1E95,
-0x1E9E => 0xDF,
-0x1EA0 => 0x1EA1,
-0x1EA2 => 0x1EA3,
-0x1EA4 => 0x1EA5,
-0x1EA6 => 0x1EA7,
-0x1EA8 => 0x1EA9,
-0x1EAA => 0x1EAB,
-0x1EAC => 0x1EAD,
-0x1EAE => 0x1EAF,
-0x1EB0 => 0x1EB1,
-0x1EB2 => 0x1EB3,
-0x1EB4 => 0x1EB5,
-0x1EB6 => 0x1EB7,
-0x1EB8 => 0x1EB9,
-0x1EBA => 0x1EBB,
-0x1EBC => 0x1EBD,
-0x1EBE => 0x1EBF,
-0x1EC0 => 0x1EC1,
-0x1EC2 => 0x1EC3,
-0x1EC4 => 0x1EC5,
-0x1EC6 => 0x1EC7,
-0x1EC8 => 0x1EC9,
-0x1ECA => 0x1ECB,
-0x1ECC => 0x1ECD,
-0x1ECE => 0x1ECF,
-0x1ED0 => 0x1ED1,
-0x1ED2 => 0x1ED3,
-0x1ED4 => 0x1ED5,
-0x1ED6 => 0x1ED7,
-0x1ED8 => 0x1ED9,
-0x1EDA => 0x1EDB,
-0x1EDC => 0x1EDD,
-0x1EDE => 0x1EDF,
-0x1EE0 => 0x1EE1,
-0x1EE2 => 0x1EE3,
-0x1EE4 => 0x1EE5,
-0x1EE6 => 0x1EE7,
-0x1EE8 => 0x1EE9,
-0x1EEA => 0x1EEB,
-0x1EEC => 0x1EED,
-0x1EEE => 0x1EEF,
-0x1EF0 => 0x1EF1,
-0x1EF2 => 0x1EF3,
-0x1EF4 => 0x1EF5,
-0x1EF6 => 0x1EF7,
-0x1EF8 => 0x1EF9,
-0x1EFA => 0x1EFB,
-0x1EFC => 0x1EFD,
-0x1EFE => 0x1EFF,
-0x1F08 => 0x1F00,
-0x1F09 => 0x1F01,
-0x1F0A => 0x1F02,
-0x1F0B => 0x1F03,
-0x1F0C => 0x1F04,
-0x1F0D => 0x1F05,
-0x1F0E => 0x1F06,
-0x1F0F => 0x1F07,
-0x1F18 => 0x1F10,
-0x1F19 => 0x1F11,
-0x1F1A => 0x1F12,
-0x1F1B => 0x1F13,
-0x1F1C => 0x1F14,
-0x1F1D => 0x1F15,
-0x1F28 => 0x1F20,
-0x1F29 => 0x1F21,
-0x1F2A => 0x1F22,
-0x1F2B => 0x1F23,
-0x1F2C => 0x1F24,
-0x1F2D => 0x1F25,
-0x1F2E => 0x1F26,
-0x1F2F => 0x1F27,
-0x1F38 => 0x1F30,
-0x1F39 => 0x1F31,
-0x1F3A => 0x1F32,
-0x1F3B => 0x1F33,
-0x1F3C => 0x1F34,
-0x1F3D => 0x1F35,
-0x1F3E => 0x1F36,
-0x1F3F => 0x1F37,
-0x1F48 => 0x1F40,
-0x1F49 => 0x1F41,
-0x1F4A => 0x1F42,
-0x1F4B => 0x1F43,
-0x1F4C => 0x1F44,
-0x1F4D => 0x1F45,
-0x1F59 => 0x1F51,
-0x1F5B => 0x1F53,
-0x1F5D => 0x1F55,
-0x1F5F => 0x1F57,
-0x1F68 => 0x1F60,
-0x1F69 => 0x1F61,
-0x1F6A => 0x1F62,
-0x1F6B => 0x1F63,
-0x1F6C => 0x1F64,
-0x1F6D => 0x1F65,
-0x1F6E => 0x1F66,
-0x1F6F => 0x1F67,
-0x1F88 => 0x1F80,
-0x1F89 => 0x1F81,
-0x1F8A => 0x1F82,
-0x1F8B => 0x1F83,
-0x1F8C => 0x1F84,
-0x1F8D => 0x1F85,
-0x1F8E => 0x1F86,
-0x1F8F => 0x1F87,
-0x1F98 => 0x1F90,
-0x1F99 => 0x1F91,
-0x1F9A => 0x1F92,
-0x1F9B => 0x1F93,
-0x1F9C => 0x1F94,
-0x1F9D => 0x1F95,
-0x1F9E => 0x1F96,
-0x1F9F => 0x1F97,
-0x1FA8 => 0x1FA0,
-0x1FA9 => 0x1FA1,
-0x1FAA => 0x1FA2,
-0x1FAB => 0x1FA3,
-0x1FAC => 0x1FA4,
-0x1FAD => 0x1FA5,
-0x1FAE => 0x1FA6,
-0x1FAF => 0x1FA7,
-0x1FB8 => 0x1FB0,
-0x1FB9 => 0x1FB1,
-0x1FBA => 0x1F70,
-0x1FBB => 0x1F71,
-0x1FBC => 0x1FB3,
-0x1FC8 => 0x1F72,
-0x1FC9 => 0x1F73,
-0x1FCA => 0x1F74,
-0x1FCB => 0x1F75,
-0x1FCC => 0x1FC3,
-0x1FD8 => 0x1FD0,
-0x1FD9 => 0x1FD1,
-0x1FDA => 0x1F76,
-0x1FDB => 0x1F77,
-0x1FE8 => 0x1FE0,
-0x1FE9 => 0x1FE1,
-0x1FEA => 0x1F7A,
-0x1FEB => 0x1F7B,
-0x1FEC => 0x1FE5,
-0x1FF8 => 0x1F78,
-0x1FF9 => 0x1F79,
-0x1FFA => 0x1F7C,
-0x1FFB => 0x1F7D,
-0x1FFC => 0x1FF3,
-0x2126 => 0x3C9,
-0x212A => 0x6B,
-0x212B => 0xE5,
-0x2132 => 0x214E,
-0x2160 => 0x2170,
-0x2161 => 0x2171,
-0x2162 => 0x2172,
-0x2163 => 0x2173,
-0x2164 => 0x2174,
-0x2165 => 0x2175,
-0x2166 => 0x2176,
-0x2167 => 0x2177,
-0x2168 => 0x2178,
-0x2169 => 0x2179,
-0x216A => 0x217A,
-0x216B => 0x217B,
-0x216C => 0x217C,
-0x216D => 0x217D,
-0x216E => 0x217E,
-0x216F => 0x217F,
-0x2183 => 0x2184,
-0x24B6 => 0x24D0,
-0x24B7 => 0x24D1,
-0x24B8 => 0x24D2,
-0x24B9 => 0x24D3,
-0x24BA => 0x24D4,
-0x24BB => 0x24D5,
-0x24BC => 0x24D6,
-0x24BD => 0x24D7,
-0x24BE => 0x24D8,
-0x24BF => 0x24D9,
-0x24C0 => 0x24DA,
-0x24C1 => 0x24DB,
-0x24C2 => 0x24DC,
-0x24C3 => 0x24DD,
-0x24C4 => 0x24DE,
-0x24C5 => 0x24DF,
-0x24C6 => 0x24E0,
-0x24C7 => 0x24E1,
-0x24C8 => 0x24E2,
-0x24C9 => 0x24E3,
-0x24CA => 0x24E4,
-0x24CB => 0x24E5,
-0x24CC => 0x24E6,
-0x24CD => 0x24E7,
-0x24CE => 0x24E8,
-0x24CF => 0x24E9,
-0x2C00 => 0x2C30,
-0x2C01 => 0x2C31,
-0x2C02 => 0x2C32,
-0x2C03 => 0x2C33,
-0x2C04 => 0x2C34,
-0x2C05 => 0x2C35,
-0x2C06 => 0x2C36,
-0x2C07 => 0x2C37,
-0x2C08 => 0x2C38,
-0x2C09 => 0x2C39,
-0x2C0A => 0x2C3A,
-0x2C0B => 0x2C3B,
-0x2C0C => 0x2C3C,
-0x2C0D => 0x2C3D,
-0x2C0E => 0x2C3E,
-0x2C0F => 0x2C3F,
-0x2C10 => 0x2C40,
-0x2C11 => 0x2C41,
-0x2C12 => 0x2C42,
-0x2C13 => 0x2C43,
-0x2C14 => 0x2C44,
-0x2C15 => 0x2C45,
-0x2C16 => 0x2C46,
-0x2C17 => 0x2C47,
-0x2C18 => 0x2C48,
-0x2C19 => 0x2C49,
-0x2C1A => 0x2C4A,
-0x2C1B => 0x2C4B,
-0x2C1C => 0x2C4C,
-0x2C1D => 0x2C4D,
-0x2C1E => 0x2C4E,
-0x2C1F => 0x2C4F,
-0x2C20 => 0x2C50,
-0x2C21 => 0x2C51,
-0x2C22 => 0x2C52,
-0x2C23 => 0x2C53,
-0x2C24 => 0x2C54,
-0x2C25 => 0x2C55,
-0x2C26 => 0x2C56,
-0x2C27 => 0x2C57,
-0x2C28 => 0x2C58,
-0x2C29 => 0x2C59,
-0x2C2A => 0x2C5A,
-0x2C2B => 0x2C5B,
-0x2C2C => 0x2C5C,
-0x2C2D => 0x2C5D,
-0x2C2E => 0x2C5E,
-0x2C60 => 0x2C61,
-0x2C62 => 0x26B,
-0x2C63 => 0x1D7D,
-0x2C64 => 0x27D,
-0x2C67 => 0x2C68,
-0x2C69 => 0x2C6A,
-0x2C6B => 0x2C6C,
-0x2C6D => 0x251,
-0x2C6E => 0x271,
-0x2C6F => 0x250,
-0x2C70 => 0x252,
-0x2C72 => 0x2C73,
-0x2C75 => 0x2C76,
-0x2C7E => 0x23F,
-0x2C7F => 0x240,
-0x2C80 => 0x2C81,
-0x2C82 => 0x2C83,
-0x2C84 => 0x2C85,
-0x2C86 => 0x2C87,
-0x2C88 => 0x2C89,
-0x2C8A => 0x2C8B,
-0x2C8C => 0x2C8D,
-0x2C8E => 0x2C8F,
-0x2C90 => 0x2C91,
-0x2C92 => 0x2C93,
-0x2C94 => 0x2C95,
-0x2C96 => 0x2C97,
-0x2C98 => 0x2C99,
-0x2C9A => 0x2C9B,
-0x2C9C => 0x2C9D,
-0x2C9E => 0x2C9F,
-0x2CA0 => 0x2CA1,
-0x2CA2 => 0x2CA3,
-0x2CA4 => 0x2CA5,
-0x2CA6 => 0x2CA7,
-0x2CA8 => 0x2CA9,
-0x2CAA => 0x2CAB,
-0x2CAC => 0x2CAD,
-0x2CAE => 0x2CAF,
-0x2CB0 => 0x2CB1,
-0x2CB2 => 0x2CB3,
-0x2CB4 => 0x2CB5,
-0x2CB6 => 0x2CB7,
-0x2CB8 => 0x2CB9,
-0x2CBA => 0x2CBB,
-0x2CBC => 0x2CBD,
-0x2CBE => 0x2CBF,
-0x2CC0 => 0x2CC1,
-0x2CC2 => 0x2CC3,
-0x2CC4 => 0x2CC5,
-0x2CC6 => 0x2CC7,
-0x2CC8 => 0x2CC9,
-0x2CCA => 0x2CCB,
-0x2CCC => 0x2CCD,
-0x2CCE => 0x2CCF,
-0x2CD0 => 0x2CD1,
-0x2CD2 => 0x2CD3,
-0x2CD4 => 0x2CD5,
-0x2CD6 => 0x2CD7,
-0x2CD8 => 0x2CD9,
-0x2CDA => 0x2CDB,
-0x2CDC => 0x2CDD,
-0x2CDE => 0x2CDF,
-0x2CE0 => 0x2CE1,
-0x2CE2 => 0x2CE3,
-0x2CEB => 0x2CEC,
-0x2CED => 0x2CEE,
-0x2CF2 => 0x2CF3,
-0xA640 => 0xA641,
-0xA642 => 0xA643,
-0xA644 => 0xA645,
-0xA646 => 0xA647,
-0xA648 => 0xA649,
-0xA64A => 0xA64B,
-0xA64C => 0xA64D,
-0xA64E => 0xA64F,
-0xA650 => 0xA651,
-0xA652 => 0xA653,
-0xA654 => 0xA655,
-0xA656 => 0xA657,
-0xA658 => 0xA659,
-0xA65A => 0xA65B,
-0xA65C => 0xA65D,
-0xA65E => 0xA65F,
-0xA660 => 0xA661,
-0xA662 => 0xA663,
-0xA664 => 0xA665,
-0xA666 => 0xA667,
-0xA668 => 0xA669,
-0xA66A => 0xA66B,
-0xA66C => 0xA66D,
-0xA680 => 0xA681,
-0xA682 => 0xA683,
-0xA684 => 0xA685,
-0xA686 => 0xA687,
-0xA688 => 0xA689,
-0xA68A => 0xA68B,
-0xA68C => 0xA68D,
-0xA68E => 0xA68F,
-0xA690 => 0xA691,
-0xA692 => 0xA693,
-0xA694 => 0xA695,
-0xA696 => 0xA697,
-0xA698 => 0xA699,
-0xA69A => 0xA69B,
-0xA722 => 0xA723,
-0xA724 => 0xA725,
-0xA726 => 0xA727,
-0xA728 => 0xA729,
-0xA72A => 0xA72B,
-0xA72C => 0xA72D,
-0xA72E => 0xA72F,
-0xA732 => 0xA733,
-0xA734 => 0xA735,
-0xA736 => 0xA737,
-0xA738 => 0xA739,
-0xA73A => 0xA73B,
-0xA73C => 0xA73D,
-0xA73E => 0xA73F,
-0xA740 => 0xA741,
-0xA742 => 0xA743,
-0xA744 => 0xA745,
-0xA746 => 0xA747,
-0xA748 => 0xA749,
-0xA74A => 0xA74B,
-0xA74C => 0xA74D,
-0xA74E => 0xA74F,
-0xA750 => 0xA751,
-0xA752 => 0xA753,
-0xA754 => 0xA755,
-0xA756 => 0xA757,
-0xA758 => 0xA759,
-0xA75A => 0xA75B,
-0xA75C => 0xA75D,
-0xA75E => 0xA75F,
-0xA760 => 0xA761,
-0xA762 => 0xA763,
-0xA764 => 0xA765,
-0xA766 => 0xA767,
-0xA768 => 0xA769,
-0xA76A => 0xA76B,
-0xA76C => 0xA76D,
-0xA76E => 0xA76F,
-0xA779 => 0xA77A,
-0xA77B => 0xA77C,
-0xA77D => 0x1D79,
-0xA77E => 0xA77F,
-0xA780 => 0xA781,
-0xA782 => 0xA783,
-0xA784 => 0xA785,
-0xA786 => 0xA787,
-0xA78B => 0xA78C,
-0xA78D => 0x265,
-0xA790 => 0xA791,
-0xA792 => 0xA793,
-0xA796 => 0xA797,
-0xA798 => 0xA799,
-0xA79A => 0xA79B,
-0xA79C => 0xA79D,
-0xA79E => 0xA79F,
-0xA7A0 => 0xA7A1,
-0xA7A2 => 0xA7A3,
-0xA7A4 => 0xA7A5,
-0xA7A6 => 0xA7A7,
-0xA7A8 => 0xA7A9,
-0xA7AA => 0x266,
-0xA7AB => 0x25C,
-0xA7AC => 0x261,
-0xA7AD => 0x26C,
-0xA7AE => 0x26A,
-0xA7B0 => 0x29E,
-0xA7B1 => 0x287,
-0xA7B2 => 0x29D,
-0xA7B3 => 0xAB53,
-0xA7B4 => 0xA7B5,
-0xA7B6 => 0xA7B7,
-0xA7B8 => 0xA7B9,
-0xA7BA => 0xA7BB,
-0xA7BC => 0xA7BD,
-0xA7BE => 0xA7BF,
-0xA7C2 => 0xA7C3,
-0xA7C4 => 0xA794,
-0xA7C5 => 0x282,
-0xA7C6 => 0x1D8E,
-0xA7C7 => 0xA7C8,
-0xA7C9 => 0xA7CA,
-0xA7F5 => 0xA7F6,
-0xFF21 => 0xFF41,
-0xFF22 => 0xFF42,
-0xFF23 => 0xFF43,
-0xFF24 => 0xFF44,
-0xFF25 => 0xFF45,
-0xFF26 => 0xFF46,
-0xFF27 => 0xFF47,
-0xFF28 => 0xFF48,
-0xFF29 => 0xFF49,
-0xFF2A => 0xFF4A,
-0xFF2B => 0xFF4B,
-0xFF2C => 0xFF4C,
-0xFF2D => 0xFF4D,
-0xFF2E => 0xFF4E,
-0xFF2F => 0xFF4F,
-0xFF30 => 0xFF50,
-0xFF31 => 0xFF51,
-0xFF32 => 0xFF52,
-0xFF33 => 0xFF53,
-0xFF34 => 0xFF54,
-0xFF35 => 0xFF55,
-0xFF36 => 0xFF56,
-0xFF37 => 0xFF57,
-0xFF38 => 0xFF58,
-0xFF39 => 0xFF59,
-0xFF3A => 0xFF5A,
-0x10400 => 0x10428,
-0x10401 => 0x10429,
-0x10402 => 0x1042A,
-0x10403 => 0x1042B,
-0x10404 => 0x1042C,
-0x10405 => 0x1042D,
-0x10406 => 0x1042E,
-0x10407 => 0x1042F,
-0x10408 => 0x10430,
-0x10409 => 0x10431,
-0x1040A => 0x10432,
-0x1040B => 0x10433,
-0x1040C => 0x10434,
-0x1040D => 0x10435,
-0x1040E => 0x10436,
-0x1040F => 0x10437,
-0x10410 => 0x10438,
-0x10411 => 0x10439,
-0x10412 => 0x1043A,
-0x10413 => 0x1043B,
-0x10414 => 0x1043C,
-0x10415 => 0x1043D,
-0x10416 => 0x1043E,
-0x10417 => 0x1043F,
-0x10418 => 0x10440,
-0x10419 => 0x10441,
-0x1041A => 0x10442,
-0x1041B => 0x10443,
-0x1041C => 0x10444,
-0x1041D => 0x10445,
-0x1041E => 0x10446,
-0x1041F => 0x10447,
-0x10420 => 0x10448,
-0x10421 => 0x10449,
-0x10422 => 0x1044A,
-0x10423 => 0x1044B,
-0x10424 => 0x1044C,
-0x10425 => 0x1044D,
-0x10426 => 0x1044E,
-0x10427 => 0x1044F,
-0x104B0 => 0x104D8,
-0x104B1 => 0x104D9,
-0x104B2 => 0x104DA,
-0x104B3 => 0x104DB,
-0x104B4 => 0x104DC,
-0x104B5 => 0x104DD,
-0x104B6 => 0x104DE,
-0x104B7 => 0x104DF,
-0x104B8 => 0x104E0,
-0x104B9 => 0x104E1,
-0x104BA => 0x104E2,
-0x104BB => 0x104E3,
-0x104BC => 0x104E4,
-0x104BD => 0x104E5,
-0x104BE => 0x104E6,
-0x104BF => 0x104E7,
-0x104C0 => 0x104E8,
-0x104C1 => 0x104E9,
-0x104C2 => 0x104EA,
-0x104C3 => 0x104EB,
-0x104C4 => 0x104EC,
-0x104C5 => 0x104ED,
-0x104C6 => 0x104EE,
-0x104C7 => 0x104EF,
-0x104C8 => 0x104F0,
-0x104C9 => 0x104F1,
-0x104CA => 0x104F2,
-0x104CB => 0x104F3,
-0x104CC => 0x104F4,
-0x104CD => 0x104F5,
-0x104CE => 0x104F6,
-0x104CF => 0x104F7,
-0x104D0 => 0x104F8,
-0x104D1 => 0x104F9,
-0x104D2 => 0x104FA,
-0x104D3 => 0x104FB,
-0x10C80 => 0x10CC0,
-0x10C81 => 0x10CC1,
-0x10C82 => 0x10CC2,
-0x10C83 => 0x10CC3,
-0x10C84 => 0x10CC4,
-0x10C85 => 0x10CC5,
-0x10C86 => 0x10CC6,
-0x10C87 => 0x10CC7,
-0x10C88 => 0x10CC8,
-0x10C89 => 0x10CC9,
-0x10C8A => 0x10CCA,
-0x10C8B => 0x10CCB,
-0x10C8C => 0x10CCC,
-0x10C8D => 0x10CCD,
-0x10C8E => 0x10CCE,
-0x10C8F => 0x10CCF,
-0x10C90 => 0x10CD0,
-0x10C91 => 0x10CD1,
-0x10C92 => 0x10CD2,
-0x10C93 => 0x10CD3,
-0x10C94 => 0x10CD4,
-0x10C95 => 0x10CD5,
-0x10C96 => 0x10CD6,
-0x10C97 => 0x10CD7,
-0x10C98 => 0x10CD8,
-0x10C99 => 0x10CD9,
-0x10C9A => 0x10CDA,
-0x10C9B => 0x10CDB,
-0x10C9C => 0x10CDC,
-0x10C9D => 0x10CDD,
-0x10C9E => 0x10CDE,
-0x10C9F => 0x10CDF,
-0x10CA0 => 0x10CE0,
-0x10CA1 => 0x10CE1,
-0x10CA2 => 0x10CE2,
-0x10CA3 => 0x10CE3,
-0x10CA4 => 0x10CE4,
-0x10CA5 => 0x10CE5,
-0x10CA6 => 0x10CE6,
-0x10CA7 => 0x10CE7,
-0x10CA8 => 0x10CE8,
-0x10CA9 => 0x10CE9,
-0x10CAA => 0x10CEA,
-0x10CAB => 0x10CEB,
-0x10CAC => 0x10CEC,
-0x10CAD => 0x10CED,
-0x10CAE => 0x10CEE,
-0x10CAF => 0x10CEF,
-0x10CB0 => 0x10CF0,
-0x10CB1 => 0x10CF1,
-0x10CB2 => 0x10CF2,
-0x118A0 => 0x118C0,
-0x118A1 => 0x118C1,
-0x118A2 => 0x118C2,
-0x118A3 => 0x118C3,
-0x118A4 => 0x118C4,
-0x118A5 => 0x118C5,
-0x118A6 => 0x118C6,
-0x118A7 => 0x118C7,
-0x118A8 => 0x118C8,
-0x118A9 => 0x118C9,
-0x118AA => 0x118CA,
-0x118AB => 0x118CB,
-0x118AC => 0x118CC,
-0x118AD => 0x118CD,
-0x118AE => 0x118CE,
-0x118AF => 0x118CF,
-0x118B0 => 0x118D0,
-0x118B1 => 0x118D1,
-0x118B2 => 0x118D2,
-0x118B3 => 0x118D3,
-0x118B4 => 0x118D4,
-0x118B5 => 0x118D5,
-0x118B6 => 0x118D6,
-0x118B7 => 0x118D7,
-0x118B8 => 0x118D8,
-0x118B9 => 0x118D9,
-0x118BA => 0x118DA,
-0x118BB => 0x118DB,
-0x118BC => 0x118DC,
-0x118BD => 0x118DD,
-0x118BE => 0x118DE,
-0x118BF => 0x118DF,
-0x16E40 => 0x16E60,
-0x16E41 => 0x16E61,
-0x16E42 => 0x16E62,
-0x16E43 => 0x16E63,
-0x16E44 => 0x16E64,
-0x16E45 => 0x16E65,
-0x16E46 => 0x16E66,
-0x16E47 => 0x16E67,
-0x16E48 => 0x16E68,
-0x16E49 => 0x16E69,
-0x16E4A => 0x16E6A,
-0x16E4B => 0x16E6B,
-0x16E4C => 0x16E6C,
-0x16E4D => 0x16E6D,
-0x16E4E => 0x16E6E,
-0x16E4F => 0x16E6F,
-0x16E50 => 0x16E70,
-0x16E51 => 0x16E71,
-0x16E52 => 0x16E72,
-0x16E53 => 0x16E73,
-0x16E54 => 0x16E74,
-0x16E55 => 0x16E75,
-0x16E56 => 0x16E76,
-0x16E57 => 0x16E77,
-0x16E58 => 0x16E78,
-0x16E59 => 0x16E79,
-0x16E5A => 0x16E7A,
-0x16E5B => 0x16E7B,
-0x16E5C => 0x16E7C,
-0x16E5D => 0x16E7D,
-0x16E5E => 0x16E7E,
-0x16E5F => 0x16E7F,
-0x1E900 => 0x1E922,
-0x1E901 => 0x1E923,
-0x1E902 => 0x1E924,
-0x1E903 => 0x1E925,
-0x1E904 => 0x1E926,
-0x1E905 => 0x1E927,
-0x1E906 => 0x1E928,
-0x1E907 => 0x1E929,
-0x1E908 => 0x1E92A,
-0x1E909 => 0x1E92B,
-0x1E90A => 0x1E92C,
-0x1E90B => 0x1E92D,
-0x1E90C => 0x1E92E,
-0x1E90D => 0x1E92F,
-0x1E90E => 0x1E930,
-0x1E90F => 0x1E931,
-0x1E910 => 0x1E932,
-0x1E911 => 0x1E933,
-0x1E912 => 0x1E934,
-0x1E913 => 0x1E935,
-0x1E914 => 0x1E936,
-0x1E915 => 0x1E937,
-0x1E916 => 0x1E938,
-0x1E917 => 0x1E939,
-0x1E918 => 0x1E93A,
-0x1E919 => 0x1E93B,
-0x1E91A => 0x1E93C,
-0x1E91B => 0x1E93D,
-0x1E91C => 0x1E93E,
-0x1E91D => 0x1E93F,
-0x1E91E => 0x1E940,
-0x1E91F => 0x1E941,
-0x1E920 => 0x1E942,
-0x1E921 => 0x1E943,
-];
+return array(
+ 0x41 => 0x61,
+ 0x42 => 0x62,
+ 0x43 => 0x63,
+ 0x44 => 0x64,
+ 0x45 => 0x65,
+ 0x46 => 0x66,
+ 0x47 => 0x67,
+ 0x48 => 0x68,
+ 0x49 => 0x69,
+ 0x4A => 0x6A,
+ 0x4B => 0x6B,
+ 0x4C => 0x6C,
+ 0x4D => 0x6D,
+ 0x4E => 0x6E,
+ 0x4F => 0x6F,
+ 0x50 => 0x70,
+ 0x51 => 0x71,
+ 0x52 => 0x72,
+ 0x53 => 0x73,
+ 0x54 => 0x74,
+ 0x55 => 0x75,
+ 0x56 => 0x76,
+ 0x57 => 0x77,
+ 0x58 => 0x78,
+ 0x59 => 0x79,
+ 0x5A => 0x7A,
+ 0xC0 => 0xE0,
+ 0xC1 => 0xE1,
+ 0xC2 => 0xE2,
+ 0xC3 => 0xE3,
+ 0xC4 => 0xE4,
+ 0xC5 => 0xE5,
+ 0xC6 => 0xE6,
+ 0xC7 => 0xE7,
+ 0xC8 => 0xE8,
+ 0xC9 => 0xE9,
+ 0xCA => 0xEA,
+ 0xCB => 0xEB,
+ 0xCC => 0xEC,
+ 0xCD => 0xED,
+ 0xCE => 0xEE,
+ 0xCF => 0xEF,
+ 0xD0 => 0xF0,
+ 0xD1 => 0xF1,
+ 0xD2 => 0xF2,
+ 0xD3 => 0xF3,
+ 0xD4 => 0xF4,
+ 0xD5 => 0xF5,
+ 0xD6 => 0xF6,
+ 0xD8 => 0xF8,
+ 0xD9 => 0xF9,
+ 0xDA => 0xFA,
+ 0xDB => 0xFB,
+ 0xDC => 0xFC,
+ 0xDD => 0xFD,
+ 0xDE => 0xFE,
+ 0x100 => 0x101,
+ 0x102 => 0x103,
+ 0x104 => 0x105,
+ 0x106 => 0x107,
+ 0x108 => 0x109,
+ 0x10A => 0x10B,
+ 0x10C => 0x10D,
+ 0x10E => 0x10F,
+ 0x110 => 0x111,
+ 0x112 => 0x113,
+ 0x114 => 0x115,
+ 0x116 => 0x117,
+ 0x118 => 0x119,
+ 0x11A => 0x11B,
+ 0x11C => 0x11D,
+ 0x11E => 0x11F,
+ 0x120 => 0x121,
+ 0x122 => 0x123,
+ 0x124 => 0x125,
+ 0x126 => 0x127,
+ 0x128 => 0x129,
+ 0x12A => 0x12B,
+ 0x12C => 0x12D,
+ 0x12E => 0x12F,
+ 0x130 => 0x69,
+ 0x132 => 0x133,
+ 0x134 => 0x135,
+ 0x136 => 0x137,
+ 0x139 => 0x13A,
+ 0x13B => 0x13C,
+ 0x13D => 0x13E,
+ 0x13F => 0x140,
+ 0x141 => 0x142,
+ 0x143 => 0x144,
+ 0x145 => 0x146,
+ 0x147 => 0x148,
+ 0x14A => 0x14B,
+ 0x14C => 0x14D,
+ 0x14E => 0x14F,
+ 0x150 => 0x151,
+ 0x152 => 0x153,
+ 0x154 => 0x155,
+ 0x156 => 0x157,
+ 0x158 => 0x159,
+ 0x15A => 0x15B,
+ 0x15C => 0x15D,
+ 0x15E => 0x15F,
+ 0x160 => 0x161,
+ 0x162 => 0x163,
+ 0x164 => 0x165,
+ 0x166 => 0x167,
+ 0x168 => 0x169,
+ 0x16A => 0x16B,
+ 0x16C => 0x16D,
+ 0x16E => 0x16F,
+ 0x170 => 0x171,
+ 0x172 => 0x173,
+ 0x174 => 0x175,
+ 0x176 => 0x177,
+ 0x178 => 0xFF,
+ 0x179 => 0x17A,
+ 0x17B => 0x17C,
+ 0x17D => 0x17E,
+ 0x181 => 0x253,
+ 0x182 => 0x183,
+ 0x184 => 0x185,
+ 0x186 => 0x254,
+ 0x187 => 0x188,
+ 0x189 => 0x256,
+ 0x18A => 0x257,
+ 0x18B => 0x18C,
+ 0x18E => 0x1DD,
+ 0x18F => 0x259,
+ 0x190 => 0x25B,
+ 0x191 => 0x192,
+ 0x193 => 0x260,
+ 0x194 => 0x263,
+ 0x196 => 0x269,
+ 0x197 => 0x268,
+ 0x198 => 0x199,
+ 0x19C => 0x26F,
+ 0x19D => 0x272,
+ 0x19F => 0x275,
+ 0x1A0 => 0x1A1,
+ 0x1A2 => 0x1A3,
+ 0x1A4 => 0x1A5,
+ 0x1A6 => 0x280,
+ 0x1A7 => 0x1A8,
+ 0x1A9 => 0x283,
+ 0x1AC => 0x1AD,
+ 0x1AE => 0x288,
+ 0x1AF => 0x1B0,
+ 0x1B1 => 0x28A,
+ 0x1B2 => 0x28B,
+ 0x1B3 => 0x1B4,
+ 0x1B5 => 0x1B6,
+ 0x1B7 => 0x292,
+ 0x1B8 => 0x1B9,
+ 0x1BC => 0x1BD,
+ 0x1C4 => 0x1C6,
+ 0x1C5 => 0x1C6,
+ 0x1C7 => 0x1C9,
+ 0x1C8 => 0x1C9,
+ 0x1CA => 0x1CC,
+ 0x1CB => 0x1CC,
+ 0x1CD => 0x1CE,
+ 0x1CF => 0x1D0,
+ 0x1D1 => 0x1D2,
+ 0x1D3 => 0x1D4,
+ 0x1D5 => 0x1D6,
+ 0x1D7 => 0x1D8,
+ 0x1D9 => 0x1DA,
+ 0x1DB => 0x1DC,
+ 0x1DE => 0x1DF,
+ 0x1E0 => 0x1E1,
+ 0x1E2 => 0x1E3,
+ 0x1E4 => 0x1E5,
+ 0x1E6 => 0x1E7,
+ 0x1E8 => 0x1E9,
+ 0x1EA => 0x1EB,
+ 0x1EC => 0x1ED,
+ 0x1EE => 0x1EF,
+ 0x1F1 => 0x1F3,
+ 0x1F2 => 0x1F3,
+ 0x1F4 => 0x1F5,
+ 0x1F6 => 0x195,
+ 0x1F7 => 0x1BF,
+ 0x1F8 => 0x1F9,
+ 0x1FA => 0x1FB,
+ 0x1FC => 0x1FD,
+ 0x1FE => 0x1FF,
+ 0x200 => 0x201,
+ 0x202 => 0x203,
+ 0x204 => 0x205,
+ 0x206 => 0x207,
+ 0x208 => 0x209,
+ 0x20A => 0x20B,
+ 0x20C => 0x20D,
+ 0x20E => 0x20F,
+ 0x210 => 0x211,
+ 0x212 => 0x213,
+ 0x214 => 0x215,
+ 0x216 => 0x217,
+ 0x218 => 0x219,
+ 0x21A => 0x21B,
+ 0x21C => 0x21D,
+ 0x21E => 0x21F,
+ 0x220 => 0x19E,
+ 0x222 => 0x223,
+ 0x224 => 0x225,
+ 0x226 => 0x227,
+ 0x228 => 0x229,
+ 0x22A => 0x22B,
+ 0x22C => 0x22D,
+ 0x22E => 0x22F,
+ 0x230 => 0x231,
+ 0x232 => 0x233,
+ 0x23A => 0x2C65,
+ 0x23B => 0x23C,
+ 0x23D => 0x19A,
+ 0x23E => 0x2C66,
+ 0x241 => 0x242,
+ 0x243 => 0x180,
+ 0x244 => 0x289,
+ 0x245 => 0x28C,
+ 0x246 => 0x247,
+ 0x248 => 0x249,
+ 0x24A => 0x24B,
+ 0x24C => 0x24D,
+ 0x24E => 0x24F,
+ 0x370 => 0x371,
+ 0x372 => 0x373,
+ 0x376 => 0x377,
+ 0x37F => 0x3F3,
+ 0x386 => 0x3AC,
+ 0x388 => 0x3AD,
+ 0x389 => 0x3AE,
+ 0x38A => 0x3AF,
+ 0x38C => 0x3CC,
+ 0x38E => 0x3CD,
+ 0x38F => 0x3CE,
+ 0x391 => 0x3B1,
+ 0x392 => 0x3B2,
+ 0x393 => 0x3B3,
+ 0x394 => 0x3B4,
+ 0x395 => 0x3B5,
+ 0x396 => 0x3B6,
+ 0x397 => 0x3B7,
+ 0x398 => 0x3B8,
+ 0x399 => 0x3B9,
+ 0x39A => 0x3BA,
+ 0x39B => 0x3BB,
+ 0x39C => 0x3BC,
+ 0x39D => 0x3BD,
+ 0x39E => 0x3BE,
+ 0x39F => 0x3BF,
+ 0x3A0 => 0x3C0,
+ 0x3A1 => 0x3C1,
+ 0x3A3 => 0x3C3,
+ 0x3A4 => 0x3C4,
+ 0x3A5 => 0x3C5,
+ 0x3A6 => 0x3C6,
+ 0x3A7 => 0x3C7,
+ 0x3A8 => 0x3C8,
+ 0x3A9 => 0x3C9,
+ 0x3AA => 0x3CA,
+ 0x3AB => 0x3CB,
+ 0x3CF => 0x3D7,
+ 0x3D8 => 0x3D9,
+ 0x3DA => 0x3DB,
+ 0x3DC => 0x3DD,
+ 0x3DE => 0x3DF,
+ 0x3E0 => 0x3E1,
+ 0x3E2 => 0x3E3,
+ 0x3E4 => 0x3E5,
+ 0x3E6 => 0x3E7,
+ 0x3E8 => 0x3E9,
+ 0x3EA => 0x3EB,
+ 0x3EC => 0x3ED,
+ 0x3EE => 0x3EF,
+ 0x3F4 => 0x3B8,
+ 0x3F7 => 0x3F8,
+ 0x3F9 => 0x3F2,
+ 0x3FA => 0x3FB,
+ 0x3FD => 0x37B,
+ 0x3FE => 0x37C,
+ 0x3FF => 0x37D,
+ 0x400 => 0x450,
+ 0x401 => 0x451,
+ 0x402 => 0x452,
+ 0x403 => 0x453,
+ 0x404 => 0x454,
+ 0x405 => 0x455,
+ 0x406 => 0x456,
+ 0x407 => 0x457,
+ 0x408 => 0x458,
+ 0x409 => 0x459,
+ 0x40A => 0x45A,
+ 0x40B => 0x45B,
+ 0x40C => 0x45C,
+ 0x40D => 0x45D,
+ 0x40E => 0x45E,
+ 0x40F => 0x45F,
+ 0x410 => 0x430,
+ 0x411 => 0x431,
+ 0x412 => 0x432,
+ 0x413 => 0x433,
+ 0x414 => 0x434,
+ 0x415 => 0x435,
+ 0x416 => 0x436,
+ 0x417 => 0x437,
+ 0x418 => 0x438,
+ 0x419 => 0x439,
+ 0x41A => 0x43A,
+ 0x41B => 0x43B,
+ 0x41C => 0x43C,
+ 0x41D => 0x43D,
+ 0x41E => 0x43E,
+ 0x41F => 0x43F,
+ 0x420 => 0x440,
+ 0x421 => 0x441,
+ 0x422 => 0x442,
+ 0x423 => 0x443,
+ 0x424 => 0x444,
+ 0x425 => 0x445,
+ 0x426 => 0x446,
+ 0x427 => 0x447,
+ 0x428 => 0x448,
+ 0x429 => 0x449,
+ 0x42A => 0x44A,
+ 0x42B => 0x44B,
+ 0x42C => 0x44C,
+ 0x42D => 0x44D,
+ 0x42E => 0x44E,
+ 0x42F => 0x44F,
+ 0x460 => 0x461,
+ 0x462 => 0x463,
+ 0x464 => 0x465,
+ 0x466 => 0x467,
+ 0x468 => 0x469,
+ 0x46A => 0x46B,
+ 0x46C => 0x46D,
+ 0x46E => 0x46F,
+ 0x470 => 0x471,
+ 0x472 => 0x473,
+ 0x474 => 0x475,
+ 0x476 => 0x477,
+ 0x478 => 0x479,
+ 0x47A => 0x47B,
+ 0x47C => 0x47D,
+ 0x47E => 0x47F,
+ 0x480 => 0x481,
+ 0x48A => 0x48B,
+ 0x48C => 0x48D,
+ 0x48E => 0x48F,
+ 0x490 => 0x491,
+ 0x492 => 0x493,
+ 0x494 => 0x495,
+ 0x496 => 0x497,
+ 0x498 => 0x499,
+ 0x49A => 0x49B,
+ 0x49C => 0x49D,
+ 0x49E => 0x49F,
+ 0x4A0 => 0x4A1,
+ 0x4A2 => 0x4A3,
+ 0x4A4 => 0x4A5,
+ 0x4A6 => 0x4A7,
+ 0x4A8 => 0x4A9,
+ 0x4AA => 0x4AB,
+ 0x4AC => 0x4AD,
+ 0x4AE => 0x4AF,
+ 0x4B0 => 0x4B1,
+ 0x4B2 => 0x4B3,
+ 0x4B4 => 0x4B5,
+ 0x4B6 => 0x4B7,
+ 0x4B8 => 0x4B9,
+ 0x4BA => 0x4BB,
+ 0x4BC => 0x4BD,
+ 0x4BE => 0x4BF,
+ 0x4C0 => 0x4CF,
+ 0x4C1 => 0x4C2,
+ 0x4C3 => 0x4C4,
+ 0x4C5 => 0x4C6,
+ 0x4C7 => 0x4C8,
+ 0x4C9 => 0x4CA,
+ 0x4CB => 0x4CC,
+ 0x4CD => 0x4CE,
+ 0x4D0 => 0x4D1,
+ 0x4D2 => 0x4D3,
+ 0x4D4 => 0x4D5,
+ 0x4D6 => 0x4D7,
+ 0x4D8 => 0x4D9,
+ 0x4DA => 0x4DB,
+ 0x4DC => 0x4DD,
+ 0x4DE => 0x4DF,
+ 0x4E0 => 0x4E1,
+ 0x4E2 => 0x4E3,
+ 0x4E4 => 0x4E5,
+ 0x4E6 => 0x4E7,
+ 0x4E8 => 0x4E9,
+ 0x4EA => 0x4EB,
+ 0x4EC => 0x4ED,
+ 0x4EE => 0x4EF,
+ 0x4F0 => 0x4F1,
+ 0x4F2 => 0x4F3,
+ 0x4F4 => 0x4F5,
+ 0x4F6 => 0x4F7,
+ 0x4F8 => 0x4F9,
+ 0x4FA => 0x4FB,
+ 0x4FC => 0x4FD,
+ 0x4FE => 0x4FF,
+ 0x500 => 0x501,
+ 0x502 => 0x503,
+ 0x504 => 0x505,
+ 0x506 => 0x507,
+ 0x508 => 0x509,
+ 0x50A => 0x50B,
+ 0x50C => 0x50D,
+ 0x50E => 0x50F,
+ 0x510 => 0x511,
+ 0x512 => 0x513,
+ 0x514 => 0x515,
+ 0x516 => 0x517,
+ 0x518 => 0x519,
+ 0x51A => 0x51B,
+ 0x51C => 0x51D,
+ 0x51E => 0x51F,
+ 0x520 => 0x521,
+ 0x522 => 0x523,
+ 0x524 => 0x525,
+ 0x526 => 0x527,
+ 0x528 => 0x529,
+ 0x52A => 0x52B,
+ 0x52C => 0x52D,
+ 0x52E => 0x52F,
+ 0x531 => 0x561,
+ 0x532 => 0x562,
+ 0x533 => 0x563,
+ 0x534 => 0x564,
+ 0x535 => 0x565,
+ 0x536 => 0x566,
+ 0x537 => 0x567,
+ 0x538 => 0x568,
+ 0x539 => 0x569,
+ 0x53A => 0x56A,
+ 0x53B => 0x56B,
+ 0x53C => 0x56C,
+ 0x53D => 0x56D,
+ 0x53E => 0x56E,
+ 0x53F => 0x56F,
+ 0x540 => 0x570,
+ 0x541 => 0x571,
+ 0x542 => 0x572,
+ 0x543 => 0x573,
+ 0x544 => 0x574,
+ 0x545 => 0x575,
+ 0x546 => 0x576,
+ 0x547 => 0x577,
+ 0x548 => 0x578,
+ 0x549 => 0x579,
+ 0x54A => 0x57A,
+ 0x54B => 0x57B,
+ 0x54C => 0x57C,
+ 0x54D => 0x57D,
+ 0x54E => 0x57E,
+ 0x54F => 0x57F,
+ 0x550 => 0x580,
+ 0x551 => 0x581,
+ 0x552 => 0x582,
+ 0x553 => 0x583,
+ 0x554 => 0x584,
+ 0x555 => 0x585,
+ 0x556 => 0x586,
+ 0x10A0 => 0x2D00,
+ 0x10A1 => 0x2D01,
+ 0x10A2 => 0x2D02,
+ 0x10A3 => 0x2D03,
+ 0x10A4 => 0x2D04,
+ 0x10A5 => 0x2D05,
+ 0x10A6 => 0x2D06,
+ 0x10A7 => 0x2D07,
+ 0x10A8 => 0x2D08,
+ 0x10A9 => 0x2D09,
+ 0x10AA => 0x2D0A,
+ 0x10AB => 0x2D0B,
+ 0x10AC => 0x2D0C,
+ 0x10AD => 0x2D0D,
+ 0x10AE => 0x2D0E,
+ 0x10AF => 0x2D0F,
+ 0x10B0 => 0x2D10,
+ 0x10B1 => 0x2D11,
+ 0x10B2 => 0x2D12,
+ 0x10B3 => 0x2D13,
+ 0x10B4 => 0x2D14,
+ 0x10B5 => 0x2D15,
+ 0x10B6 => 0x2D16,
+ 0x10B7 => 0x2D17,
+ 0x10B8 => 0x2D18,
+ 0x10B9 => 0x2D19,
+ 0x10BA => 0x2D1A,
+ 0x10BB => 0x2D1B,
+ 0x10BC => 0x2D1C,
+ 0x10BD => 0x2D1D,
+ 0x10BE => 0x2D1E,
+ 0x10BF => 0x2D1F,
+ 0x10C0 => 0x2D20,
+ 0x10C1 => 0x2D21,
+ 0x10C2 => 0x2D22,
+ 0x10C3 => 0x2D23,
+ 0x10C4 => 0x2D24,
+ 0x10C5 => 0x2D25,
+ 0x10C7 => 0x2D27,
+ 0x10CD => 0x2D2D,
+ 0x13A0 => 0xAB70,
+ 0x13A1 => 0xAB71,
+ 0x13A2 => 0xAB72,
+ 0x13A3 => 0xAB73,
+ 0x13A4 => 0xAB74,
+ 0x13A5 => 0xAB75,
+ 0x13A6 => 0xAB76,
+ 0x13A7 => 0xAB77,
+ 0x13A8 => 0xAB78,
+ 0x13A9 => 0xAB79,
+ 0x13AA => 0xAB7A,
+ 0x13AB => 0xAB7B,
+ 0x13AC => 0xAB7C,
+ 0x13AD => 0xAB7D,
+ 0x13AE => 0xAB7E,
+ 0x13AF => 0xAB7F,
+ 0x13B0 => 0xAB80,
+ 0x13B1 => 0xAB81,
+ 0x13B2 => 0xAB82,
+ 0x13B3 => 0xAB83,
+ 0x13B4 => 0xAB84,
+ 0x13B5 => 0xAB85,
+ 0x13B6 => 0xAB86,
+ 0x13B7 => 0xAB87,
+ 0x13B8 => 0xAB88,
+ 0x13B9 => 0xAB89,
+ 0x13BA => 0xAB8A,
+ 0x13BB => 0xAB8B,
+ 0x13BC => 0xAB8C,
+ 0x13BD => 0xAB8D,
+ 0x13BE => 0xAB8E,
+ 0x13BF => 0xAB8F,
+ 0x13C0 => 0xAB90,
+ 0x13C1 => 0xAB91,
+ 0x13C2 => 0xAB92,
+ 0x13C3 => 0xAB93,
+ 0x13C4 => 0xAB94,
+ 0x13C5 => 0xAB95,
+ 0x13C6 => 0xAB96,
+ 0x13C7 => 0xAB97,
+ 0x13C8 => 0xAB98,
+ 0x13C9 => 0xAB99,
+ 0x13CA => 0xAB9A,
+ 0x13CB => 0xAB9B,
+ 0x13CC => 0xAB9C,
+ 0x13CD => 0xAB9D,
+ 0x13CE => 0xAB9E,
+ 0x13CF => 0xAB9F,
+ 0x13D0 => 0xABA0,
+ 0x13D1 => 0xABA1,
+ 0x13D2 => 0xABA2,
+ 0x13D3 => 0xABA3,
+ 0x13D4 => 0xABA4,
+ 0x13D5 => 0xABA5,
+ 0x13D6 => 0xABA6,
+ 0x13D7 => 0xABA7,
+ 0x13D8 => 0xABA8,
+ 0x13D9 => 0xABA9,
+ 0x13DA => 0xABAA,
+ 0x13DB => 0xABAB,
+ 0x13DC => 0xABAC,
+ 0x13DD => 0xABAD,
+ 0x13DE => 0xABAE,
+ 0x13DF => 0xABAF,
+ 0x13E0 => 0xABB0,
+ 0x13E1 => 0xABB1,
+ 0x13E2 => 0xABB2,
+ 0x13E3 => 0xABB3,
+ 0x13E4 => 0xABB4,
+ 0x13E5 => 0xABB5,
+ 0x13E6 => 0xABB6,
+ 0x13E7 => 0xABB7,
+ 0x13E8 => 0xABB8,
+ 0x13E9 => 0xABB9,
+ 0x13EA => 0xABBA,
+ 0x13EB => 0xABBB,
+ 0x13EC => 0xABBC,
+ 0x13ED => 0xABBD,
+ 0x13EE => 0xABBE,
+ 0x13EF => 0xABBF,
+ 0x13F0 => 0x13F8,
+ 0x13F1 => 0x13F9,
+ 0x13F2 => 0x13FA,
+ 0x13F3 => 0x13FB,
+ 0x13F4 => 0x13FC,
+ 0x13F5 => 0x13FD,
+ 0x1C90 => 0x10D0,
+ 0x1C91 => 0x10D1,
+ 0x1C92 => 0x10D2,
+ 0x1C93 => 0x10D3,
+ 0x1C94 => 0x10D4,
+ 0x1C95 => 0x10D5,
+ 0x1C96 => 0x10D6,
+ 0x1C97 => 0x10D7,
+ 0x1C98 => 0x10D8,
+ 0x1C99 => 0x10D9,
+ 0x1C9A => 0x10DA,
+ 0x1C9B => 0x10DB,
+ 0x1C9C => 0x10DC,
+ 0x1C9D => 0x10DD,
+ 0x1C9E => 0x10DE,
+ 0x1C9F => 0x10DF,
+ 0x1CA0 => 0x10E0,
+ 0x1CA1 => 0x10E1,
+ 0x1CA2 => 0x10E2,
+ 0x1CA3 => 0x10E3,
+ 0x1CA4 => 0x10E4,
+ 0x1CA5 => 0x10E5,
+ 0x1CA6 => 0x10E6,
+ 0x1CA7 => 0x10E7,
+ 0x1CA8 => 0x10E8,
+ 0x1CA9 => 0x10E9,
+ 0x1CAA => 0x10EA,
+ 0x1CAB => 0x10EB,
+ 0x1CAC => 0x10EC,
+ 0x1CAD => 0x10ED,
+ 0x1CAE => 0x10EE,
+ 0x1CAF => 0x10EF,
+ 0x1CB0 => 0x10F0,
+ 0x1CB1 => 0x10F1,
+ 0x1CB2 => 0x10F2,
+ 0x1CB3 => 0x10F3,
+ 0x1CB4 => 0x10F4,
+ 0x1CB5 => 0x10F5,
+ 0x1CB6 => 0x10F6,
+ 0x1CB7 => 0x10F7,
+ 0x1CB8 => 0x10F8,
+ 0x1CB9 => 0x10F9,
+ 0x1CBA => 0x10FA,
+ 0x1CBD => 0x10FD,
+ 0x1CBE => 0x10FE,
+ 0x1CBF => 0x10FF,
+ 0x1E00 => 0x1E01,
+ 0x1E02 => 0x1E03,
+ 0x1E04 => 0x1E05,
+ 0x1E06 => 0x1E07,
+ 0x1E08 => 0x1E09,
+ 0x1E0A => 0x1E0B,
+ 0x1E0C => 0x1E0D,
+ 0x1E0E => 0x1E0F,
+ 0x1E10 => 0x1E11,
+ 0x1E12 => 0x1E13,
+ 0x1E14 => 0x1E15,
+ 0x1E16 => 0x1E17,
+ 0x1E18 => 0x1E19,
+ 0x1E1A => 0x1E1B,
+ 0x1E1C => 0x1E1D,
+ 0x1E1E => 0x1E1F,
+ 0x1E20 => 0x1E21,
+ 0x1E22 => 0x1E23,
+ 0x1E24 => 0x1E25,
+ 0x1E26 => 0x1E27,
+ 0x1E28 => 0x1E29,
+ 0x1E2A => 0x1E2B,
+ 0x1E2C => 0x1E2D,
+ 0x1E2E => 0x1E2F,
+ 0x1E30 => 0x1E31,
+ 0x1E32 => 0x1E33,
+ 0x1E34 => 0x1E35,
+ 0x1E36 => 0x1E37,
+ 0x1E38 => 0x1E39,
+ 0x1E3A => 0x1E3B,
+ 0x1E3C => 0x1E3D,
+ 0x1E3E => 0x1E3F,
+ 0x1E40 => 0x1E41,
+ 0x1E42 => 0x1E43,
+ 0x1E44 => 0x1E45,
+ 0x1E46 => 0x1E47,
+ 0x1E48 => 0x1E49,
+ 0x1E4A => 0x1E4B,
+ 0x1E4C => 0x1E4D,
+ 0x1E4E => 0x1E4F,
+ 0x1E50 => 0x1E51,
+ 0x1E52 => 0x1E53,
+ 0x1E54 => 0x1E55,
+ 0x1E56 => 0x1E57,
+ 0x1E58 => 0x1E59,
+ 0x1E5A => 0x1E5B,
+ 0x1E5C => 0x1E5D,
+ 0x1E5E => 0x1E5F,
+ 0x1E60 => 0x1E61,
+ 0x1E62 => 0x1E63,
+ 0x1E64 => 0x1E65,
+ 0x1E66 => 0x1E67,
+ 0x1E68 => 0x1E69,
+ 0x1E6A => 0x1E6B,
+ 0x1E6C => 0x1E6D,
+ 0x1E6E => 0x1E6F,
+ 0x1E70 => 0x1E71,
+ 0x1E72 => 0x1E73,
+ 0x1E74 => 0x1E75,
+ 0x1E76 => 0x1E77,
+ 0x1E78 => 0x1E79,
+ 0x1E7A => 0x1E7B,
+ 0x1E7C => 0x1E7D,
+ 0x1E7E => 0x1E7F,
+ 0x1E80 => 0x1E81,
+ 0x1E82 => 0x1E83,
+ 0x1E84 => 0x1E85,
+ 0x1E86 => 0x1E87,
+ 0x1E88 => 0x1E89,
+ 0x1E8A => 0x1E8B,
+ 0x1E8C => 0x1E8D,
+ 0x1E8E => 0x1E8F,
+ 0x1E90 => 0x1E91,
+ 0x1E92 => 0x1E93,
+ 0x1E94 => 0x1E95,
+ 0x1E9E => 0xDF,
+ 0x1EA0 => 0x1EA1,
+ 0x1EA2 => 0x1EA3,
+ 0x1EA4 => 0x1EA5,
+ 0x1EA6 => 0x1EA7,
+ 0x1EA8 => 0x1EA9,
+ 0x1EAA => 0x1EAB,
+ 0x1EAC => 0x1EAD,
+ 0x1EAE => 0x1EAF,
+ 0x1EB0 => 0x1EB1,
+ 0x1EB2 => 0x1EB3,
+ 0x1EB4 => 0x1EB5,
+ 0x1EB6 => 0x1EB7,
+ 0x1EB8 => 0x1EB9,
+ 0x1EBA => 0x1EBB,
+ 0x1EBC => 0x1EBD,
+ 0x1EBE => 0x1EBF,
+ 0x1EC0 => 0x1EC1,
+ 0x1EC2 => 0x1EC3,
+ 0x1EC4 => 0x1EC5,
+ 0x1EC6 => 0x1EC7,
+ 0x1EC8 => 0x1EC9,
+ 0x1ECA => 0x1ECB,
+ 0x1ECC => 0x1ECD,
+ 0x1ECE => 0x1ECF,
+ 0x1ED0 => 0x1ED1,
+ 0x1ED2 => 0x1ED3,
+ 0x1ED4 => 0x1ED5,
+ 0x1ED6 => 0x1ED7,
+ 0x1ED8 => 0x1ED9,
+ 0x1EDA => 0x1EDB,
+ 0x1EDC => 0x1EDD,
+ 0x1EDE => 0x1EDF,
+ 0x1EE0 => 0x1EE1,
+ 0x1EE2 => 0x1EE3,
+ 0x1EE4 => 0x1EE5,
+ 0x1EE6 => 0x1EE7,
+ 0x1EE8 => 0x1EE9,
+ 0x1EEA => 0x1EEB,
+ 0x1EEC => 0x1EED,
+ 0x1EEE => 0x1EEF,
+ 0x1EF0 => 0x1EF1,
+ 0x1EF2 => 0x1EF3,
+ 0x1EF4 => 0x1EF5,
+ 0x1EF6 => 0x1EF7,
+ 0x1EF8 => 0x1EF9,
+ 0x1EFA => 0x1EFB,
+ 0x1EFC => 0x1EFD,
+ 0x1EFE => 0x1EFF,
+ 0x1F08 => 0x1F00,
+ 0x1F09 => 0x1F01,
+ 0x1F0A => 0x1F02,
+ 0x1F0B => 0x1F03,
+ 0x1F0C => 0x1F04,
+ 0x1F0D => 0x1F05,
+ 0x1F0E => 0x1F06,
+ 0x1F0F => 0x1F07,
+ 0x1F18 => 0x1F10,
+ 0x1F19 => 0x1F11,
+ 0x1F1A => 0x1F12,
+ 0x1F1B => 0x1F13,
+ 0x1F1C => 0x1F14,
+ 0x1F1D => 0x1F15,
+ 0x1F28 => 0x1F20,
+ 0x1F29 => 0x1F21,
+ 0x1F2A => 0x1F22,
+ 0x1F2B => 0x1F23,
+ 0x1F2C => 0x1F24,
+ 0x1F2D => 0x1F25,
+ 0x1F2E => 0x1F26,
+ 0x1F2F => 0x1F27,
+ 0x1F38 => 0x1F30,
+ 0x1F39 => 0x1F31,
+ 0x1F3A => 0x1F32,
+ 0x1F3B => 0x1F33,
+ 0x1F3C => 0x1F34,
+ 0x1F3D => 0x1F35,
+ 0x1F3E => 0x1F36,
+ 0x1F3F => 0x1F37,
+ 0x1F48 => 0x1F40,
+ 0x1F49 => 0x1F41,
+ 0x1F4A => 0x1F42,
+ 0x1F4B => 0x1F43,
+ 0x1F4C => 0x1F44,
+ 0x1F4D => 0x1F45,
+ 0x1F59 => 0x1F51,
+ 0x1F5B => 0x1F53,
+ 0x1F5D => 0x1F55,
+ 0x1F5F => 0x1F57,
+ 0x1F68 => 0x1F60,
+ 0x1F69 => 0x1F61,
+ 0x1F6A => 0x1F62,
+ 0x1F6B => 0x1F63,
+ 0x1F6C => 0x1F64,
+ 0x1F6D => 0x1F65,
+ 0x1F6E => 0x1F66,
+ 0x1F6F => 0x1F67,
+ 0x1F88 => 0x1F80,
+ 0x1F89 => 0x1F81,
+ 0x1F8A => 0x1F82,
+ 0x1F8B => 0x1F83,
+ 0x1F8C => 0x1F84,
+ 0x1F8D => 0x1F85,
+ 0x1F8E => 0x1F86,
+ 0x1F8F => 0x1F87,
+ 0x1F98 => 0x1F90,
+ 0x1F99 => 0x1F91,
+ 0x1F9A => 0x1F92,
+ 0x1F9B => 0x1F93,
+ 0x1F9C => 0x1F94,
+ 0x1F9D => 0x1F95,
+ 0x1F9E => 0x1F96,
+ 0x1F9F => 0x1F97,
+ 0x1FA8 => 0x1FA0,
+ 0x1FA9 => 0x1FA1,
+ 0x1FAA => 0x1FA2,
+ 0x1FAB => 0x1FA3,
+ 0x1FAC => 0x1FA4,
+ 0x1FAD => 0x1FA5,
+ 0x1FAE => 0x1FA6,
+ 0x1FAF => 0x1FA7,
+ 0x1FB8 => 0x1FB0,
+ 0x1FB9 => 0x1FB1,
+ 0x1FBA => 0x1F70,
+ 0x1FBB => 0x1F71,
+ 0x1FBC => 0x1FB3,
+ 0x1FC8 => 0x1F72,
+ 0x1FC9 => 0x1F73,
+ 0x1FCA => 0x1F74,
+ 0x1FCB => 0x1F75,
+ 0x1FCC => 0x1FC3,
+ 0x1FD8 => 0x1FD0,
+ 0x1FD9 => 0x1FD1,
+ 0x1FDA => 0x1F76,
+ 0x1FDB => 0x1F77,
+ 0x1FE8 => 0x1FE0,
+ 0x1FE9 => 0x1FE1,
+ 0x1FEA => 0x1F7A,
+ 0x1FEB => 0x1F7B,
+ 0x1FEC => 0x1FE5,
+ 0x1FF8 => 0x1F78,
+ 0x1FF9 => 0x1F79,
+ 0x1FFA => 0x1F7C,
+ 0x1FFB => 0x1F7D,
+ 0x1FFC => 0x1FF3,
+ 0x2126 => 0x3C9,
+ 0x212A => 0x6B,
+ 0x212B => 0xE5,
+ 0x2132 => 0x214E,
+ 0x2160 => 0x2170,
+ 0x2161 => 0x2171,
+ 0x2162 => 0x2172,
+ 0x2163 => 0x2173,
+ 0x2164 => 0x2174,
+ 0x2165 => 0x2175,
+ 0x2166 => 0x2176,
+ 0x2167 => 0x2177,
+ 0x2168 => 0x2178,
+ 0x2169 => 0x2179,
+ 0x216A => 0x217A,
+ 0x216B => 0x217B,
+ 0x216C => 0x217C,
+ 0x216D => 0x217D,
+ 0x216E => 0x217E,
+ 0x216F => 0x217F,
+ 0x2183 => 0x2184,
+ 0x24B6 => 0x24D0,
+ 0x24B7 => 0x24D1,
+ 0x24B8 => 0x24D2,
+ 0x24B9 => 0x24D3,
+ 0x24BA => 0x24D4,
+ 0x24BB => 0x24D5,
+ 0x24BC => 0x24D6,
+ 0x24BD => 0x24D7,
+ 0x24BE => 0x24D8,
+ 0x24BF => 0x24D9,
+ 0x24C0 => 0x24DA,
+ 0x24C1 => 0x24DB,
+ 0x24C2 => 0x24DC,
+ 0x24C3 => 0x24DD,
+ 0x24C4 => 0x24DE,
+ 0x24C5 => 0x24DF,
+ 0x24C6 => 0x24E0,
+ 0x24C7 => 0x24E1,
+ 0x24C8 => 0x24E2,
+ 0x24C9 => 0x24E3,
+ 0x24CA => 0x24E4,
+ 0x24CB => 0x24E5,
+ 0x24CC => 0x24E6,
+ 0x24CD => 0x24E7,
+ 0x24CE => 0x24E8,
+ 0x24CF => 0x24E9,
+ 0x2C00 => 0x2C30,
+ 0x2C01 => 0x2C31,
+ 0x2C02 => 0x2C32,
+ 0x2C03 => 0x2C33,
+ 0x2C04 => 0x2C34,
+ 0x2C05 => 0x2C35,
+ 0x2C06 => 0x2C36,
+ 0x2C07 => 0x2C37,
+ 0x2C08 => 0x2C38,
+ 0x2C09 => 0x2C39,
+ 0x2C0A => 0x2C3A,
+ 0x2C0B => 0x2C3B,
+ 0x2C0C => 0x2C3C,
+ 0x2C0D => 0x2C3D,
+ 0x2C0E => 0x2C3E,
+ 0x2C0F => 0x2C3F,
+ 0x2C10 => 0x2C40,
+ 0x2C11 => 0x2C41,
+ 0x2C12 => 0x2C42,
+ 0x2C13 => 0x2C43,
+ 0x2C14 => 0x2C44,
+ 0x2C15 => 0x2C45,
+ 0x2C16 => 0x2C46,
+ 0x2C17 => 0x2C47,
+ 0x2C18 => 0x2C48,
+ 0x2C19 => 0x2C49,
+ 0x2C1A => 0x2C4A,
+ 0x2C1B => 0x2C4B,
+ 0x2C1C => 0x2C4C,
+ 0x2C1D => 0x2C4D,
+ 0x2C1E => 0x2C4E,
+ 0x2C1F => 0x2C4F,
+ 0x2C20 => 0x2C50,
+ 0x2C21 => 0x2C51,
+ 0x2C22 => 0x2C52,
+ 0x2C23 => 0x2C53,
+ 0x2C24 => 0x2C54,
+ 0x2C25 => 0x2C55,
+ 0x2C26 => 0x2C56,
+ 0x2C27 => 0x2C57,
+ 0x2C28 => 0x2C58,
+ 0x2C29 => 0x2C59,
+ 0x2C2A => 0x2C5A,
+ 0x2C2B => 0x2C5B,
+ 0x2C2C => 0x2C5C,
+ 0x2C2D => 0x2C5D,
+ 0x2C2E => 0x2C5E,
+ 0x2C60 => 0x2C61,
+ 0x2C62 => 0x26B,
+ 0x2C63 => 0x1D7D,
+ 0x2C64 => 0x27D,
+ 0x2C67 => 0x2C68,
+ 0x2C69 => 0x2C6A,
+ 0x2C6B => 0x2C6C,
+ 0x2C6D => 0x251,
+ 0x2C6E => 0x271,
+ 0x2C6F => 0x250,
+ 0x2C70 => 0x252,
+ 0x2C72 => 0x2C73,
+ 0x2C75 => 0x2C76,
+ 0x2C7E => 0x23F,
+ 0x2C7F => 0x240,
+ 0x2C80 => 0x2C81,
+ 0x2C82 => 0x2C83,
+ 0x2C84 => 0x2C85,
+ 0x2C86 => 0x2C87,
+ 0x2C88 => 0x2C89,
+ 0x2C8A => 0x2C8B,
+ 0x2C8C => 0x2C8D,
+ 0x2C8E => 0x2C8F,
+ 0x2C90 => 0x2C91,
+ 0x2C92 => 0x2C93,
+ 0x2C94 => 0x2C95,
+ 0x2C96 => 0x2C97,
+ 0x2C98 => 0x2C99,
+ 0x2C9A => 0x2C9B,
+ 0x2C9C => 0x2C9D,
+ 0x2C9E => 0x2C9F,
+ 0x2CA0 => 0x2CA1,
+ 0x2CA2 => 0x2CA3,
+ 0x2CA4 => 0x2CA5,
+ 0x2CA6 => 0x2CA7,
+ 0x2CA8 => 0x2CA9,
+ 0x2CAA => 0x2CAB,
+ 0x2CAC => 0x2CAD,
+ 0x2CAE => 0x2CAF,
+ 0x2CB0 => 0x2CB1,
+ 0x2CB2 => 0x2CB3,
+ 0x2CB4 => 0x2CB5,
+ 0x2CB6 => 0x2CB7,
+ 0x2CB8 => 0x2CB9,
+ 0x2CBA => 0x2CBB,
+ 0x2CBC => 0x2CBD,
+ 0x2CBE => 0x2CBF,
+ 0x2CC0 => 0x2CC1,
+ 0x2CC2 => 0x2CC3,
+ 0x2CC4 => 0x2CC5,
+ 0x2CC6 => 0x2CC7,
+ 0x2CC8 => 0x2CC9,
+ 0x2CCA => 0x2CCB,
+ 0x2CCC => 0x2CCD,
+ 0x2CCE => 0x2CCF,
+ 0x2CD0 => 0x2CD1,
+ 0x2CD2 => 0x2CD3,
+ 0x2CD4 => 0x2CD5,
+ 0x2CD6 => 0x2CD7,
+ 0x2CD8 => 0x2CD9,
+ 0x2CDA => 0x2CDB,
+ 0x2CDC => 0x2CDD,
+ 0x2CDE => 0x2CDF,
+ 0x2CE0 => 0x2CE1,
+ 0x2CE2 => 0x2CE3,
+ 0x2CEB => 0x2CEC,
+ 0x2CED => 0x2CEE,
+ 0x2CF2 => 0x2CF3,
+ 0xA640 => 0xA641,
+ 0xA642 => 0xA643,
+ 0xA644 => 0xA645,
+ 0xA646 => 0xA647,
+ 0xA648 => 0xA649,
+ 0xA64A => 0xA64B,
+ 0xA64C => 0xA64D,
+ 0xA64E => 0xA64F,
+ 0xA650 => 0xA651,
+ 0xA652 => 0xA653,
+ 0xA654 => 0xA655,
+ 0xA656 => 0xA657,
+ 0xA658 => 0xA659,
+ 0xA65A => 0xA65B,
+ 0xA65C => 0xA65D,
+ 0xA65E => 0xA65F,
+ 0xA660 => 0xA661,
+ 0xA662 => 0xA663,
+ 0xA664 => 0xA665,
+ 0xA666 => 0xA667,
+ 0xA668 => 0xA669,
+ 0xA66A => 0xA66B,
+ 0xA66C => 0xA66D,
+ 0xA680 => 0xA681,
+ 0xA682 => 0xA683,
+ 0xA684 => 0xA685,
+ 0xA686 => 0xA687,
+ 0xA688 => 0xA689,
+ 0xA68A => 0xA68B,
+ 0xA68C => 0xA68D,
+ 0xA68E => 0xA68F,
+ 0xA690 => 0xA691,
+ 0xA692 => 0xA693,
+ 0xA694 => 0xA695,
+ 0xA696 => 0xA697,
+ 0xA698 => 0xA699,
+ 0xA69A => 0xA69B,
+ 0xA722 => 0xA723,
+ 0xA724 => 0xA725,
+ 0xA726 => 0xA727,
+ 0xA728 => 0xA729,
+ 0xA72A => 0xA72B,
+ 0xA72C => 0xA72D,
+ 0xA72E => 0xA72F,
+ 0xA732 => 0xA733,
+ 0xA734 => 0xA735,
+ 0xA736 => 0xA737,
+ 0xA738 => 0xA739,
+ 0xA73A => 0xA73B,
+ 0xA73C => 0xA73D,
+ 0xA73E => 0xA73F,
+ 0xA740 => 0xA741,
+ 0xA742 => 0xA743,
+ 0xA744 => 0xA745,
+ 0xA746 => 0xA747,
+ 0xA748 => 0xA749,
+ 0xA74A => 0xA74B,
+ 0xA74C => 0xA74D,
+ 0xA74E => 0xA74F,
+ 0xA750 => 0xA751,
+ 0xA752 => 0xA753,
+ 0xA754 => 0xA755,
+ 0xA756 => 0xA757,
+ 0xA758 => 0xA759,
+ 0xA75A => 0xA75B,
+ 0xA75C => 0xA75D,
+ 0xA75E => 0xA75F,
+ 0xA760 => 0xA761,
+ 0xA762 => 0xA763,
+ 0xA764 => 0xA765,
+ 0xA766 => 0xA767,
+ 0xA768 => 0xA769,
+ 0xA76A => 0xA76B,
+ 0xA76C => 0xA76D,
+ 0xA76E => 0xA76F,
+ 0xA779 => 0xA77A,
+ 0xA77B => 0xA77C,
+ 0xA77D => 0x1D79,
+ 0xA77E => 0xA77F,
+ 0xA780 => 0xA781,
+ 0xA782 => 0xA783,
+ 0xA784 => 0xA785,
+ 0xA786 => 0xA787,
+ 0xA78B => 0xA78C,
+ 0xA78D => 0x265,
+ 0xA790 => 0xA791,
+ 0xA792 => 0xA793,
+ 0xA796 => 0xA797,
+ 0xA798 => 0xA799,
+ 0xA79A => 0xA79B,
+ 0xA79C => 0xA79D,
+ 0xA79E => 0xA79F,
+ 0xA7A0 => 0xA7A1,
+ 0xA7A2 => 0xA7A3,
+ 0xA7A4 => 0xA7A5,
+ 0xA7A6 => 0xA7A7,
+ 0xA7A8 => 0xA7A9,
+ 0xA7AA => 0x266,
+ 0xA7AB => 0x25C,
+ 0xA7AC => 0x261,
+ 0xA7AD => 0x26C,
+ 0xA7AE => 0x26A,
+ 0xA7B0 => 0x29E,
+ 0xA7B1 => 0x287,
+ 0xA7B2 => 0x29D,
+ 0xA7B3 => 0xAB53,
+ 0xA7B4 => 0xA7B5,
+ 0xA7B6 => 0xA7B7,
+ 0xA7B8 => 0xA7B9,
+ 0xA7BA => 0xA7BB,
+ 0xA7BC => 0xA7BD,
+ 0xA7BE => 0xA7BF,
+ 0xA7C2 => 0xA7C3,
+ 0xA7C4 => 0xA794,
+ 0xA7C5 => 0x282,
+ 0xA7C6 => 0x1D8E,
+ 0xA7C7 => 0xA7C8,
+ 0xA7C9 => 0xA7CA,
+ 0xA7F5 => 0xA7F6,
+ 0xFF21 => 0xFF41,
+ 0xFF22 => 0xFF42,
+ 0xFF23 => 0xFF43,
+ 0xFF24 => 0xFF44,
+ 0xFF25 => 0xFF45,
+ 0xFF26 => 0xFF46,
+ 0xFF27 => 0xFF47,
+ 0xFF28 => 0xFF48,
+ 0xFF29 => 0xFF49,
+ 0xFF2A => 0xFF4A,
+ 0xFF2B => 0xFF4B,
+ 0xFF2C => 0xFF4C,
+ 0xFF2D => 0xFF4D,
+ 0xFF2E => 0xFF4E,
+ 0xFF2F => 0xFF4F,
+ 0xFF30 => 0xFF50,
+ 0xFF31 => 0xFF51,
+ 0xFF32 => 0xFF52,
+ 0xFF33 => 0xFF53,
+ 0xFF34 => 0xFF54,
+ 0xFF35 => 0xFF55,
+ 0xFF36 => 0xFF56,
+ 0xFF37 => 0xFF57,
+ 0xFF38 => 0xFF58,
+ 0xFF39 => 0xFF59,
+ 0xFF3A => 0xFF5A,
+ 0x10400 => 0x10428,
+ 0x10401 => 0x10429,
+ 0x10402 => 0x1042A,
+ 0x10403 => 0x1042B,
+ 0x10404 => 0x1042C,
+ 0x10405 => 0x1042D,
+ 0x10406 => 0x1042E,
+ 0x10407 => 0x1042F,
+ 0x10408 => 0x10430,
+ 0x10409 => 0x10431,
+ 0x1040A => 0x10432,
+ 0x1040B => 0x10433,
+ 0x1040C => 0x10434,
+ 0x1040D => 0x10435,
+ 0x1040E => 0x10436,
+ 0x1040F => 0x10437,
+ 0x10410 => 0x10438,
+ 0x10411 => 0x10439,
+ 0x10412 => 0x1043A,
+ 0x10413 => 0x1043B,
+ 0x10414 => 0x1043C,
+ 0x10415 => 0x1043D,
+ 0x10416 => 0x1043E,
+ 0x10417 => 0x1043F,
+ 0x10418 => 0x10440,
+ 0x10419 => 0x10441,
+ 0x1041A => 0x10442,
+ 0x1041B => 0x10443,
+ 0x1041C => 0x10444,
+ 0x1041D => 0x10445,
+ 0x1041E => 0x10446,
+ 0x1041F => 0x10447,
+ 0x10420 => 0x10448,
+ 0x10421 => 0x10449,
+ 0x10422 => 0x1044A,
+ 0x10423 => 0x1044B,
+ 0x10424 => 0x1044C,
+ 0x10425 => 0x1044D,
+ 0x10426 => 0x1044E,
+ 0x10427 => 0x1044F,
+ 0x104B0 => 0x104D8,
+ 0x104B1 => 0x104D9,
+ 0x104B2 => 0x104DA,
+ 0x104B3 => 0x104DB,
+ 0x104B4 => 0x104DC,
+ 0x104B5 => 0x104DD,
+ 0x104B6 => 0x104DE,
+ 0x104B7 => 0x104DF,
+ 0x104B8 => 0x104E0,
+ 0x104B9 => 0x104E1,
+ 0x104BA => 0x104E2,
+ 0x104BB => 0x104E3,
+ 0x104BC => 0x104E4,
+ 0x104BD => 0x104E5,
+ 0x104BE => 0x104E6,
+ 0x104BF => 0x104E7,
+ 0x104C0 => 0x104E8,
+ 0x104C1 => 0x104E9,
+ 0x104C2 => 0x104EA,
+ 0x104C3 => 0x104EB,
+ 0x104C4 => 0x104EC,
+ 0x104C5 => 0x104ED,
+ 0x104C6 => 0x104EE,
+ 0x104C7 => 0x104EF,
+ 0x104C8 => 0x104F0,
+ 0x104C9 => 0x104F1,
+ 0x104CA => 0x104F2,
+ 0x104CB => 0x104F3,
+ 0x104CC => 0x104F4,
+ 0x104CD => 0x104F5,
+ 0x104CE => 0x104F6,
+ 0x104CF => 0x104F7,
+ 0x104D0 => 0x104F8,
+ 0x104D1 => 0x104F9,
+ 0x104D2 => 0x104FA,
+ 0x104D3 => 0x104FB,
+ 0x10C80 => 0x10CC0,
+ 0x10C81 => 0x10CC1,
+ 0x10C82 => 0x10CC2,
+ 0x10C83 => 0x10CC3,
+ 0x10C84 => 0x10CC4,
+ 0x10C85 => 0x10CC5,
+ 0x10C86 => 0x10CC6,
+ 0x10C87 => 0x10CC7,
+ 0x10C88 => 0x10CC8,
+ 0x10C89 => 0x10CC9,
+ 0x10C8A => 0x10CCA,
+ 0x10C8B => 0x10CCB,
+ 0x10C8C => 0x10CCC,
+ 0x10C8D => 0x10CCD,
+ 0x10C8E => 0x10CCE,
+ 0x10C8F => 0x10CCF,
+ 0x10C90 => 0x10CD0,
+ 0x10C91 => 0x10CD1,
+ 0x10C92 => 0x10CD2,
+ 0x10C93 => 0x10CD3,
+ 0x10C94 => 0x10CD4,
+ 0x10C95 => 0x10CD5,
+ 0x10C96 => 0x10CD6,
+ 0x10C97 => 0x10CD7,
+ 0x10C98 => 0x10CD8,
+ 0x10C99 => 0x10CD9,
+ 0x10C9A => 0x10CDA,
+ 0x10C9B => 0x10CDB,
+ 0x10C9C => 0x10CDC,
+ 0x10C9D => 0x10CDD,
+ 0x10C9E => 0x10CDE,
+ 0x10C9F => 0x10CDF,
+ 0x10CA0 => 0x10CE0,
+ 0x10CA1 => 0x10CE1,
+ 0x10CA2 => 0x10CE2,
+ 0x10CA3 => 0x10CE3,
+ 0x10CA4 => 0x10CE4,
+ 0x10CA5 => 0x10CE5,
+ 0x10CA6 => 0x10CE6,
+ 0x10CA7 => 0x10CE7,
+ 0x10CA8 => 0x10CE8,
+ 0x10CA9 => 0x10CE9,
+ 0x10CAA => 0x10CEA,
+ 0x10CAB => 0x10CEB,
+ 0x10CAC => 0x10CEC,
+ 0x10CAD => 0x10CED,
+ 0x10CAE => 0x10CEE,
+ 0x10CAF => 0x10CEF,
+ 0x10CB0 => 0x10CF0,
+ 0x10CB1 => 0x10CF1,
+ 0x10CB2 => 0x10CF2,
+ 0x118A0 => 0x118C0,
+ 0x118A1 => 0x118C1,
+ 0x118A2 => 0x118C2,
+ 0x118A3 => 0x118C3,
+ 0x118A4 => 0x118C4,
+ 0x118A5 => 0x118C5,
+ 0x118A6 => 0x118C6,
+ 0x118A7 => 0x118C7,
+ 0x118A8 => 0x118C8,
+ 0x118A9 => 0x118C9,
+ 0x118AA => 0x118CA,
+ 0x118AB => 0x118CB,
+ 0x118AC => 0x118CC,
+ 0x118AD => 0x118CD,
+ 0x118AE => 0x118CE,
+ 0x118AF => 0x118CF,
+ 0x118B0 => 0x118D0,
+ 0x118B1 => 0x118D1,
+ 0x118B2 => 0x118D2,
+ 0x118B3 => 0x118D3,
+ 0x118B4 => 0x118D4,
+ 0x118B5 => 0x118D5,
+ 0x118B6 => 0x118D6,
+ 0x118B7 => 0x118D7,
+ 0x118B8 => 0x118D8,
+ 0x118B9 => 0x118D9,
+ 0x118BA => 0x118DA,
+ 0x118BB => 0x118DB,
+ 0x118BC => 0x118DC,
+ 0x118BD => 0x118DD,
+ 0x118BE => 0x118DE,
+ 0x118BF => 0x118DF,
+ 0x16E40 => 0x16E60,
+ 0x16E41 => 0x16E61,
+ 0x16E42 => 0x16E62,
+ 0x16E43 => 0x16E63,
+ 0x16E44 => 0x16E64,
+ 0x16E45 => 0x16E65,
+ 0x16E46 => 0x16E66,
+ 0x16E47 => 0x16E67,
+ 0x16E48 => 0x16E68,
+ 0x16E49 => 0x16E69,
+ 0x16E4A => 0x16E6A,
+ 0x16E4B => 0x16E6B,
+ 0x16E4C => 0x16E6C,
+ 0x16E4D => 0x16E6D,
+ 0x16E4E => 0x16E6E,
+ 0x16E4F => 0x16E6F,
+ 0x16E50 => 0x16E70,
+ 0x16E51 => 0x16E71,
+ 0x16E52 => 0x16E72,
+ 0x16E53 => 0x16E73,
+ 0x16E54 => 0x16E74,
+ 0x16E55 => 0x16E75,
+ 0x16E56 => 0x16E76,
+ 0x16E57 => 0x16E77,
+ 0x16E58 => 0x16E78,
+ 0x16E59 => 0x16E79,
+ 0x16E5A => 0x16E7A,
+ 0x16E5B => 0x16E7B,
+ 0x16E5C => 0x16E7C,
+ 0x16E5D => 0x16E7D,
+ 0x16E5E => 0x16E7E,
+ 0x16E5F => 0x16E7F,
+ 0x1E900 => 0x1E922,
+ 0x1E901 => 0x1E923,
+ 0x1E902 => 0x1E924,
+ 0x1E903 => 0x1E925,
+ 0x1E904 => 0x1E926,
+ 0x1E905 => 0x1E927,
+ 0x1E906 => 0x1E928,
+ 0x1E907 => 0x1E929,
+ 0x1E908 => 0x1E92A,
+ 0x1E909 => 0x1E92B,
+ 0x1E90A => 0x1E92C,
+ 0x1E90B => 0x1E92D,
+ 0x1E90C => 0x1E92E,
+ 0x1E90D => 0x1E92F,
+ 0x1E90E => 0x1E930,
+ 0x1E90F => 0x1E931,
+ 0x1E910 => 0x1E932,
+ 0x1E911 => 0x1E933,
+ 0x1E912 => 0x1E934,
+ 0x1E913 => 0x1E935,
+ 0x1E914 => 0x1E936,
+ 0x1E915 => 0x1E937,
+ 0x1E916 => 0x1E938,
+ 0x1E917 => 0x1E939,
+ 0x1E918 => 0x1E93A,
+ 0x1E919 => 0x1E93B,
+ 0x1E91A => 0x1E93C,
+ 0x1E91B => 0x1E93D,
+ 0x1E91C => 0x1E93E,
+ 0x1E91D => 0x1E93F,
+ 0x1E91E => 0x1E940,
+ 0x1E91F => 0x1E941,
+ 0x1E920 => 0x1E942,
+ 0x1E921 => 0x1E943,
+);
diff --git a/src/opis/string/res/upper.php b/src/opis/string/res/upper.php
index 376ce6e6..549389a0 100644
--- a/src/opis/string/res/upper.php
+++ b/src/opis/string/res/upper.php
@@ -1,1413 +1,1413 @@
0x41,
-0x62 => 0x42,
-0x63 => 0x43,
-0x64 => 0x44,
-0x65 => 0x45,
-0x66 => 0x46,
-0x67 => 0x47,
-0x68 => 0x48,
-0x69 => 0x49,
-0x6A => 0x4A,
-0x6B => 0x4B,
-0x6C => 0x4C,
-0x6D => 0x4D,
-0x6E => 0x4E,
-0x6F => 0x4F,
-0x70 => 0x50,
-0x71 => 0x51,
-0x72 => 0x52,
-0x73 => 0x53,
-0x74 => 0x54,
-0x75 => 0x55,
-0x76 => 0x56,
-0x77 => 0x57,
-0x78 => 0x58,
-0x79 => 0x59,
-0x7A => 0x5A,
-0xB5 => 0x39C,
-0xE0 => 0xC0,
-0xE1 => 0xC1,
-0xE2 => 0xC2,
-0xE3 => 0xC3,
-0xE4 => 0xC4,
-0xE5 => 0xC5,
-0xE6 => 0xC6,
-0xE7 => 0xC7,
-0xE8 => 0xC8,
-0xE9 => 0xC9,
-0xEA => 0xCA,
-0xEB => 0xCB,
-0xEC => 0xCC,
-0xED => 0xCD,
-0xEE => 0xCE,
-0xEF => 0xCF,
-0xF0 => 0xD0,
-0xF1 => 0xD1,
-0xF2 => 0xD2,
-0xF3 => 0xD3,
-0xF4 => 0xD4,
-0xF5 => 0xD5,
-0xF6 => 0xD6,
-0xF8 => 0xD8,
-0xF9 => 0xD9,
-0xFA => 0xDA,
-0xFB => 0xDB,
-0xFC => 0xDC,
-0xFD => 0xDD,
-0xFE => 0xDE,
-0xFF => 0x178,
-0x101 => 0x100,
-0x103 => 0x102,
-0x105 => 0x104,
-0x107 => 0x106,
-0x109 => 0x108,
-0x10B => 0x10A,
-0x10D => 0x10C,
-0x10F => 0x10E,
-0x111 => 0x110,
-0x113 => 0x112,
-0x115 => 0x114,
-0x117 => 0x116,
-0x119 => 0x118,
-0x11B => 0x11A,
-0x11D => 0x11C,
-0x11F => 0x11E,
-0x121 => 0x120,
-0x123 => 0x122,
-0x125 => 0x124,
-0x127 => 0x126,
-0x129 => 0x128,
-0x12B => 0x12A,
-0x12D => 0x12C,
-0x12F => 0x12E,
-0x131 => 0x49,
-0x133 => 0x132,
-0x135 => 0x134,
-0x137 => 0x136,
-0x13A => 0x139,
-0x13C => 0x13B,
-0x13E => 0x13D,
-0x140 => 0x13F,
-0x142 => 0x141,
-0x144 => 0x143,
-0x146 => 0x145,
-0x148 => 0x147,
-0x14B => 0x14A,
-0x14D => 0x14C,
-0x14F => 0x14E,
-0x151 => 0x150,
-0x153 => 0x152,
-0x155 => 0x154,
-0x157 => 0x156,
-0x159 => 0x158,
-0x15B => 0x15A,
-0x15D => 0x15C,
-0x15F => 0x15E,
-0x161 => 0x160,
-0x163 => 0x162,
-0x165 => 0x164,
-0x167 => 0x166,
-0x169 => 0x168,
-0x16B => 0x16A,
-0x16D => 0x16C,
-0x16F => 0x16E,
-0x171 => 0x170,
-0x173 => 0x172,
-0x175 => 0x174,
-0x177 => 0x176,
-0x17A => 0x179,
-0x17C => 0x17B,
-0x17E => 0x17D,
-0x17F => 0x53,
-0x180 => 0x243,
-0x183 => 0x182,
-0x185 => 0x184,
-0x188 => 0x187,
-0x18C => 0x18B,
-0x192 => 0x191,
-0x195 => 0x1F6,
-0x199 => 0x198,
-0x19A => 0x23D,
-0x19E => 0x220,
-0x1A1 => 0x1A0,
-0x1A3 => 0x1A2,
-0x1A5 => 0x1A4,
-0x1A8 => 0x1A7,
-0x1AD => 0x1AC,
-0x1B0 => 0x1AF,
-0x1B4 => 0x1B3,
-0x1B6 => 0x1B5,
-0x1B9 => 0x1B8,
-0x1BD => 0x1BC,
-0x1BF => 0x1F7,
-0x1C5 => 0x1C4,
-0x1C6 => 0x1C4,
-0x1C8 => 0x1C7,
-0x1C9 => 0x1C7,
-0x1CB => 0x1CA,
-0x1CC => 0x1CA,
-0x1CE => 0x1CD,
-0x1D0 => 0x1CF,
-0x1D2 => 0x1D1,
-0x1D4 => 0x1D3,
-0x1D6 => 0x1D5,
-0x1D8 => 0x1D7,
-0x1DA => 0x1D9,
-0x1DC => 0x1DB,
-0x1DD => 0x18E,
-0x1DF => 0x1DE,
-0x1E1 => 0x1E0,
-0x1E3 => 0x1E2,
-0x1E5 => 0x1E4,
-0x1E7 => 0x1E6,
-0x1E9 => 0x1E8,
-0x1EB => 0x1EA,
-0x1ED => 0x1EC,
-0x1EF => 0x1EE,
-0x1F2 => 0x1F1,
-0x1F3 => 0x1F1,
-0x1F5 => 0x1F4,
-0x1F9 => 0x1F8,
-0x1FB => 0x1FA,
-0x1FD => 0x1FC,
-0x1FF => 0x1FE,
-0x201 => 0x200,
-0x203 => 0x202,
-0x205 => 0x204,
-0x207 => 0x206,
-0x209 => 0x208,
-0x20B => 0x20A,
-0x20D => 0x20C,
-0x20F => 0x20E,
-0x211 => 0x210,
-0x213 => 0x212,
-0x215 => 0x214,
-0x217 => 0x216,
-0x219 => 0x218,
-0x21B => 0x21A,
-0x21D => 0x21C,
-0x21F => 0x21E,
-0x223 => 0x222,
-0x225 => 0x224,
-0x227 => 0x226,
-0x229 => 0x228,
-0x22B => 0x22A,
-0x22D => 0x22C,
-0x22F => 0x22E,
-0x231 => 0x230,
-0x233 => 0x232,
-0x23C => 0x23B,
-0x23F => 0x2C7E,
-0x240 => 0x2C7F,
-0x242 => 0x241,
-0x247 => 0x246,
-0x249 => 0x248,
-0x24B => 0x24A,
-0x24D => 0x24C,
-0x24F => 0x24E,
-0x250 => 0x2C6F,
-0x251 => 0x2C6D,
-0x252 => 0x2C70,
-0x253 => 0x181,
-0x254 => 0x186,
-0x256 => 0x189,
-0x257 => 0x18A,
-0x259 => 0x18F,
-0x25B => 0x190,
-0x25C => 0xA7AB,
-0x260 => 0x193,
-0x261 => 0xA7AC,
-0x263 => 0x194,
-0x265 => 0xA78D,
-0x266 => 0xA7AA,
-0x268 => 0x197,
-0x269 => 0x196,
-0x26A => 0xA7AE,
-0x26B => 0x2C62,
-0x26C => 0xA7AD,
-0x26F => 0x19C,
-0x271 => 0x2C6E,
-0x272 => 0x19D,
-0x275 => 0x19F,
-0x27D => 0x2C64,
-0x280 => 0x1A6,
-0x282 => 0xA7C5,
-0x283 => 0x1A9,
-0x287 => 0xA7B1,
-0x288 => 0x1AE,
-0x289 => 0x244,
-0x28A => 0x1B1,
-0x28B => 0x1B2,
-0x28C => 0x245,
-0x292 => 0x1B7,
-0x29D => 0xA7B2,
-0x29E => 0xA7B0,
-0x345 => 0x399,
-0x371 => 0x370,
-0x373 => 0x372,
-0x377 => 0x376,
-0x37B => 0x3FD,
-0x37C => 0x3FE,
-0x37D => 0x3FF,
-0x3AC => 0x386,
-0x3AD => 0x388,
-0x3AE => 0x389,
-0x3AF => 0x38A,
-0x3B1 => 0x391,
-0x3B2 => 0x392,
-0x3B3 => 0x393,
-0x3B4 => 0x394,
-0x3B5 => 0x395,
-0x3B6 => 0x396,
-0x3B7 => 0x397,
-0x3B8 => 0x398,
-0x3B9 => 0x399,
-0x3BA => 0x39A,
-0x3BB => 0x39B,
-0x3BC => 0x39C,
-0x3BD => 0x39D,
-0x3BE => 0x39E,
-0x3BF => 0x39F,
-0x3C0 => 0x3A0,
-0x3C1 => 0x3A1,
-0x3C2 => 0x3A3,
-0x3C3 => 0x3A3,
-0x3C4 => 0x3A4,
-0x3C5 => 0x3A5,
-0x3C6 => 0x3A6,
-0x3C7 => 0x3A7,
-0x3C8 => 0x3A8,
-0x3C9 => 0x3A9,
-0x3CA => 0x3AA,
-0x3CB => 0x3AB,
-0x3CC => 0x38C,
-0x3CD => 0x38E,
-0x3CE => 0x38F,
-0x3D0 => 0x392,
-0x3D1 => 0x398,
-0x3D5 => 0x3A6,
-0x3D6 => 0x3A0,
-0x3D7 => 0x3CF,
-0x3D9 => 0x3D8,
-0x3DB => 0x3DA,
-0x3DD => 0x3DC,
-0x3DF => 0x3DE,
-0x3E1 => 0x3E0,
-0x3E3 => 0x3E2,
-0x3E5 => 0x3E4,
-0x3E7 => 0x3E6,
-0x3E9 => 0x3E8,
-0x3EB => 0x3EA,
-0x3ED => 0x3EC,
-0x3EF => 0x3EE,
-0x3F0 => 0x39A,
-0x3F1 => 0x3A1,
-0x3F2 => 0x3F9,
-0x3F3 => 0x37F,
-0x3F5 => 0x395,
-0x3F8 => 0x3F7,
-0x3FB => 0x3FA,
-0x430 => 0x410,
-0x431 => 0x411,
-0x432 => 0x412,
-0x433 => 0x413,
-0x434 => 0x414,
-0x435 => 0x415,
-0x436 => 0x416,
-0x437 => 0x417,
-0x438 => 0x418,
-0x439 => 0x419,
-0x43A => 0x41A,
-0x43B => 0x41B,
-0x43C => 0x41C,
-0x43D => 0x41D,
-0x43E => 0x41E,
-0x43F => 0x41F,
-0x440 => 0x420,
-0x441 => 0x421,
-0x442 => 0x422,
-0x443 => 0x423,
-0x444 => 0x424,
-0x445 => 0x425,
-0x446 => 0x426,
-0x447 => 0x427,
-0x448 => 0x428,
-0x449 => 0x429,
-0x44A => 0x42A,
-0x44B => 0x42B,
-0x44C => 0x42C,
-0x44D => 0x42D,
-0x44E => 0x42E,
-0x44F => 0x42F,
-0x450 => 0x400,
-0x451 => 0x401,
-0x452 => 0x402,
-0x453 => 0x403,
-0x454 => 0x404,
-0x455 => 0x405,
-0x456 => 0x406,
-0x457 => 0x407,
-0x458 => 0x408,
-0x459 => 0x409,
-0x45A => 0x40A,
-0x45B => 0x40B,
-0x45C => 0x40C,
-0x45D => 0x40D,
-0x45E => 0x40E,
-0x45F => 0x40F,
-0x461 => 0x460,
-0x463 => 0x462,
-0x465 => 0x464,
-0x467 => 0x466,
-0x469 => 0x468,
-0x46B => 0x46A,
-0x46D => 0x46C,
-0x46F => 0x46E,
-0x471 => 0x470,
-0x473 => 0x472,
-0x475 => 0x474,
-0x477 => 0x476,
-0x479 => 0x478,
-0x47B => 0x47A,
-0x47D => 0x47C,
-0x47F => 0x47E,
-0x481 => 0x480,
-0x48B => 0x48A,
-0x48D => 0x48C,
-0x48F => 0x48E,
-0x491 => 0x490,
-0x493 => 0x492,
-0x495 => 0x494,
-0x497 => 0x496,
-0x499 => 0x498,
-0x49B => 0x49A,
-0x49D => 0x49C,
-0x49F => 0x49E,
-0x4A1 => 0x4A0,
-0x4A3 => 0x4A2,
-0x4A5 => 0x4A4,
-0x4A7 => 0x4A6,
-0x4A9 => 0x4A8,
-0x4AB => 0x4AA,
-0x4AD => 0x4AC,
-0x4AF => 0x4AE,
-0x4B1 => 0x4B0,
-0x4B3 => 0x4B2,
-0x4B5 => 0x4B4,
-0x4B7 => 0x4B6,
-0x4B9 => 0x4B8,
-0x4BB => 0x4BA,
-0x4BD => 0x4BC,
-0x4BF => 0x4BE,
-0x4C2 => 0x4C1,
-0x4C4 => 0x4C3,
-0x4C6 => 0x4C5,
-0x4C8 => 0x4C7,
-0x4CA => 0x4C9,
-0x4CC => 0x4CB,
-0x4CE => 0x4CD,
-0x4CF => 0x4C0,
-0x4D1 => 0x4D0,
-0x4D3 => 0x4D2,
-0x4D5 => 0x4D4,
-0x4D7 => 0x4D6,
-0x4D9 => 0x4D8,
-0x4DB => 0x4DA,
-0x4DD => 0x4DC,
-0x4DF => 0x4DE,
-0x4E1 => 0x4E0,
-0x4E3 => 0x4E2,
-0x4E5 => 0x4E4,
-0x4E7 => 0x4E6,
-0x4E9 => 0x4E8,
-0x4EB => 0x4EA,
-0x4ED => 0x4EC,
-0x4EF => 0x4EE,
-0x4F1 => 0x4F0,
-0x4F3 => 0x4F2,
-0x4F5 => 0x4F4,
-0x4F7 => 0x4F6,
-0x4F9 => 0x4F8,
-0x4FB => 0x4FA,
-0x4FD => 0x4FC,
-0x4FF => 0x4FE,
-0x501 => 0x500,
-0x503 => 0x502,
-0x505 => 0x504,
-0x507 => 0x506,
-0x509 => 0x508,
-0x50B => 0x50A,
-0x50D => 0x50C,
-0x50F => 0x50E,
-0x511 => 0x510,
-0x513 => 0x512,
-0x515 => 0x514,
-0x517 => 0x516,
-0x519 => 0x518,
-0x51B => 0x51A,
-0x51D => 0x51C,
-0x51F => 0x51E,
-0x521 => 0x520,
-0x523 => 0x522,
-0x525 => 0x524,
-0x527 => 0x526,
-0x529 => 0x528,
-0x52B => 0x52A,
-0x52D => 0x52C,
-0x52F => 0x52E,
-0x561 => 0x531,
-0x562 => 0x532,
-0x563 => 0x533,
-0x564 => 0x534,
-0x565 => 0x535,
-0x566 => 0x536,
-0x567 => 0x537,
-0x568 => 0x538,
-0x569 => 0x539,
-0x56A => 0x53A,
-0x56B => 0x53B,
-0x56C => 0x53C,
-0x56D => 0x53D,
-0x56E => 0x53E,
-0x56F => 0x53F,
-0x570 => 0x540,
-0x571 => 0x541,
-0x572 => 0x542,
-0x573 => 0x543,
-0x574 => 0x544,
-0x575 => 0x545,
-0x576 => 0x546,
-0x577 => 0x547,
-0x578 => 0x548,
-0x579 => 0x549,
-0x57A => 0x54A,
-0x57B => 0x54B,
-0x57C => 0x54C,
-0x57D => 0x54D,
-0x57E => 0x54E,
-0x57F => 0x54F,
-0x580 => 0x550,
-0x581 => 0x551,
-0x582 => 0x552,
-0x583 => 0x553,
-0x584 => 0x554,
-0x585 => 0x555,
-0x586 => 0x556,
-0x10D0 => 0x1C90,
-0x10D1 => 0x1C91,
-0x10D2 => 0x1C92,
-0x10D3 => 0x1C93,
-0x10D4 => 0x1C94,
-0x10D5 => 0x1C95,
-0x10D6 => 0x1C96,
-0x10D7 => 0x1C97,
-0x10D8 => 0x1C98,
-0x10D9 => 0x1C99,
-0x10DA => 0x1C9A,
-0x10DB => 0x1C9B,
-0x10DC => 0x1C9C,
-0x10DD => 0x1C9D,
-0x10DE => 0x1C9E,
-0x10DF => 0x1C9F,
-0x10E0 => 0x1CA0,
-0x10E1 => 0x1CA1,
-0x10E2 => 0x1CA2,
-0x10E3 => 0x1CA3,
-0x10E4 => 0x1CA4,
-0x10E5 => 0x1CA5,
-0x10E6 => 0x1CA6,
-0x10E7 => 0x1CA7,
-0x10E8 => 0x1CA8,
-0x10E9 => 0x1CA9,
-0x10EA => 0x1CAA,
-0x10EB => 0x1CAB,
-0x10EC => 0x1CAC,
-0x10ED => 0x1CAD,
-0x10EE => 0x1CAE,
-0x10EF => 0x1CAF,
-0x10F0 => 0x1CB0,
-0x10F1 => 0x1CB1,
-0x10F2 => 0x1CB2,
-0x10F3 => 0x1CB3,
-0x10F4 => 0x1CB4,
-0x10F5 => 0x1CB5,
-0x10F6 => 0x1CB6,
-0x10F7 => 0x1CB7,
-0x10F8 => 0x1CB8,
-0x10F9 => 0x1CB9,
-0x10FA => 0x1CBA,
-0x10FD => 0x1CBD,
-0x10FE => 0x1CBE,
-0x10FF => 0x1CBF,
-0x13F8 => 0x13F0,
-0x13F9 => 0x13F1,
-0x13FA => 0x13F2,
-0x13FB => 0x13F3,
-0x13FC => 0x13F4,
-0x13FD => 0x13F5,
-0x1C80 => 0x412,
-0x1C81 => 0x414,
-0x1C82 => 0x41E,
-0x1C83 => 0x421,
-0x1C84 => 0x422,
-0x1C85 => 0x422,
-0x1C86 => 0x42A,
-0x1C87 => 0x462,
-0x1C88 => 0xA64A,
-0x1D79 => 0xA77D,
-0x1D7D => 0x2C63,
-0x1D8E => 0xA7C6,
-0x1E01 => 0x1E00,
-0x1E03 => 0x1E02,
-0x1E05 => 0x1E04,
-0x1E07 => 0x1E06,
-0x1E09 => 0x1E08,
-0x1E0B => 0x1E0A,
-0x1E0D => 0x1E0C,
-0x1E0F => 0x1E0E,
-0x1E11 => 0x1E10,
-0x1E13 => 0x1E12,
-0x1E15 => 0x1E14,
-0x1E17 => 0x1E16,
-0x1E19 => 0x1E18,
-0x1E1B => 0x1E1A,
-0x1E1D => 0x1E1C,
-0x1E1F => 0x1E1E,
-0x1E21 => 0x1E20,
-0x1E23 => 0x1E22,
-0x1E25 => 0x1E24,
-0x1E27 => 0x1E26,
-0x1E29 => 0x1E28,
-0x1E2B => 0x1E2A,
-0x1E2D => 0x1E2C,
-0x1E2F => 0x1E2E,
-0x1E31 => 0x1E30,
-0x1E33 => 0x1E32,
-0x1E35 => 0x1E34,
-0x1E37 => 0x1E36,
-0x1E39 => 0x1E38,
-0x1E3B => 0x1E3A,
-0x1E3D => 0x1E3C,
-0x1E3F => 0x1E3E,
-0x1E41 => 0x1E40,
-0x1E43 => 0x1E42,
-0x1E45 => 0x1E44,
-0x1E47 => 0x1E46,
-0x1E49 => 0x1E48,
-0x1E4B => 0x1E4A,
-0x1E4D => 0x1E4C,
-0x1E4F => 0x1E4E,
-0x1E51 => 0x1E50,
-0x1E53 => 0x1E52,
-0x1E55 => 0x1E54,
-0x1E57 => 0x1E56,
-0x1E59 => 0x1E58,
-0x1E5B => 0x1E5A,
-0x1E5D => 0x1E5C,
-0x1E5F => 0x1E5E,
-0x1E61 => 0x1E60,
-0x1E63 => 0x1E62,
-0x1E65 => 0x1E64,
-0x1E67 => 0x1E66,
-0x1E69 => 0x1E68,
-0x1E6B => 0x1E6A,
-0x1E6D => 0x1E6C,
-0x1E6F => 0x1E6E,
-0x1E71 => 0x1E70,
-0x1E73 => 0x1E72,
-0x1E75 => 0x1E74,
-0x1E77 => 0x1E76,
-0x1E79 => 0x1E78,
-0x1E7B => 0x1E7A,
-0x1E7D => 0x1E7C,
-0x1E7F => 0x1E7E,
-0x1E81 => 0x1E80,
-0x1E83 => 0x1E82,
-0x1E85 => 0x1E84,
-0x1E87 => 0x1E86,
-0x1E89 => 0x1E88,
-0x1E8B => 0x1E8A,
-0x1E8D => 0x1E8C,
-0x1E8F => 0x1E8E,
-0x1E91 => 0x1E90,
-0x1E93 => 0x1E92,
-0x1E95 => 0x1E94,
-0x1E9B => 0x1E60,
-0x1EA1 => 0x1EA0,
-0x1EA3 => 0x1EA2,
-0x1EA5 => 0x1EA4,
-0x1EA7 => 0x1EA6,
-0x1EA9 => 0x1EA8,
-0x1EAB => 0x1EAA,
-0x1EAD => 0x1EAC,
-0x1EAF => 0x1EAE,
-0x1EB1 => 0x1EB0,
-0x1EB3 => 0x1EB2,
-0x1EB5 => 0x1EB4,
-0x1EB7 => 0x1EB6,
-0x1EB9 => 0x1EB8,
-0x1EBB => 0x1EBA,
-0x1EBD => 0x1EBC,
-0x1EBF => 0x1EBE,
-0x1EC1 => 0x1EC0,
-0x1EC3 => 0x1EC2,
-0x1EC5 => 0x1EC4,
-0x1EC7 => 0x1EC6,
-0x1EC9 => 0x1EC8,
-0x1ECB => 0x1ECA,
-0x1ECD => 0x1ECC,
-0x1ECF => 0x1ECE,
-0x1ED1 => 0x1ED0,
-0x1ED3 => 0x1ED2,
-0x1ED5 => 0x1ED4,
-0x1ED7 => 0x1ED6,
-0x1ED9 => 0x1ED8,
-0x1EDB => 0x1EDA,
-0x1EDD => 0x1EDC,
-0x1EDF => 0x1EDE,
-0x1EE1 => 0x1EE0,
-0x1EE3 => 0x1EE2,
-0x1EE5 => 0x1EE4,
-0x1EE7 => 0x1EE6,
-0x1EE9 => 0x1EE8,
-0x1EEB => 0x1EEA,
-0x1EED => 0x1EEC,
-0x1EEF => 0x1EEE,
-0x1EF1 => 0x1EF0,
-0x1EF3 => 0x1EF2,
-0x1EF5 => 0x1EF4,
-0x1EF7 => 0x1EF6,
-0x1EF9 => 0x1EF8,
-0x1EFB => 0x1EFA,
-0x1EFD => 0x1EFC,
-0x1EFF => 0x1EFE,
-0x1F00 => 0x1F08,
-0x1F01 => 0x1F09,
-0x1F02 => 0x1F0A,
-0x1F03 => 0x1F0B,
-0x1F04 => 0x1F0C,
-0x1F05 => 0x1F0D,
-0x1F06 => 0x1F0E,
-0x1F07 => 0x1F0F,
-0x1F10 => 0x1F18,
-0x1F11 => 0x1F19,
-0x1F12 => 0x1F1A,
-0x1F13 => 0x1F1B,
-0x1F14 => 0x1F1C,
-0x1F15 => 0x1F1D,
-0x1F20 => 0x1F28,
-0x1F21 => 0x1F29,
-0x1F22 => 0x1F2A,
-0x1F23 => 0x1F2B,
-0x1F24 => 0x1F2C,
-0x1F25 => 0x1F2D,
-0x1F26 => 0x1F2E,
-0x1F27 => 0x1F2F,
-0x1F30 => 0x1F38,
-0x1F31 => 0x1F39,
-0x1F32 => 0x1F3A,
-0x1F33 => 0x1F3B,
-0x1F34 => 0x1F3C,
-0x1F35 => 0x1F3D,
-0x1F36 => 0x1F3E,
-0x1F37 => 0x1F3F,
-0x1F40 => 0x1F48,
-0x1F41 => 0x1F49,
-0x1F42 => 0x1F4A,
-0x1F43 => 0x1F4B,
-0x1F44 => 0x1F4C,
-0x1F45 => 0x1F4D,
-0x1F51 => 0x1F59,
-0x1F53 => 0x1F5B,
-0x1F55 => 0x1F5D,
-0x1F57 => 0x1F5F,
-0x1F60 => 0x1F68,
-0x1F61 => 0x1F69,
-0x1F62 => 0x1F6A,
-0x1F63 => 0x1F6B,
-0x1F64 => 0x1F6C,
-0x1F65 => 0x1F6D,
-0x1F66 => 0x1F6E,
-0x1F67 => 0x1F6F,
-0x1F70 => 0x1FBA,
-0x1F71 => 0x1FBB,
-0x1F72 => 0x1FC8,
-0x1F73 => 0x1FC9,
-0x1F74 => 0x1FCA,
-0x1F75 => 0x1FCB,
-0x1F76 => 0x1FDA,
-0x1F77 => 0x1FDB,
-0x1F78 => 0x1FF8,
-0x1F79 => 0x1FF9,
-0x1F7A => 0x1FEA,
-0x1F7B => 0x1FEB,
-0x1F7C => 0x1FFA,
-0x1F7D => 0x1FFB,
-0x1F80 => 0x1F88,
-0x1F81 => 0x1F89,
-0x1F82 => 0x1F8A,
-0x1F83 => 0x1F8B,
-0x1F84 => 0x1F8C,
-0x1F85 => 0x1F8D,
-0x1F86 => 0x1F8E,
-0x1F87 => 0x1F8F,
-0x1F90 => 0x1F98,
-0x1F91 => 0x1F99,
-0x1F92 => 0x1F9A,
-0x1F93 => 0x1F9B,
-0x1F94 => 0x1F9C,
-0x1F95 => 0x1F9D,
-0x1F96 => 0x1F9E,
-0x1F97 => 0x1F9F,
-0x1FA0 => 0x1FA8,
-0x1FA1 => 0x1FA9,
-0x1FA2 => 0x1FAA,
-0x1FA3 => 0x1FAB,
-0x1FA4 => 0x1FAC,
-0x1FA5 => 0x1FAD,
-0x1FA6 => 0x1FAE,
-0x1FA7 => 0x1FAF,
-0x1FB0 => 0x1FB8,
-0x1FB1 => 0x1FB9,
-0x1FB3 => 0x1FBC,
-0x1FBE => 0x399,
-0x1FC3 => 0x1FCC,
-0x1FD0 => 0x1FD8,
-0x1FD1 => 0x1FD9,
-0x1FE0 => 0x1FE8,
-0x1FE1 => 0x1FE9,
-0x1FE5 => 0x1FEC,
-0x1FF3 => 0x1FFC,
-0x214E => 0x2132,
-0x2170 => 0x2160,
-0x2171 => 0x2161,
-0x2172 => 0x2162,
-0x2173 => 0x2163,
-0x2174 => 0x2164,
-0x2175 => 0x2165,
-0x2176 => 0x2166,
-0x2177 => 0x2167,
-0x2178 => 0x2168,
-0x2179 => 0x2169,
-0x217A => 0x216A,
-0x217B => 0x216B,
-0x217C => 0x216C,
-0x217D => 0x216D,
-0x217E => 0x216E,
-0x217F => 0x216F,
-0x2184 => 0x2183,
-0x24D0 => 0x24B6,
-0x24D1 => 0x24B7,
-0x24D2 => 0x24B8,
-0x24D3 => 0x24B9,
-0x24D4 => 0x24BA,
-0x24D5 => 0x24BB,
-0x24D6 => 0x24BC,
-0x24D7 => 0x24BD,
-0x24D8 => 0x24BE,
-0x24D9 => 0x24BF,
-0x24DA => 0x24C0,
-0x24DB => 0x24C1,
-0x24DC => 0x24C2,
-0x24DD => 0x24C3,
-0x24DE => 0x24C4,
-0x24DF => 0x24C5,
-0x24E0 => 0x24C6,
-0x24E1 => 0x24C7,
-0x24E2 => 0x24C8,
-0x24E3 => 0x24C9,
-0x24E4 => 0x24CA,
-0x24E5 => 0x24CB,
-0x24E6 => 0x24CC,
-0x24E7 => 0x24CD,
-0x24E8 => 0x24CE,
-0x24E9 => 0x24CF,
-0x2C30 => 0x2C00,
-0x2C31 => 0x2C01,
-0x2C32 => 0x2C02,
-0x2C33 => 0x2C03,
-0x2C34 => 0x2C04,
-0x2C35 => 0x2C05,
-0x2C36 => 0x2C06,
-0x2C37 => 0x2C07,
-0x2C38 => 0x2C08,
-0x2C39 => 0x2C09,
-0x2C3A => 0x2C0A,
-0x2C3B => 0x2C0B,
-0x2C3C => 0x2C0C,
-0x2C3D => 0x2C0D,
-0x2C3E => 0x2C0E,
-0x2C3F => 0x2C0F,
-0x2C40 => 0x2C10,
-0x2C41 => 0x2C11,
-0x2C42 => 0x2C12,
-0x2C43 => 0x2C13,
-0x2C44 => 0x2C14,
-0x2C45 => 0x2C15,
-0x2C46 => 0x2C16,
-0x2C47 => 0x2C17,
-0x2C48 => 0x2C18,
-0x2C49 => 0x2C19,
-0x2C4A => 0x2C1A,
-0x2C4B => 0x2C1B,
-0x2C4C => 0x2C1C,
-0x2C4D => 0x2C1D,
-0x2C4E => 0x2C1E,
-0x2C4F => 0x2C1F,
-0x2C50 => 0x2C20,
-0x2C51 => 0x2C21,
-0x2C52 => 0x2C22,
-0x2C53 => 0x2C23,
-0x2C54 => 0x2C24,
-0x2C55 => 0x2C25,
-0x2C56 => 0x2C26,
-0x2C57 => 0x2C27,
-0x2C58 => 0x2C28,
-0x2C59 => 0x2C29,
-0x2C5A => 0x2C2A,
-0x2C5B => 0x2C2B,
-0x2C5C => 0x2C2C,
-0x2C5D => 0x2C2D,
-0x2C5E => 0x2C2E,
-0x2C61 => 0x2C60,
-0x2C65 => 0x23A,
-0x2C66 => 0x23E,
-0x2C68 => 0x2C67,
-0x2C6A => 0x2C69,
-0x2C6C => 0x2C6B,
-0x2C73 => 0x2C72,
-0x2C76 => 0x2C75,
-0x2C81 => 0x2C80,
-0x2C83 => 0x2C82,
-0x2C85 => 0x2C84,
-0x2C87 => 0x2C86,
-0x2C89 => 0x2C88,
-0x2C8B => 0x2C8A,
-0x2C8D => 0x2C8C,
-0x2C8F => 0x2C8E,
-0x2C91 => 0x2C90,
-0x2C93 => 0x2C92,
-0x2C95 => 0x2C94,
-0x2C97 => 0x2C96,
-0x2C99 => 0x2C98,
-0x2C9B => 0x2C9A,
-0x2C9D => 0x2C9C,
-0x2C9F => 0x2C9E,
-0x2CA1 => 0x2CA0,
-0x2CA3 => 0x2CA2,
-0x2CA5 => 0x2CA4,
-0x2CA7 => 0x2CA6,
-0x2CA9 => 0x2CA8,
-0x2CAB => 0x2CAA,
-0x2CAD => 0x2CAC,
-0x2CAF => 0x2CAE,
-0x2CB1 => 0x2CB0,
-0x2CB3 => 0x2CB2,
-0x2CB5 => 0x2CB4,
-0x2CB7 => 0x2CB6,
-0x2CB9 => 0x2CB8,
-0x2CBB => 0x2CBA,
-0x2CBD => 0x2CBC,
-0x2CBF => 0x2CBE,
-0x2CC1 => 0x2CC0,
-0x2CC3 => 0x2CC2,
-0x2CC5 => 0x2CC4,
-0x2CC7 => 0x2CC6,
-0x2CC9 => 0x2CC8,
-0x2CCB => 0x2CCA,
-0x2CCD => 0x2CCC,
-0x2CCF => 0x2CCE,
-0x2CD1 => 0x2CD0,
-0x2CD3 => 0x2CD2,
-0x2CD5 => 0x2CD4,
-0x2CD7 => 0x2CD6,
-0x2CD9 => 0x2CD8,
-0x2CDB => 0x2CDA,
-0x2CDD => 0x2CDC,
-0x2CDF => 0x2CDE,
-0x2CE1 => 0x2CE0,
-0x2CE3 => 0x2CE2,
-0x2CEC => 0x2CEB,
-0x2CEE => 0x2CED,
-0x2CF3 => 0x2CF2,
-0x2D00 => 0x10A0,
-0x2D01 => 0x10A1,
-0x2D02 => 0x10A2,
-0x2D03 => 0x10A3,
-0x2D04 => 0x10A4,
-0x2D05 => 0x10A5,
-0x2D06 => 0x10A6,
-0x2D07 => 0x10A7,
-0x2D08 => 0x10A8,
-0x2D09 => 0x10A9,
-0x2D0A => 0x10AA,
-0x2D0B => 0x10AB,
-0x2D0C => 0x10AC,
-0x2D0D => 0x10AD,
-0x2D0E => 0x10AE,
-0x2D0F => 0x10AF,
-0x2D10 => 0x10B0,
-0x2D11 => 0x10B1,
-0x2D12 => 0x10B2,
-0x2D13 => 0x10B3,
-0x2D14 => 0x10B4,
-0x2D15 => 0x10B5,
-0x2D16 => 0x10B6,
-0x2D17 => 0x10B7,
-0x2D18 => 0x10B8,
-0x2D19 => 0x10B9,
-0x2D1A => 0x10BA,
-0x2D1B => 0x10BB,
-0x2D1C => 0x10BC,
-0x2D1D => 0x10BD,
-0x2D1E => 0x10BE,
-0x2D1F => 0x10BF,
-0x2D20 => 0x10C0,
-0x2D21 => 0x10C1,
-0x2D22 => 0x10C2,
-0x2D23 => 0x10C3,
-0x2D24 => 0x10C4,
-0x2D25 => 0x10C5,
-0x2D27 => 0x10C7,
-0x2D2D => 0x10CD,
-0xA641 => 0xA640,
-0xA643 => 0xA642,
-0xA645 => 0xA644,
-0xA647 => 0xA646,
-0xA649 => 0xA648,
-0xA64B => 0xA64A,
-0xA64D => 0xA64C,
-0xA64F => 0xA64E,
-0xA651 => 0xA650,
-0xA653 => 0xA652,
-0xA655 => 0xA654,
-0xA657 => 0xA656,
-0xA659 => 0xA658,
-0xA65B => 0xA65A,
-0xA65D => 0xA65C,
-0xA65F => 0xA65E,
-0xA661 => 0xA660,
-0xA663 => 0xA662,
-0xA665 => 0xA664,
-0xA667 => 0xA666,
-0xA669 => 0xA668,
-0xA66B => 0xA66A,
-0xA66D => 0xA66C,
-0xA681 => 0xA680,
-0xA683 => 0xA682,
-0xA685 => 0xA684,
-0xA687 => 0xA686,
-0xA689 => 0xA688,
-0xA68B => 0xA68A,
-0xA68D => 0xA68C,
-0xA68F => 0xA68E,
-0xA691 => 0xA690,
-0xA693 => 0xA692,
-0xA695 => 0xA694,
-0xA697 => 0xA696,
-0xA699 => 0xA698,
-0xA69B => 0xA69A,
-0xA723 => 0xA722,
-0xA725 => 0xA724,
-0xA727 => 0xA726,
-0xA729 => 0xA728,
-0xA72B => 0xA72A,
-0xA72D => 0xA72C,
-0xA72F => 0xA72E,
-0xA733 => 0xA732,
-0xA735 => 0xA734,
-0xA737 => 0xA736,
-0xA739 => 0xA738,
-0xA73B => 0xA73A,
-0xA73D => 0xA73C,
-0xA73F => 0xA73E,
-0xA741 => 0xA740,
-0xA743 => 0xA742,
-0xA745 => 0xA744,
-0xA747 => 0xA746,
-0xA749 => 0xA748,
-0xA74B => 0xA74A,
-0xA74D => 0xA74C,
-0xA74F => 0xA74E,
-0xA751 => 0xA750,
-0xA753 => 0xA752,
-0xA755 => 0xA754,
-0xA757 => 0xA756,
-0xA759 => 0xA758,
-0xA75B => 0xA75A,
-0xA75D => 0xA75C,
-0xA75F => 0xA75E,
-0xA761 => 0xA760,
-0xA763 => 0xA762,
-0xA765 => 0xA764,
-0xA767 => 0xA766,
-0xA769 => 0xA768,
-0xA76B => 0xA76A,
-0xA76D => 0xA76C,
-0xA76F => 0xA76E,
-0xA77A => 0xA779,
-0xA77C => 0xA77B,
-0xA77F => 0xA77E,
-0xA781 => 0xA780,
-0xA783 => 0xA782,
-0xA785 => 0xA784,
-0xA787 => 0xA786,
-0xA78C => 0xA78B,
-0xA791 => 0xA790,
-0xA793 => 0xA792,
-0xA794 => 0xA7C4,
-0xA797 => 0xA796,
-0xA799 => 0xA798,
-0xA79B => 0xA79A,
-0xA79D => 0xA79C,
-0xA79F => 0xA79E,
-0xA7A1 => 0xA7A0,
-0xA7A3 => 0xA7A2,
-0xA7A5 => 0xA7A4,
-0xA7A7 => 0xA7A6,
-0xA7A9 => 0xA7A8,
-0xA7B5 => 0xA7B4,
-0xA7B7 => 0xA7B6,
-0xA7B9 => 0xA7B8,
-0xA7BB => 0xA7BA,
-0xA7BD => 0xA7BC,
-0xA7BF => 0xA7BE,
-0xA7C3 => 0xA7C2,
-0xA7C8 => 0xA7C7,
-0xA7CA => 0xA7C9,
-0xA7F6 => 0xA7F5,
-0xAB53 => 0xA7B3,
-0xAB70 => 0x13A0,
-0xAB71 => 0x13A1,
-0xAB72 => 0x13A2,
-0xAB73 => 0x13A3,
-0xAB74 => 0x13A4,
-0xAB75 => 0x13A5,
-0xAB76 => 0x13A6,
-0xAB77 => 0x13A7,
-0xAB78 => 0x13A8,
-0xAB79 => 0x13A9,
-0xAB7A => 0x13AA,
-0xAB7B => 0x13AB,
-0xAB7C => 0x13AC,
-0xAB7D => 0x13AD,
-0xAB7E => 0x13AE,
-0xAB7F => 0x13AF,
-0xAB80 => 0x13B0,
-0xAB81 => 0x13B1,
-0xAB82 => 0x13B2,
-0xAB83 => 0x13B3,
-0xAB84 => 0x13B4,
-0xAB85 => 0x13B5,
-0xAB86 => 0x13B6,
-0xAB87 => 0x13B7,
-0xAB88 => 0x13B8,
-0xAB89 => 0x13B9,
-0xAB8A => 0x13BA,
-0xAB8B => 0x13BB,
-0xAB8C => 0x13BC,
-0xAB8D => 0x13BD,
-0xAB8E => 0x13BE,
-0xAB8F => 0x13BF,
-0xAB90 => 0x13C0,
-0xAB91 => 0x13C1,
-0xAB92 => 0x13C2,
-0xAB93 => 0x13C3,
-0xAB94 => 0x13C4,
-0xAB95 => 0x13C5,
-0xAB96 => 0x13C6,
-0xAB97 => 0x13C7,
-0xAB98 => 0x13C8,
-0xAB99 => 0x13C9,
-0xAB9A => 0x13CA,
-0xAB9B => 0x13CB,
-0xAB9C => 0x13CC,
-0xAB9D => 0x13CD,
-0xAB9E => 0x13CE,
-0xAB9F => 0x13CF,
-0xABA0 => 0x13D0,
-0xABA1 => 0x13D1,
-0xABA2 => 0x13D2,
-0xABA3 => 0x13D3,
-0xABA4 => 0x13D4,
-0xABA5 => 0x13D5,
-0xABA6 => 0x13D6,
-0xABA7 => 0x13D7,
-0xABA8 => 0x13D8,
-0xABA9 => 0x13D9,
-0xABAA => 0x13DA,
-0xABAB => 0x13DB,
-0xABAC => 0x13DC,
-0xABAD => 0x13DD,
-0xABAE => 0x13DE,
-0xABAF => 0x13DF,
-0xABB0 => 0x13E0,
-0xABB1 => 0x13E1,
-0xABB2 => 0x13E2,
-0xABB3 => 0x13E3,
-0xABB4 => 0x13E4,
-0xABB5 => 0x13E5,
-0xABB6 => 0x13E6,
-0xABB7 => 0x13E7,
-0xABB8 => 0x13E8,
-0xABB9 => 0x13E9,
-0xABBA => 0x13EA,
-0xABBB => 0x13EB,
-0xABBC => 0x13EC,
-0xABBD => 0x13ED,
-0xABBE => 0x13EE,
-0xABBF => 0x13EF,
-0xFF41 => 0xFF21,
-0xFF42 => 0xFF22,
-0xFF43 => 0xFF23,
-0xFF44 => 0xFF24,
-0xFF45 => 0xFF25,
-0xFF46 => 0xFF26,
-0xFF47 => 0xFF27,
-0xFF48 => 0xFF28,
-0xFF49 => 0xFF29,
-0xFF4A => 0xFF2A,
-0xFF4B => 0xFF2B,
-0xFF4C => 0xFF2C,
-0xFF4D => 0xFF2D,
-0xFF4E => 0xFF2E,
-0xFF4F => 0xFF2F,
-0xFF50 => 0xFF30,
-0xFF51 => 0xFF31,
-0xFF52 => 0xFF32,
-0xFF53 => 0xFF33,
-0xFF54 => 0xFF34,
-0xFF55 => 0xFF35,
-0xFF56 => 0xFF36,
-0xFF57 => 0xFF37,
-0xFF58 => 0xFF38,
-0xFF59 => 0xFF39,
-0xFF5A => 0xFF3A,
-0x10428 => 0x10400,
-0x10429 => 0x10401,
-0x1042A => 0x10402,
-0x1042B => 0x10403,
-0x1042C => 0x10404,
-0x1042D => 0x10405,
-0x1042E => 0x10406,
-0x1042F => 0x10407,
-0x10430 => 0x10408,
-0x10431 => 0x10409,
-0x10432 => 0x1040A,
-0x10433 => 0x1040B,
-0x10434 => 0x1040C,
-0x10435 => 0x1040D,
-0x10436 => 0x1040E,
-0x10437 => 0x1040F,
-0x10438 => 0x10410,
-0x10439 => 0x10411,
-0x1043A => 0x10412,
-0x1043B => 0x10413,
-0x1043C => 0x10414,
-0x1043D => 0x10415,
-0x1043E => 0x10416,
-0x1043F => 0x10417,
-0x10440 => 0x10418,
-0x10441 => 0x10419,
-0x10442 => 0x1041A,
-0x10443 => 0x1041B,
-0x10444 => 0x1041C,
-0x10445 => 0x1041D,
-0x10446 => 0x1041E,
-0x10447 => 0x1041F,
-0x10448 => 0x10420,
-0x10449 => 0x10421,
-0x1044A => 0x10422,
-0x1044B => 0x10423,
-0x1044C => 0x10424,
-0x1044D => 0x10425,
-0x1044E => 0x10426,
-0x1044F => 0x10427,
-0x104D8 => 0x104B0,
-0x104D9 => 0x104B1,
-0x104DA => 0x104B2,
-0x104DB => 0x104B3,
-0x104DC => 0x104B4,
-0x104DD => 0x104B5,
-0x104DE => 0x104B6,
-0x104DF => 0x104B7,
-0x104E0 => 0x104B8,
-0x104E1 => 0x104B9,
-0x104E2 => 0x104BA,
-0x104E3 => 0x104BB,
-0x104E4 => 0x104BC,
-0x104E5 => 0x104BD,
-0x104E6 => 0x104BE,
-0x104E7 => 0x104BF,
-0x104E8 => 0x104C0,
-0x104E9 => 0x104C1,
-0x104EA => 0x104C2,
-0x104EB => 0x104C3,
-0x104EC => 0x104C4,
-0x104ED => 0x104C5,
-0x104EE => 0x104C6,
-0x104EF => 0x104C7,
-0x104F0 => 0x104C8,
-0x104F1 => 0x104C9,
-0x104F2 => 0x104CA,
-0x104F3 => 0x104CB,
-0x104F4 => 0x104CC,
-0x104F5 => 0x104CD,
-0x104F6 => 0x104CE,
-0x104F7 => 0x104CF,
-0x104F8 => 0x104D0,
-0x104F9 => 0x104D1,
-0x104FA => 0x104D2,
-0x104FB => 0x104D3,
-0x10CC0 => 0x10C80,
-0x10CC1 => 0x10C81,
-0x10CC2 => 0x10C82,
-0x10CC3 => 0x10C83,
-0x10CC4 => 0x10C84,
-0x10CC5 => 0x10C85,
-0x10CC6 => 0x10C86,
-0x10CC7 => 0x10C87,
-0x10CC8 => 0x10C88,
-0x10CC9 => 0x10C89,
-0x10CCA => 0x10C8A,
-0x10CCB => 0x10C8B,
-0x10CCC => 0x10C8C,
-0x10CCD => 0x10C8D,
-0x10CCE => 0x10C8E,
-0x10CCF => 0x10C8F,
-0x10CD0 => 0x10C90,
-0x10CD1 => 0x10C91,
-0x10CD2 => 0x10C92,
-0x10CD3 => 0x10C93,
-0x10CD4 => 0x10C94,
-0x10CD5 => 0x10C95,
-0x10CD6 => 0x10C96,
-0x10CD7 => 0x10C97,
-0x10CD8 => 0x10C98,
-0x10CD9 => 0x10C99,
-0x10CDA => 0x10C9A,
-0x10CDB => 0x10C9B,
-0x10CDC => 0x10C9C,
-0x10CDD => 0x10C9D,
-0x10CDE => 0x10C9E,
-0x10CDF => 0x10C9F,
-0x10CE0 => 0x10CA0,
-0x10CE1 => 0x10CA1,
-0x10CE2 => 0x10CA2,
-0x10CE3 => 0x10CA3,
-0x10CE4 => 0x10CA4,
-0x10CE5 => 0x10CA5,
-0x10CE6 => 0x10CA6,
-0x10CE7 => 0x10CA7,
-0x10CE8 => 0x10CA8,
-0x10CE9 => 0x10CA9,
-0x10CEA => 0x10CAA,
-0x10CEB => 0x10CAB,
-0x10CEC => 0x10CAC,
-0x10CED => 0x10CAD,
-0x10CEE => 0x10CAE,
-0x10CEF => 0x10CAF,
-0x10CF0 => 0x10CB0,
-0x10CF1 => 0x10CB1,
-0x10CF2 => 0x10CB2,
-0x118C0 => 0x118A0,
-0x118C1 => 0x118A1,
-0x118C2 => 0x118A2,
-0x118C3 => 0x118A3,
-0x118C4 => 0x118A4,
-0x118C5 => 0x118A5,
-0x118C6 => 0x118A6,
-0x118C7 => 0x118A7,
-0x118C8 => 0x118A8,
-0x118C9 => 0x118A9,
-0x118CA => 0x118AA,
-0x118CB => 0x118AB,
-0x118CC => 0x118AC,
-0x118CD => 0x118AD,
-0x118CE => 0x118AE,
-0x118CF => 0x118AF,
-0x118D0 => 0x118B0,
-0x118D1 => 0x118B1,
-0x118D2 => 0x118B2,
-0x118D3 => 0x118B3,
-0x118D4 => 0x118B4,
-0x118D5 => 0x118B5,
-0x118D6 => 0x118B6,
-0x118D7 => 0x118B7,
-0x118D8 => 0x118B8,
-0x118D9 => 0x118B9,
-0x118DA => 0x118BA,
-0x118DB => 0x118BB,
-0x118DC => 0x118BC,
-0x118DD => 0x118BD,
-0x118DE => 0x118BE,
-0x118DF => 0x118BF,
-0x16E60 => 0x16E40,
-0x16E61 => 0x16E41,
-0x16E62 => 0x16E42,
-0x16E63 => 0x16E43,
-0x16E64 => 0x16E44,
-0x16E65 => 0x16E45,
-0x16E66 => 0x16E46,
-0x16E67 => 0x16E47,
-0x16E68 => 0x16E48,
-0x16E69 => 0x16E49,
-0x16E6A => 0x16E4A,
-0x16E6B => 0x16E4B,
-0x16E6C => 0x16E4C,
-0x16E6D => 0x16E4D,
-0x16E6E => 0x16E4E,
-0x16E6F => 0x16E4F,
-0x16E70 => 0x16E50,
-0x16E71 => 0x16E51,
-0x16E72 => 0x16E52,
-0x16E73 => 0x16E53,
-0x16E74 => 0x16E54,
-0x16E75 => 0x16E55,
-0x16E76 => 0x16E56,
-0x16E77 => 0x16E57,
-0x16E78 => 0x16E58,
-0x16E79 => 0x16E59,
-0x16E7A => 0x16E5A,
-0x16E7B => 0x16E5B,
-0x16E7C => 0x16E5C,
-0x16E7D => 0x16E5D,
-0x16E7E => 0x16E5E,
-0x16E7F => 0x16E5F,
-0x1E922 => 0x1E900,
-0x1E923 => 0x1E901,
-0x1E924 => 0x1E902,
-0x1E925 => 0x1E903,
-0x1E926 => 0x1E904,
-0x1E927 => 0x1E905,
-0x1E928 => 0x1E906,
-0x1E929 => 0x1E907,
-0x1E92A => 0x1E908,
-0x1E92B => 0x1E909,
-0x1E92C => 0x1E90A,
-0x1E92D => 0x1E90B,
-0x1E92E => 0x1E90C,
-0x1E92F => 0x1E90D,
-0x1E930 => 0x1E90E,
-0x1E931 => 0x1E90F,
-0x1E932 => 0x1E910,
-0x1E933 => 0x1E911,
-0x1E934 => 0x1E912,
-0x1E935 => 0x1E913,
-0x1E936 => 0x1E914,
-0x1E937 => 0x1E915,
-0x1E938 => 0x1E916,
-0x1E939 => 0x1E917,
-0x1E93A => 0x1E918,
-0x1E93B => 0x1E919,
-0x1E93C => 0x1E91A,
-0x1E93D => 0x1E91B,
-0x1E93E => 0x1E91C,
-0x1E93F => 0x1E91D,
-0x1E940 => 0x1E91E,
-0x1E941 => 0x1E91F,
-0x1E942 => 0x1E920,
-0x1E943 => 0x1E921,
-];
+return array(
+ 0x61 => 0x41,
+ 0x62 => 0x42,
+ 0x63 => 0x43,
+ 0x64 => 0x44,
+ 0x65 => 0x45,
+ 0x66 => 0x46,
+ 0x67 => 0x47,
+ 0x68 => 0x48,
+ 0x69 => 0x49,
+ 0x6A => 0x4A,
+ 0x6B => 0x4B,
+ 0x6C => 0x4C,
+ 0x6D => 0x4D,
+ 0x6E => 0x4E,
+ 0x6F => 0x4F,
+ 0x70 => 0x50,
+ 0x71 => 0x51,
+ 0x72 => 0x52,
+ 0x73 => 0x53,
+ 0x74 => 0x54,
+ 0x75 => 0x55,
+ 0x76 => 0x56,
+ 0x77 => 0x57,
+ 0x78 => 0x58,
+ 0x79 => 0x59,
+ 0x7A => 0x5A,
+ 0xB5 => 0x39C,
+ 0xE0 => 0xC0,
+ 0xE1 => 0xC1,
+ 0xE2 => 0xC2,
+ 0xE3 => 0xC3,
+ 0xE4 => 0xC4,
+ 0xE5 => 0xC5,
+ 0xE6 => 0xC6,
+ 0xE7 => 0xC7,
+ 0xE8 => 0xC8,
+ 0xE9 => 0xC9,
+ 0xEA => 0xCA,
+ 0xEB => 0xCB,
+ 0xEC => 0xCC,
+ 0xED => 0xCD,
+ 0xEE => 0xCE,
+ 0xEF => 0xCF,
+ 0xF0 => 0xD0,
+ 0xF1 => 0xD1,
+ 0xF2 => 0xD2,
+ 0xF3 => 0xD3,
+ 0xF4 => 0xD4,
+ 0xF5 => 0xD5,
+ 0xF6 => 0xD6,
+ 0xF8 => 0xD8,
+ 0xF9 => 0xD9,
+ 0xFA => 0xDA,
+ 0xFB => 0xDB,
+ 0xFC => 0xDC,
+ 0xFD => 0xDD,
+ 0xFE => 0xDE,
+ 0xFF => 0x178,
+ 0x101 => 0x100,
+ 0x103 => 0x102,
+ 0x105 => 0x104,
+ 0x107 => 0x106,
+ 0x109 => 0x108,
+ 0x10B => 0x10A,
+ 0x10D => 0x10C,
+ 0x10F => 0x10E,
+ 0x111 => 0x110,
+ 0x113 => 0x112,
+ 0x115 => 0x114,
+ 0x117 => 0x116,
+ 0x119 => 0x118,
+ 0x11B => 0x11A,
+ 0x11D => 0x11C,
+ 0x11F => 0x11E,
+ 0x121 => 0x120,
+ 0x123 => 0x122,
+ 0x125 => 0x124,
+ 0x127 => 0x126,
+ 0x129 => 0x128,
+ 0x12B => 0x12A,
+ 0x12D => 0x12C,
+ 0x12F => 0x12E,
+ 0x131 => 0x49,
+ 0x133 => 0x132,
+ 0x135 => 0x134,
+ 0x137 => 0x136,
+ 0x13A => 0x139,
+ 0x13C => 0x13B,
+ 0x13E => 0x13D,
+ 0x140 => 0x13F,
+ 0x142 => 0x141,
+ 0x144 => 0x143,
+ 0x146 => 0x145,
+ 0x148 => 0x147,
+ 0x14B => 0x14A,
+ 0x14D => 0x14C,
+ 0x14F => 0x14E,
+ 0x151 => 0x150,
+ 0x153 => 0x152,
+ 0x155 => 0x154,
+ 0x157 => 0x156,
+ 0x159 => 0x158,
+ 0x15B => 0x15A,
+ 0x15D => 0x15C,
+ 0x15F => 0x15E,
+ 0x161 => 0x160,
+ 0x163 => 0x162,
+ 0x165 => 0x164,
+ 0x167 => 0x166,
+ 0x169 => 0x168,
+ 0x16B => 0x16A,
+ 0x16D => 0x16C,
+ 0x16F => 0x16E,
+ 0x171 => 0x170,
+ 0x173 => 0x172,
+ 0x175 => 0x174,
+ 0x177 => 0x176,
+ 0x17A => 0x179,
+ 0x17C => 0x17B,
+ 0x17E => 0x17D,
+ 0x17F => 0x53,
+ 0x180 => 0x243,
+ 0x183 => 0x182,
+ 0x185 => 0x184,
+ 0x188 => 0x187,
+ 0x18C => 0x18B,
+ 0x192 => 0x191,
+ 0x195 => 0x1F6,
+ 0x199 => 0x198,
+ 0x19A => 0x23D,
+ 0x19E => 0x220,
+ 0x1A1 => 0x1A0,
+ 0x1A3 => 0x1A2,
+ 0x1A5 => 0x1A4,
+ 0x1A8 => 0x1A7,
+ 0x1AD => 0x1AC,
+ 0x1B0 => 0x1AF,
+ 0x1B4 => 0x1B3,
+ 0x1B6 => 0x1B5,
+ 0x1B9 => 0x1B8,
+ 0x1BD => 0x1BC,
+ 0x1BF => 0x1F7,
+ 0x1C5 => 0x1C4,
+ 0x1C6 => 0x1C4,
+ 0x1C8 => 0x1C7,
+ 0x1C9 => 0x1C7,
+ 0x1CB => 0x1CA,
+ 0x1CC => 0x1CA,
+ 0x1CE => 0x1CD,
+ 0x1D0 => 0x1CF,
+ 0x1D2 => 0x1D1,
+ 0x1D4 => 0x1D3,
+ 0x1D6 => 0x1D5,
+ 0x1D8 => 0x1D7,
+ 0x1DA => 0x1D9,
+ 0x1DC => 0x1DB,
+ 0x1DD => 0x18E,
+ 0x1DF => 0x1DE,
+ 0x1E1 => 0x1E0,
+ 0x1E3 => 0x1E2,
+ 0x1E5 => 0x1E4,
+ 0x1E7 => 0x1E6,
+ 0x1E9 => 0x1E8,
+ 0x1EB => 0x1EA,
+ 0x1ED => 0x1EC,
+ 0x1EF => 0x1EE,
+ 0x1F2 => 0x1F1,
+ 0x1F3 => 0x1F1,
+ 0x1F5 => 0x1F4,
+ 0x1F9 => 0x1F8,
+ 0x1FB => 0x1FA,
+ 0x1FD => 0x1FC,
+ 0x1FF => 0x1FE,
+ 0x201 => 0x200,
+ 0x203 => 0x202,
+ 0x205 => 0x204,
+ 0x207 => 0x206,
+ 0x209 => 0x208,
+ 0x20B => 0x20A,
+ 0x20D => 0x20C,
+ 0x20F => 0x20E,
+ 0x211 => 0x210,
+ 0x213 => 0x212,
+ 0x215 => 0x214,
+ 0x217 => 0x216,
+ 0x219 => 0x218,
+ 0x21B => 0x21A,
+ 0x21D => 0x21C,
+ 0x21F => 0x21E,
+ 0x223 => 0x222,
+ 0x225 => 0x224,
+ 0x227 => 0x226,
+ 0x229 => 0x228,
+ 0x22B => 0x22A,
+ 0x22D => 0x22C,
+ 0x22F => 0x22E,
+ 0x231 => 0x230,
+ 0x233 => 0x232,
+ 0x23C => 0x23B,
+ 0x23F => 0x2C7E,
+ 0x240 => 0x2C7F,
+ 0x242 => 0x241,
+ 0x247 => 0x246,
+ 0x249 => 0x248,
+ 0x24B => 0x24A,
+ 0x24D => 0x24C,
+ 0x24F => 0x24E,
+ 0x250 => 0x2C6F,
+ 0x251 => 0x2C6D,
+ 0x252 => 0x2C70,
+ 0x253 => 0x181,
+ 0x254 => 0x186,
+ 0x256 => 0x189,
+ 0x257 => 0x18A,
+ 0x259 => 0x18F,
+ 0x25B => 0x190,
+ 0x25C => 0xA7AB,
+ 0x260 => 0x193,
+ 0x261 => 0xA7AC,
+ 0x263 => 0x194,
+ 0x265 => 0xA78D,
+ 0x266 => 0xA7AA,
+ 0x268 => 0x197,
+ 0x269 => 0x196,
+ 0x26A => 0xA7AE,
+ 0x26B => 0x2C62,
+ 0x26C => 0xA7AD,
+ 0x26F => 0x19C,
+ 0x271 => 0x2C6E,
+ 0x272 => 0x19D,
+ 0x275 => 0x19F,
+ 0x27D => 0x2C64,
+ 0x280 => 0x1A6,
+ 0x282 => 0xA7C5,
+ 0x283 => 0x1A9,
+ 0x287 => 0xA7B1,
+ 0x288 => 0x1AE,
+ 0x289 => 0x244,
+ 0x28A => 0x1B1,
+ 0x28B => 0x1B2,
+ 0x28C => 0x245,
+ 0x292 => 0x1B7,
+ 0x29D => 0xA7B2,
+ 0x29E => 0xA7B0,
+ 0x345 => 0x399,
+ 0x371 => 0x370,
+ 0x373 => 0x372,
+ 0x377 => 0x376,
+ 0x37B => 0x3FD,
+ 0x37C => 0x3FE,
+ 0x37D => 0x3FF,
+ 0x3AC => 0x386,
+ 0x3AD => 0x388,
+ 0x3AE => 0x389,
+ 0x3AF => 0x38A,
+ 0x3B1 => 0x391,
+ 0x3B2 => 0x392,
+ 0x3B3 => 0x393,
+ 0x3B4 => 0x394,
+ 0x3B5 => 0x395,
+ 0x3B6 => 0x396,
+ 0x3B7 => 0x397,
+ 0x3B8 => 0x398,
+ 0x3B9 => 0x399,
+ 0x3BA => 0x39A,
+ 0x3BB => 0x39B,
+ 0x3BC => 0x39C,
+ 0x3BD => 0x39D,
+ 0x3BE => 0x39E,
+ 0x3BF => 0x39F,
+ 0x3C0 => 0x3A0,
+ 0x3C1 => 0x3A1,
+ 0x3C2 => 0x3A3,
+ 0x3C3 => 0x3A3,
+ 0x3C4 => 0x3A4,
+ 0x3C5 => 0x3A5,
+ 0x3C6 => 0x3A6,
+ 0x3C7 => 0x3A7,
+ 0x3C8 => 0x3A8,
+ 0x3C9 => 0x3A9,
+ 0x3CA => 0x3AA,
+ 0x3CB => 0x3AB,
+ 0x3CC => 0x38C,
+ 0x3CD => 0x38E,
+ 0x3CE => 0x38F,
+ 0x3D0 => 0x392,
+ 0x3D1 => 0x398,
+ 0x3D5 => 0x3A6,
+ 0x3D6 => 0x3A0,
+ 0x3D7 => 0x3CF,
+ 0x3D9 => 0x3D8,
+ 0x3DB => 0x3DA,
+ 0x3DD => 0x3DC,
+ 0x3DF => 0x3DE,
+ 0x3E1 => 0x3E0,
+ 0x3E3 => 0x3E2,
+ 0x3E5 => 0x3E4,
+ 0x3E7 => 0x3E6,
+ 0x3E9 => 0x3E8,
+ 0x3EB => 0x3EA,
+ 0x3ED => 0x3EC,
+ 0x3EF => 0x3EE,
+ 0x3F0 => 0x39A,
+ 0x3F1 => 0x3A1,
+ 0x3F2 => 0x3F9,
+ 0x3F3 => 0x37F,
+ 0x3F5 => 0x395,
+ 0x3F8 => 0x3F7,
+ 0x3FB => 0x3FA,
+ 0x430 => 0x410,
+ 0x431 => 0x411,
+ 0x432 => 0x412,
+ 0x433 => 0x413,
+ 0x434 => 0x414,
+ 0x435 => 0x415,
+ 0x436 => 0x416,
+ 0x437 => 0x417,
+ 0x438 => 0x418,
+ 0x439 => 0x419,
+ 0x43A => 0x41A,
+ 0x43B => 0x41B,
+ 0x43C => 0x41C,
+ 0x43D => 0x41D,
+ 0x43E => 0x41E,
+ 0x43F => 0x41F,
+ 0x440 => 0x420,
+ 0x441 => 0x421,
+ 0x442 => 0x422,
+ 0x443 => 0x423,
+ 0x444 => 0x424,
+ 0x445 => 0x425,
+ 0x446 => 0x426,
+ 0x447 => 0x427,
+ 0x448 => 0x428,
+ 0x449 => 0x429,
+ 0x44A => 0x42A,
+ 0x44B => 0x42B,
+ 0x44C => 0x42C,
+ 0x44D => 0x42D,
+ 0x44E => 0x42E,
+ 0x44F => 0x42F,
+ 0x450 => 0x400,
+ 0x451 => 0x401,
+ 0x452 => 0x402,
+ 0x453 => 0x403,
+ 0x454 => 0x404,
+ 0x455 => 0x405,
+ 0x456 => 0x406,
+ 0x457 => 0x407,
+ 0x458 => 0x408,
+ 0x459 => 0x409,
+ 0x45A => 0x40A,
+ 0x45B => 0x40B,
+ 0x45C => 0x40C,
+ 0x45D => 0x40D,
+ 0x45E => 0x40E,
+ 0x45F => 0x40F,
+ 0x461 => 0x460,
+ 0x463 => 0x462,
+ 0x465 => 0x464,
+ 0x467 => 0x466,
+ 0x469 => 0x468,
+ 0x46B => 0x46A,
+ 0x46D => 0x46C,
+ 0x46F => 0x46E,
+ 0x471 => 0x470,
+ 0x473 => 0x472,
+ 0x475 => 0x474,
+ 0x477 => 0x476,
+ 0x479 => 0x478,
+ 0x47B => 0x47A,
+ 0x47D => 0x47C,
+ 0x47F => 0x47E,
+ 0x481 => 0x480,
+ 0x48B => 0x48A,
+ 0x48D => 0x48C,
+ 0x48F => 0x48E,
+ 0x491 => 0x490,
+ 0x493 => 0x492,
+ 0x495 => 0x494,
+ 0x497 => 0x496,
+ 0x499 => 0x498,
+ 0x49B => 0x49A,
+ 0x49D => 0x49C,
+ 0x49F => 0x49E,
+ 0x4A1 => 0x4A0,
+ 0x4A3 => 0x4A2,
+ 0x4A5 => 0x4A4,
+ 0x4A7 => 0x4A6,
+ 0x4A9 => 0x4A8,
+ 0x4AB => 0x4AA,
+ 0x4AD => 0x4AC,
+ 0x4AF => 0x4AE,
+ 0x4B1 => 0x4B0,
+ 0x4B3 => 0x4B2,
+ 0x4B5 => 0x4B4,
+ 0x4B7 => 0x4B6,
+ 0x4B9 => 0x4B8,
+ 0x4BB => 0x4BA,
+ 0x4BD => 0x4BC,
+ 0x4BF => 0x4BE,
+ 0x4C2 => 0x4C1,
+ 0x4C4 => 0x4C3,
+ 0x4C6 => 0x4C5,
+ 0x4C8 => 0x4C7,
+ 0x4CA => 0x4C9,
+ 0x4CC => 0x4CB,
+ 0x4CE => 0x4CD,
+ 0x4CF => 0x4C0,
+ 0x4D1 => 0x4D0,
+ 0x4D3 => 0x4D2,
+ 0x4D5 => 0x4D4,
+ 0x4D7 => 0x4D6,
+ 0x4D9 => 0x4D8,
+ 0x4DB => 0x4DA,
+ 0x4DD => 0x4DC,
+ 0x4DF => 0x4DE,
+ 0x4E1 => 0x4E0,
+ 0x4E3 => 0x4E2,
+ 0x4E5 => 0x4E4,
+ 0x4E7 => 0x4E6,
+ 0x4E9 => 0x4E8,
+ 0x4EB => 0x4EA,
+ 0x4ED => 0x4EC,
+ 0x4EF => 0x4EE,
+ 0x4F1 => 0x4F0,
+ 0x4F3 => 0x4F2,
+ 0x4F5 => 0x4F4,
+ 0x4F7 => 0x4F6,
+ 0x4F9 => 0x4F8,
+ 0x4FB => 0x4FA,
+ 0x4FD => 0x4FC,
+ 0x4FF => 0x4FE,
+ 0x501 => 0x500,
+ 0x503 => 0x502,
+ 0x505 => 0x504,
+ 0x507 => 0x506,
+ 0x509 => 0x508,
+ 0x50B => 0x50A,
+ 0x50D => 0x50C,
+ 0x50F => 0x50E,
+ 0x511 => 0x510,
+ 0x513 => 0x512,
+ 0x515 => 0x514,
+ 0x517 => 0x516,
+ 0x519 => 0x518,
+ 0x51B => 0x51A,
+ 0x51D => 0x51C,
+ 0x51F => 0x51E,
+ 0x521 => 0x520,
+ 0x523 => 0x522,
+ 0x525 => 0x524,
+ 0x527 => 0x526,
+ 0x529 => 0x528,
+ 0x52B => 0x52A,
+ 0x52D => 0x52C,
+ 0x52F => 0x52E,
+ 0x561 => 0x531,
+ 0x562 => 0x532,
+ 0x563 => 0x533,
+ 0x564 => 0x534,
+ 0x565 => 0x535,
+ 0x566 => 0x536,
+ 0x567 => 0x537,
+ 0x568 => 0x538,
+ 0x569 => 0x539,
+ 0x56A => 0x53A,
+ 0x56B => 0x53B,
+ 0x56C => 0x53C,
+ 0x56D => 0x53D,
+ 0x56E => 0x53E,
+ 0x56F => 0x53F,
+ 0x570 => 0x540,
+ 0x571 => 0x541,
+ 0x572 => 0x542,
+ 0x573 => 0x543,
+ 0x574 => 0x544,
+ 0x575 => 0x545,
+ 0x576 => 0x546,
+ 0x577 => 0x547,
+ 0x578 => 0x548,
+ 0x579 => 0x549,
+ 0x57A => 0x54A,
+ 0x57B => 0x54B,
+ 0x57C => 0x54C,
+ 0x57D => 0x54D,
+ 0x57E => 0x54E,
+ 0x57F => 0x54F,
+ 0x580 => 0x550,
+ 0x581 => 0x551,
+ 0x582 => 0x552,
+ 0x583 => 0x553,
+ 0x584 => 0x554,
+ 0x585 => 0x555,
+ 0x586 => 0x556,
+ 0x10D0 => 0x1C90,
+ 0x10D1 => 0x1C91,
+ 0x10D2 => 0x1C92,
+ 0x10D3 => 0x1C93,
+ 0x10D4 => 0x1C94,
+ 0x10D5 => 0x1C95,
+ 0x10D6 => 0x1C96,
+ 0x10D7 => 0x1C97,
+ 0x10D8 => 0x1C98,
+ 0x10D9 => 0x1C99,
+ 0x10DA => 0x1C9A,
+ 0x10DB => 0x1C9B,
+ 0x10DC => 0x1C9C,
+ 0x10DD => 0x1C9D,
+ 0x10DE => 0x1C9E,
+ 0x10DF => 0x1C9F,
+ 0x10E0 => 0x1CA0,
+ 0x10E1 => 0x1CA1,
+ 0x10E2 => 0x1CA2,
+ 0x10E3 => 0x1CA3,
+ 0x10E4 => 0x1CA4,
+ 0x10E5 => 0x1CA5,
+ 0x10E6 => 0x1CA6,
+ 0x10E7 => 0x1CA7,
+ 0x10E8 => 0x1CA8,
+ 0x10E9 => 0x1CA9,
+ 0x10EA => 0x1CAA,
+ 0x10EB => 0x1CAB,
+ 0x10EC => 0x1CAC,
+ 0x10ED => 0x1CAD,
+ 0x10EE => 0x1CAE,
+ 0x10EF => 0x1CAF,
+ 0x10F0 => 0x1CB0,
+ 0x10F1 => 0x1CB1,
+ 0x10F2 => 0x1CB2,
+ 0x10F3 => 0x1CB3,
+ 0x10F4 => 0x1CB4,
+ 0x10F5 => 0x1CB5,
+ 0x10F6 => 0x1CB6,
+ 0x10F7 => 0x1CB7,
+ 0x10F8 => 0x1CB8,
+ 0x10F9 => 0x1CB9,
+ 0x10FA => 0x1CBA,
+ 0x10FD => 0x1CBD,
+ 0x10FE => 0x1CBE,
+ 0x10FF => 0x1CBF,
+ 0x13F8 => 0x13F0,
+ 0x13F9 => 0x13F1,
+ 0x13FA => 0x13F2,
+ 0x13FB => 0x13F3,
+ 0x13FC => 0x13F4,
+ 0x13FD => 0x13F5,
+ 0x1C80 => 0x412,
+ 0x1C81 => 0x414,
+ 0x1C82 => 0x41E,
+ 0x1C83 => 0x421,
+ 0x1C84 => 0x422,
+ 0x1C85 => 0x422,
+ 0x1C86 => 0x42A,
+ 0x1C87 => 0x462,
+ 0x1C88 => 0xA64A,
+ 0x1D79 => 0xA77D,
+ 0x1D7D => 0x2C63,
+ 0x1D8E => 0xA7C6,
+ 0x1E01 => 0x1E00,
+ 0x1E03 => 0x1E02,
+ 0x1E05 => 0x1E04,
+ 0x1E07 => 0x1E06,
+ 0x1E09 => 0x1E08,
+ 0x1E0B => 0x1E0A,
+ 0x1E0D => 0x1E0C,
+ 0x1E0F => 0x1E0E,
+ 0x1E11 => 0x1E10,
+ 0x1E13 => 0x1E12,
+ 0x1E15 => 0x1E14,
+ 0x1E17 => 0x1E16,
+ 0x1E19 => 0x1E18,
+ 0x1E1B => 0x1E1A,
+ 0x1E1D => 0x1E1C,
+ 0x1E1F => 0x1E1E,
+ 0x1E21 => 0x1E20,
+ 0x1E23 => 0x1E22,
+ 0x1E25 => 0x1E24,
+ 0x1E27 => 0x1E26,
+ 0x1E29 => 0x1E28,
+ 0x1E2B => 0x1E2A,
+ 0x1E2D => 0x1E2C,
+ 0x1E2F => 0x1E2E,
+ 0x1E31 => 0x1E30,
+ 0x1E33 => 0x1E32,
+ 0x1E35 => 0x1E34,
+ 0x1E37 => 0x1E36,
+ 0x1E39 => 0x1E38,
+ 0x1E3B => 0x1E3A,
+ 0x1E3D => 0x1E3C,
+ 0x1E3F => 0x1E3E,
+ 0x1E41 => 0x1E40,
+ 0x1E43 => 0x1E42,
+ 0x1E45 => 0x1E44,
+ 0x1E47 => 0x1E46,
+ 0x1E49 => 0x1E48,
+ 0x1E4B => 0x1E4A,
+ 0x1E4D => 0x1E4C,
+ 0x1E4F => 0x1E4E,
+ 0x1E51 => 0x1E50,
+ 0x1E53 => 0x1E52,
+ 0x1E55 => 0x1E54,
+ 0x1E57 => 0x1E56,
+ 0x1E59 => 0x1E58,
+ 0x1E5B => 0x1E5A,
+ 0x1E5D => 0x1E5C,
+ 0x1E5F => 0x1E5E,
+ 0x1E61 => 0x1E60,
+ 0x1E63 => 0x1E62,
+ 0x1E65 => 0x1E64,
+ 0x1E67 => 0x1E66,
+ 0x1E69 => 0x1E68,
+ 0x1E6B => 0x1E6A,
+ 0x1E6D => 0x1E6C,
+ 0x1E6F => 0x1E6E,
+ 0x1E71 => 0x1E70,
+ 0x1E73 => 0x1E72,
+ 0x1E75 => 0x1E74,
+ 0x1E77 => 0x1E76,
+ 0x1E79 => 0x1E78,
+ 0x1E7B => 0x1E7A,
+ 0x1E7D => 0x1E7C,
+ 0x1E7F => 0x1E7E,
+ 0x1E81 => 0x1E80,
+ 0x1E83 => 0x1E82,
+ 0x1E85 => 0x1E84,
+ 0x1E87 => 0x1E86,
+ 0x1E89 => 0x1E88,
+ 0x1E8B => 0x1E8A,
+ 0x1E8D => 0x1E8C,
+ 0x1E8F => 0x1E8E,
+ 0x1E91 => 0x1E90,
+ 0x1E93 => 0x1E92,
+ 0x1E95 => 0x1E94,
+ 0x1E9B => 0x1E60,
+ 0x1EA1 => 0x1EA0,
+ 0x1EA3 => 0x1EA2,
+ 0x1EA5 => 0x1EA4,
+ 0x1EA7 => 0x1EA6,
+ 0x1EA9 => 0x1EA8,
+ 0x1EAB => 0x1EAA,
+ 0x1EAD => 0x1EAC,
+ 0x1EAF => 0x1EAE,
+ 0x1EB1 => 0x1EB0,
+ 0x1EB3 => 0x1EB2,
+ 0x1EB5 => 0x1EB4,
+ 0x1EB7 => 0x1EB6,
+ 0x1EB9 => 0x1EB8,
+ 0x1EBB => 0x1EBA,
+ 0x1EBD => 0x1EBC,
+ 0x1EBF => 0x1EBE,
+ 0x1EC1 => 0x1EC0,
+ 0x1EC3 => 0x1EC2,
+ 0x1EC5 => 0x1EC4,
+ 0x1EC7 => 0x1EC6,
+ 0x1EC9 => 0x1EC8,
+ 0x1ECB => 0x1ECA,
+ 0x1ECD => 0x1ECC,
+ 0x1ECF => 0x1ECE,
+ 0x1ED1 => 0x1ED0,
+ 0x1ED3 => 0x1ED2,
+ 0x1ED5 => 0x1ED4,
+ 0x1ED7 => 0x1ED6,
+ 0x1ED9 => 0x1ED8,
+ 0x1EDB => 0x1EDA,
+ 0x1EDD => 0x1EDC,
+ 0x1EDF => 0x1EDE,
+ 0x1EE1 => 0x1EE0,
+ 0x1EE3 => 0x1EE2,
+ 0x1EE5 => 0x1EE4,
+ 0x1EE7 => 0x1EE6,
+ 0x1EE9 => 0x1EE8,
+ 0x1EEB => 0x1EEA,
+ 0x1EED => 0x1EEC,
+ 0x1EEF => 0x1EEE,
+ 0x1EF1 => 0x1EF0,
+ 0x1EF3 => 0x1EF2,
+ 0x1EF5 => 0x1EF4,
+ 0x1EF7 => 0x1EF6,
+ 0x1EF9 => 0x1EF8,
+ 0x1EFB => 0x1EFA,
+ 0x1EFD => 0x1EFC,
+ 0x1EFF => 0x1EFE,
+ 0x1F00 => 0x1F08,
+ 0x1F01 => 0x1F09,
+ 0x1F02 => 0x1F0A,
+ 0x1F03 => 0x1F0B,
+ 0x1F04 => 0x1F0C,
+ 0x1F05 => 0x1F0D,
+ 0x1F06 => 0x1F0E,
+ 0x1F07 => 0x1F0F,
+ 0x1F10 => 0x1F18,
+ 0x1F11 => 0x1F19,
+ 0x1F12 => 0x1F1A,
+ 0x1F13 => 0x1F1B,
+ 0x1F14 => 0x1F1C,
+ 0x1F15 => 0x1F1D,
+ 0x1F20 => 0x1F28,
+ 0x1F21 => 0x1F29,
+ 0x1F22 => 0x1F2A,
+ 0x1F23 => 0x1F2B,
+ 0x1F24 => 0x1F2C,
+ 0x1F25 => 0x1F2D,
+ 0x1F26 => 0x1F2E,
+ 0x1F27 => 0x1F2F,
+ 0x1F30 => 0x1F38,
+ 0x1F31 => 0x1F39,
+ 0x1F32 => 0x1F3A,
+ 0x1F33 => 0x1F3B,
+ 0x1F34 => 0x1F3C,
+ 0x1F35 => 0x1F3D,
+ 0x1F36 => 0x1F3E,
+ 0x1F37 => 0x1F3F,
+ 0x1F40 => 0x1F48,
+ 0x1F41 => 0x1F49,
+ 0x1F42 => 0x1F4A,
+ 0x1F43 => 0x1F4B,
+ 0x1F44 => 0x1F4C,
+ 0x1F45 => 0x1F4D,
+ 0x1F51 => 0x1F59,
+ 0x1F53 => 0x1F5B,
+ 0x1F55 => 0x1F5D,
+ 0x1F57 => 0x1F5F,
+ 0x1F60 => 0x1F68,
+ 0x1F61 => 0x1F69,
+ 0x1F62 => 0x1F6A,
+ 0x1F63 => 0x1F6B,
+ 0x1F64 => 0x1F6C,
+ 0x1F65 => 0x1F6D,
+ 0x1F66 => 0x1F6E,
+ 0x1F67 => 0x1F6F,
+ 0x1F70 => 0x1FBA,
+ 0x1F71 => 0x1FBB,
+ 0x1F72 => 0x1FC8,
+ 0x1F73 => 0x1FC9,
+ 0x1F74 => 0x1FCA,
+ 0x1F75 => 0x1FCB,
+ 0x1F76 => 0x1FDA,
+ 0x1F77 => 0x1FDB,
+ 0x1F78 => 0x1FF8,
+ 0x1F79 => 0x1FF9,
+ 0x1F7A => 0x1FEA,
+ 0x1F7B => 0x1FEB,
+ 0x1F7C => 0x1FFA,
+ 0x1F7D => 0x1FFB,
+ 0x1F80 => 0x1F88,
+ 0x1F81 => 0x1F89,
+ 0x1F82 => 0x1F8A,
+ 0x1F83 => 0x1F8B,
+ 0x1F84 => 0x1F8C,
+ 0x1F85 => 0x1F8D,
+ 0x1F86 => 0x1F8E,
+ 0x1F87 => 0x1F8F,
+ 0x1F90 => 0x1F98,
+ 0x1F91 => 0x1F99,
+ 0x1F92 => 0x1F9A,
+ 0x1F93 => 0x1F9B,
+ 0x1F94 => 0x1F9C,
+ 0x1F95 => 0x1F9D,
+ 0x1F96 => 0x1F9E,
+ 0x1F97 => 0x1F9F,
+ 0x1FA0 => 0x1FA8,
+ 0x1FA1 => 0x1FA9,
+ 0x1FA2 => 0x1FAA,
+ 0x1FA3 => 0x1FAB,
+ 0x1FA4 => 0x1FAC,
+ 0x1FA5 => 0x1FAD,
+ 0x1FA6 => 0x1FAE,
+ 0x1FA7 => 0x1FAF,
+ 0x1FB0 => 0x1FB8,
+ 0x1FB1 => 0x1FB9,
+ 0x1FB3 => 0x1FBC,
+ 0x1FBE => 0x399,
+ 0x1FC3 => 0x1FCC,
+ 0x1FD0 => 0x1FD8,
+ 0x1FD1 => 0x1FD9,
+ 0x1FE0 => 0x1FE8,
+ 0x1FE1 => 0x1FE9,
+ 0x1FE5 => 0x1FEC,
+ 0x1FF3 => 0x1FFC,
+ 0x214E => 0x2132,
+ 0x2170 => 0x2160,
+ 0x2171 => 0x2161,
+ 0x2172 => 0x2162,
+ 0x2173 => 0x2163,
+ 0x2174 => 0x2164,
+ 0x2175 => 0x2165,
+ 0x2176 => 0x2166,
+ 0x2177 => 0x2167,
+ 0x2178 => 0x2168,
+ 0x2179 => 0x2169,
+ 0x217A => 0x216A,
+ 0x217B => 0x216B,
+ 0x217C => 0x216C,
+ 0x217D => 0x216D,
+ 0x217E => 0x216E,
+ 0x217F => 0x216F,
+ 0x2184 => 0x2183,
+ 0x24D0 => 0x24B6,
+ 0x24D1 => 0x24B7,
+ 0x24D2 => 0x24B8,
+ 0x24D3 => 0x24B9,
+ 0x24D4 => 0x24BA,
+ 0x24D5 => 0x24BB,
+ 0x24D6 => 0x24BC,
+ 0x24D7 => 0x24BD,
+ 0x24D8 => 0x24BE,
+ 0x24D9 => 0x24BF,
+ 0x24DA => 0x24C0,
+ 0x24DB => 0x24C1,
+ 0x24DC => 0x24C2,
+ 0x24DD => 0x24C3,
+ 0x24DE => 0x24C4,
+ 0x24DF => 0x24C5,
+ 0x24E0 => 0x24C6,
+ 0x24E1 => 0x24C7,
+ 0x24E2 => 0x24C8,
+ 0x24E3 => 0x24C9,
+ 0x24E4 => 0x24CA,
+ 0x24E5 => 0x24CB,
+ 0x24E6 => 0x24CC,
+ 0x24E7 => 0x24CD,
+ 0x24E8 => 0x24CE,
+ 0x24E9 => 0x24CF,
+ 0x2C30 => 0x2C00,
+ 0x2C31 => 0x2C01,
+ 0x2C32 => 0x2C02,
+ 0x2C33 => 0x2C03,
+ 0x2C34 => 0x2C04,
+ 0x2C35 => 0x2C05,
+ 0x2C36 => 0x2C06,
+ 0x2C37 => 0x2C07,
+ 0x2C38 => 0x2C08,
+ 0x2C39 => 0x2C09,
+ 0x2C3A => 0x2C0A,
+ 0x2C3B => 0x2C0B,
+ 0x2C3C => 0x2C0C,
+ 0x2C3D => 0x2C0D,
+ 0x2C3E => 0x2C0E,
+ 0x2C3F => 0x2C0F,
+ 0x2C40 => 0x2C10,
+ 0x2C41 => 0x2C11,
+ 0x2C42 => 0x2C12,
+ 0x2C43 => 0x2C13,
+ 0x2C44 => 0x2C14,
+ 0x2C45 => 0x2C15,
+ 0x2C46 => 0x2C16,
+ 0x2C47 => 0x2C17,
+ 0x2C48 => 0x2C18,
+ 0x2C49 => 0x2C19,
+ 0x2C4A => 0x2C1A,
+ 0x2C4B => 0x2C1B,
+ 0x2C4C => 0x2C1C,
+ 0x2C4D => 0x2C1D,
+ 0x2C4E => 0x2C1E,
+ 0x2C4F => 0x2C1F,
+ 0x2C50 => 0x2C20,
+ 0x2C51 => 0x2C21,
+ 0x2C52 => 0x2C22,
+ 0x2C53 => 0x2C23,
+ 0x2C54 => 0x2C24,
+ 0x2C55 => 0x2C25,
+ 0x2C56 => 0x2C26,
+ 0x2C57 => 0x2C27,
+ 0x2C58 => 0x2C28,
+ 0x2C59 => 0x2C29,
+ 0x2C5A => 0x2C2A,
+ 0x2C5B => 0x2C2B,
+ 0x2C5C => 0x2C2C,
+ 0x2C5D => 0x2C2D,
+ 0x2C5E => 0x2C2E,
+ 0x2C61 => 0x2C60,
+ 0x2C65 => 0x23A,
+ 0x2C66 => 0x23E,
+ 0x2C68 => 0x2C67,
+ 0x2C6A => 0x2C69,
+ 0x2C6C => 0x2C6B,
+ 0x2C73 => 0x2C72,
+ 0x2C76 => 0x2C75,
+ 0x2C81 => 0x2C80,
+ 0x2C83 => 0x2C82,
+ 0x2C85 => 0x2C84,
+ 0x2C87 => 0x2C86,
+ 0x2C89 => 0x2C88,
+ 0x2C8B => 0x2C8A,
+ 0x2C8D => 0x2C8C,
+ 0x2C8F => 0x2C8E,
+ 0x2C91 => 0x2C90,
+ 0x2C93 => 0x2C92,
+ 0x2C95 => 0x2C94,
+ 0x2C97 => 0x2C96,
+ 0x2C99 => 0x2C98,
+ 0x2C9B => 0x2C9A,
+ 0x2C9D => 0x2C9C,
+ 0x2C9F => 0x2C9E,
+ 0x2CA1 => 0x2CA0,
+ 0x2CA3 => 0x2CA2,
+ 0x2CA5 => 0x2CA4,
+ 0x2CA7 => 0x2CA6,
+ 0x2CA9 => 0x2CA8,
+ 0x2CAB => 0x2CAA,
+ 0x2CAD => 0x2CAC,
+ 0x2CAF => 0x2CAE,
+ 0x2CB1 => 0x2CB0,
+ 0x2CB3 => 0x2CB2,
+ 0x2CB5 => 0x2CB4,
+ 0x2CB7 => 0x2CB6,
+ 0x2CB9 => 0x2CB8,
+ 0x2CBB => 0x2CBA,
+ 0x2CBD => 0x2CBC,
+ 0x2CBF => 0x2CBE,
+ 0x2CC1 => 0x2CC0,
+ 0x2CC3 => 0x2CC2,
+ 0x2CC5 => 0x2CC4,
+ 0x2CC7 => 0x2CC6,
+ 0x2CC9 => 0x2CC8,
+ 0x2CCB => 0x2CCA,
+ 0x2CCD => 0x2CCC,
+ 0x2CCF => 0x2CCE,
+ 0x2CD1 => 0x2CD0,
+ 0x2CD3 => 0x2CD2,
+ 0x2CD5 => 0x2CD4,
+ 0x2CD7 => 0x2CD6,
+ 0x2CD9 => 0x2CD8,
+ 0x2CDB => 0x2CDA,
+ 0x2CDD => 0x2CDC,
+ 0x2CDF => 0x2CDE,
+ 0x2CE1 => 0x2CE0,
+ 0x2CE3 => 0x2CE2,
+ 0x2CEC => 0x2CEB,
+ 0x2CEE => 0x2CED,
+ 0x2CF3 => 0x2CF2,
+ 0x2D00 => 0x10A0,
+ 0x2D01 => 0x10A1,
+ 0x2D02 => 0x10A2,
+ 0x2D03 => 0x10A3,
+ 0x2D04 => 0x10A4,
+ 0x2D05 => 0x10A5,
+ 0x2D06 => 0x10A6,
+ 0x2D07 => 0x10A7,
+ 0x2D08 => 0x10A8,
+ 0x2D09 => 0x10A9,
+ 0x2D0A => 0x10AA,
+ 0x2D0B => 0x10AB,
+ 0x2D0C => 0x10AC,
+ 0x2D0D => 0x10AD,
+ 0x2D0E => 0x10AE,
+ 0x2D0F => 0x10AF,
+ 0x2D10 => 0x10B0,
+ 0x2D11 => 0x10B1,
+ 0x2D12 => 0x10B2,
+ 0x2D13 => 0x10B3,
+ 0x2D14 => 0x10B4,
+ 0x2D15 => 0x10B5,
+ 0x2D16 => 0x10B6,
+ 0x2D17 => 0x10B7,
+ 0x2D18 => 0x10B8,
+ 0x2D19 => 0x10B9,
+ 0x2D1A => 0x10BA,
+ 0x2D1B => 0x10BB,
+ 0x2D1C => 0x10BC,
+ 0x2D1D => 0x10BD,
+ 0x2D1E => 0x10BE,
+ 0x2D1F => 0x10BF,
+ 0x2D20 => 0x10C0,
+ 0x2D21 => 0x10C1,
+ 0x2D22 => 0x10C2,
+ 0x2D23 => 0x10C3,
+ 0x2D24 => 0x10C4,
+ 0x2D25 => 0x10C5,
+ 0x2D27 => 0x10C7,
+ 0x2D2D => 0x10CD,
+ 0xA641 => 0xA640,
+ 0xA643 => 0xA642,
+ 0xA645 => 0xA644,
+ 0xA647 => 0xA646,
+ 0xA649 => 0xA648,
+ 0xA64B => 0xA64A,
+ 0xA64D => 0xA64C,
+ 0xA64F => 0xA64E,
+ 0xA651 => 0xA650,
+ 0xA653 => 0xA652,
+ 0xA655 => 0xA654,
+ 0xA657 => 0xA656,
+ 0xA659 => 0xA658,
+ 0xA65B => 0xA65A,
+ 0xA65D => 0xA65C,
+ 0xA65F => 0xA65E,
+ 0xA661 => 0xA660,
+ 0xA663 => 0xA662,
+ 0xA665 => 0xA664,
+ 0xA667 => 0xA666,
+ 0xA669 => 0xA668,
+ 0xA66B => 0xA66A,
+ 0xA66D => 0xA66C,
+ 0xA681 => 0xA680,
+ 0xA683 => 0xA682,
+ 0xA685 => 0xA684,
+ 0xA687 => 0xA686,
+ 0xA689 => 0xA688,
+ 0xA68B => 0xA68A,
+ 0xA68D => 0xA68C,
+ 0xA68F => 0xA68E,
+ 0xA691 => 0xA690,
+ 0xA693 => 0xA692,
+ 0xA695 => 0xA694,
+ 0xA697 => 0xA696,
+ 0xA699 => 0xA698,
+ 0xA69B => 0xA69A,
+ 0xA723 => 0xA722,
+ 0xA725 => 0xA724,
+ 0xA727 => 0xA726,
+ 0xA729 => 0xA728,
+ 0xA72B => 0xA72A,
+ 0xA72D => 0xA72C,
+ 0xA72F => 0xA72E,
+ 0xA733 => 0xA732,
+ 0xA735 => 0xA734,
+ 0xA737 => 0xA736,
+ 0xA739 => 0xA738,
+ 0xA73B => 0xA73A,
+ 0xA73D => 0xA73C,
+ 0xA73F => 0xA73E,
+ 0xA741 => 0xA740,
+ 0xA743 => 0xA742,
+ 0xA745 => 0xA744,
+ 0xA747 => 0xA746,
+ 0xA749 => 0xA748,
+ 0xA74B => 0xA74A,
+ 0xA74D => 0xA74C,
+ 0xA74F => 0xA74E,
+ 0xA751 => 0xA750,
+ 0xA753 => 0xA752,
+ 0xA755 => 0xA754,
+ 0xA757 => 0xA756,
+ 0xA759 => 0xA758,
+ 0xA75B => 0xA75A,
+ 0xA75D => 0xA75C,
+ 0xA75F => 0xA75E,
+ 0xA761 => 0xA760,
+ 0xA763 => 0xA762,
+ 0xA765 => 0xA764,
+ 0xA767 => 0xA766,
+ 0xA769 => 0xA768,
+ 0xA76B => 0xA76A,
+ 0xA76D => 0xA76C,
+ 0xA76F => 0xA76E,
+ 0xA77A => 0xA779,
+ 0xA77C => 0xA77B,
+ 0xA77F => 0xA77E,
+ 0xA781 => 0xA780,
+ 0xA783 => 0xA782,
+ 0xA785 => 0xA784,
+ 0xA787 => 0xA786,
+ 0xA78C => 0xA78B,
+ 0xA791 => 0xA790,
+ 0xA793 => 0xA792,
+ 0xA794 => 0xA7C4,
+ 0xA797 => 0xA796,
+ 0xA799 => 0xA798,
+ 0xA79B => 0xA79A,
+ 0xA79D => 0xA79C,
+ 0xA79F => 0xA79E,
+ 0xA7A1 => 0xA7A0,
+ 0xA7A3 => 0xA7A2,
+ 0xA7A5 => 0xA7A4,
+ 0xA7A7 => 0xA7A6,
+ 0xA7A9 => 0xA7A8,
+ 0xA7B5 => 0xA7B4,
+ 0xA7B7 => 0xA7B6,
+ 0xA7B9 => 0xA7B8,
+ 0xA7BB => 0xA7BA,
+ 0xA7BD => 0xA7BC,
+ 0xA7BF => 0xA7BE,
+ 0xA7C3 => 0xA7C2,
+ 0xA7C8 => 0xA7C7,
+ 0xA7CA => 0xA7C9,
+ 0xA7F6 => 0xA7F5,
+ 0xAB53 => 0xA7B3,
+ 0xAB70 => 0x13A0,
+ 0xAB71 => 0x13A1,
+ 0xAB72 => 0x13A2,
+ 0xAB73 => 0x13A3,
+ 0xAB74 => 0x13A4,
+ 0xAB75 => 0x13A5,
+ 0xAB76 => 0x13A6,
+ 0xAB77 => 0x13A7,
+ 0xAB78 => 0x13A8,
+ 0xAB79 => 0x13A9,
+ 0xAB7A => 0x13AA,
+ 0xAB7B => 0x13AB,
+ 0xAB7C => 0x13AC,
+ 0xAB7D => 0x13AD,
+ 0xAB7E => 0x13AE,
+ 0xAB7F => 0x13AF,
+ 0xAB80 => 0x13B0,
+ 0xAB81 => 0x13B1,
+ 0xAB82 => 0x13B2,
+ 0xAB83 => 0x13B3,
+ 0xAB84 => 0x13B4,
+ 0xAB85 => 0x13B5,
+ 0xAB86 => 0x13B6,
+ 0xAB87 => 0x13B7,
+ 0xAB88 => 0x13B8,
+ 0xAB89 => 0x13B9,
+ 0xAB8A => 0x13BA,
+ 0xAB8B => 0x13BB,
+ 0xAB8C => 0x13BC,
+ 0xAB8D => 0x13BD,
+ 0xAB8E => 0x13BE,
+ 0xAB8F => 0x13BF,
+ 0xAB90 => 0x13C0,
+ 0xAB91 => 0x13C1,
+ 0xAB92 => 0x13C2,
+ 0xAB93 => 0x13C3,
+ 0xAB94 => 0x13C4,
+ 0xAB95 => 0x13C5,
+ 0xAB96 => 0x13C6,
+ 0xAB97 => 0x13C7,
+ 0xAB98 => 0x13C8,
+ 0xAB99 => 0x13C9,
+ 0xAB9A => 0x13CA,
+ 0xAB9B => 0x13CB,
+ 0xAB9C => 0x13CC,
+ 0xAB9D => 0x13CD,
+ 0xAB9E => 0x13CE,
+ 0xAB9F => 0x13CF,
+ 0xABA0 => 0x13D0,
+ 0xABA1 => 0x13D1,
+ 0xABA2 => 0x13D2,
+ 0xABA3 => 0x13D3,
+ 0xABA4 => 0x13D4,
+ 0xABA5 => 0x13D5,
+ 0xABA6 => 0x13D6,
+ 0xABA7 => 0x13D7,
+ 0xABA8 => 0x13D8,
+ 0xABA9 => 0x13D9,
+ 0xABAA => 0x13DA,
+ 0xABAB => 0x13DB,
+ 0xABAC => 0x13DC,
+ 0xABAD => 0x13DD,
+ 0xABAE => 0x13DE,
+ 0xABAF => 0x13DF,
+ 0xABB0 => 0x13E0,
+ 0xABB1 => 0x13E1,
+ 0xABB2 => 0x13E2,
+ 0xABB3 => 0x13E3,
+ 0xABB4 => 0x13E4,
+ 0xABB5 => 0x13E5,
+ 0xABB6 => 0x13E6,
+ 0xABB7 => 0x13E7,
+ 0xABB8 => 0x13E8,
+ 0xABB9 => 0x13E9,
+ 0xABBA => 0x13EA,
+ 0xABBB => 0x13EB,
+ 0xABBC => 0x13EC,
+ 0xABBD => 0x13ED,
+ 0xABBE => 0x13EE,
+ 0xABBF => 0x13EF,
+ 0xFF41 => 0xFF21,
+ 0xFF42 => 0xFF22,
+ 0xFF43 => 0xFF23,
+ 0xFF44 => 0xFF24,
+ 0xFF45 => 0xFF25,
+ 0xFF46 => 0xFF26,
+ 0xFF47 => 0xFF27,
+ 0xFF48 => 0xFF28,
+ 0xFF49 => 0xFF29,
+ 0xFF4A => 0xFF2A,
+ 0xFF4B => 0xFF2B,
+ 0xFF4C => 0xFF2C,
+ 0xFF4D => 0xFF2D,
+ 0xFF4E => 0xFF2E,
+ 0xFF4F => 0xFF2F,
+ 0xFF50 => 0xFF30,
+ 0xFF51 => 0xFF31,
+ 0xFF52 => 0xFF32,
+ 0xFF53 => 0xFF33,
+ 0xFF54 => 0xFF34,
+ 0xFF55 => 0xFF35,
+ 0xFF56 => 0xFF36,
+ 0xFF57 => 0xFF37,
+ 0xFF58 => 0xFF38,
+ 0xFF59 => 0xFF39,
+ 0xFF5A => 0xFF3A,
+ 0x10428 => 0x10400,
+ 0x10429 => 0x10401,
+ 0x1042A => 0x10402,
+ 0x1042B => 0x10403,
+ 0x1042C => 0x10404,
+ 0x1042D => 0x10405,
+ 0x1042E => 0x10406,
+ 0x1042F => 0x10407,
+ 0x10430 => 0x10408,
+ 0x10431 => 0x10409,
+ 0x10432 => 0x1040A,
+ 0x10433 => 0x1040B,
+ 0x10434 => 0x1040C,
+ 0x10435 => 0x1040D,
+ 0x10436 => 0x1040E,
+ 0x10437 => 0x1040F,
+ 0x10438 => 0x10410,
+ 0x10439 => 0x10411,
+ 0x1043A => 0x10412,
+ 0x1043B => 0x10413,
+ 0x1043C => 0x10414,
+ 0x1043D => 0x10415,
+ 0x1043E => 0x10416,
+ 0x1043F => 0x10417,
+ 0x10440 => 0x10418,
+ 0x10441 => 0x10419,
+ 0x10442 => 0x1041A,
+ 0x10443 => 0x1041B,
+ 0x10444 => 0x1041C,
+ 0x10445 => 0x1041D,
+ 0x10446 => 0x1041E,
+ 0x10447 => 0x1041F,
+ 0x10448 => 0x10420,
+ 0x10449 => 0x10421,
+ 0x1044A => 0x10422,
+ 0x1044B => 0x10423,
+ 0x1044C => 0x10424,
+ 0x1044D => 0x10425,
+ 0x1044E => 0x10426,
+ 0x1044F => 0x10427,
+ 0x104D8 => 0x104B0,
+ 0x104D9 => 0x104B1,
+ 0x104DA => 0x104B2,
+ 0x104DB => 0x104B3,
+ 0x104DC => 0x104B4,
+ 0x104DD => 0x104B5,
+ 0x104DE => 0x104B6,
+ 0x104DF => 0x104B7,
+ 0x104E0 => 0x104B8,
+ 0x104E1 => 0x104B9,
+ 0x104E2 => 0x104BA,
+ 0x104E3 => 0x104BB,
+ 0x104E4 => 0x104BC,
+ 0x104E5 => 0x104BD,
+ 0x104E6 => 0x104BE,
+ 0x104E7 => 0x104BF,
+ 0x104E8 => 0x104C0,
+ 0x104E9 => 0x104C1,
+ 0x104EA => 0x104C2,
+ 0x104EB => 0x104C3,
+ 0x104EC => 0x104C4,
+ 0x104ED => 0x104C5,
+ 0x104EE => 0x104C6,
+ 0x104EF => 0x104C7,
+ 0x104F0 => 0x104C8,
+ 0x104F1 => 0x104C9,
+ 0x104F2 => 0x104CA,
+ 0x104F3 => 0x104CB,
+ 0x104F4 => 0x104CC,
+ 0x104F5 => 0x104CD,
+ 0x104F6 => 0x104CE,
+ 0x104F7 => 0x104CF,
+ 0x104F8 => 0x104D0,
+ 0x104F9 => 0x104D1,
+ 0x104FA => 0x104D2,
+ 0x104FB => 0x104D3,
+ 0x10CC0 => 0x10C80,
+ 0x10CC1 => 0x10C81,
+ 0x10CC2 => 0x10C82,
+ 0x10CC3 => 0x10C83,
+ 0x10CC4 => 0x10C84,
+ 0x10CC5 => 0x10C85,
+ 0x10CC6 => 0x10C86,
+ 0x10CC7 => 0x10C87,
+ 0x10CC8 => 0x10C88,
+ 0x10CC9 => 0x10C89,
+ 0x10CCA => 0x10C8A,
+ 0x10CCB => 0x10C8B,
+ 0x10CCC => 0x10C8C,
+ 0x10CCD => 0x10C8D,
+ 0x10CCE => 0x10C8E,
+ 0x10CCF => 0x10C8F,
+ 0x10CD0 => 0x10C90,
+ 0x10CD1 => 0x10C91,
+ 0x10CD2 => 0x10C92,
+ 0x10CD3 => 0x10C93,
+ 0x10CD4 => 0x10C94,
+ 0x10CD5 => 0x10C95,
+ 0x10CD6 => 0x10C96,
+ 0x10CD7 => 0x10C97,
+ 0x10CD8 => 0x10C98,
+ 0x10CD9 => 0x10C99,
+ 0x10CDA => 0x10C9A,
+ 0x10CDB => 0x10C9B,
+ 0x10CDC => 0x10C9C,
+ 0x10CDD => 0x10C9D,
+ 0x10CDE => 0x10C9E,
+ 0x10CDF => 0x10C9F,
+ 0x10CE0 => 0x10CA0,
+ 0x10CE1 => 0x10CA1,
+ 0x10CE2 => 0x10CA2,
+ 0x10CE3 => 0x10CA3,
+ 0x10CE4 => 0x10CA4,
+ 0x10CE5 => 0x10CA5,
+ 0x10CE6 => 0x10CA6,
+ 0x10CE7 => 0x10CA7,
+ 0x10CE8 => 0x10CA8,
+ 0x10CE9 => 0x10CA9,
+ 0x10CEA => 0x10CAA,
+ 0x10CEB => 0x10CAB,
+ 0x10CEC => 0x10CAC,
+ 0x10CED => 0x10CAD,
+ 0x10CEE => 0x10CAE,
+ 0x10CEF => 0x10CAF,
+ 0x10CF0 => 0x10CB0,
+ 0x10CF1 => 0x10CB1,
+ 0x10CF2 => 0x10CB2,
+ 0x118C0 => 0x118A0,
+ 0x118C1 => 0x118A1,
+ 0x118C2 => 0x118A2,
+ 0x118C3 => 0x118A3,
+ 0x118C4 => 0x118A4,
+ 0x118C5 => 0x118A5,
+ 0x118C6 => 0x118A6,
+ 0x118C7 => 0x118A7,
+ 0x118C8 => 0x118A8,
+ 0x118C9 => 0x118A9,
+ 0x118CA => 0x118AA,
+ 0x118CB => 0x118AB,
+ 0x118CC => 0x118AC,
+ 0x118CD => 0x118AD,
+ 0x118CE => 0x118AE,
+ 0x118CF => 0x118AF,
+ 0x118D0 => 0x118B0,
+ 0x118D1 => 0x118B1,
+ 0x118D2 => 0x118B2,
+ 0x118D3 => 0x118B3,
+ 0x118D4 => 0x118B4,
+ 0x118D5 => 0x118B5,
+ 0x118D6 => 0x118B6,
+ 0x118D7 => 0x118B7,
+ 0x118D8 => 0x118B8,
+ 0x118D9 => 0x118B9,
+ 0x118DA => 0x118BA,
+ 0x118DB => 0x118BB,
+ 0x118DC => 0x118BC,
+ 0x118DD => 0x118BD,
+ 0x118DE => 0x118BE,
+ 0x118DF => 0x118BF,
+ 0x16E60 => 0x16E40,
+ 0x16E61 => 0x16E41,
+ 0x16E62 => 0x16E42,
+ 0x16E63 => 0x16E43,
+ 0x16E64 => 0x16E44,
+ 0x16E65 => 0x16E45,
+ 0x16E66 => 0x16E46,
+ 0x16E67 => 0x16E47,
+ 0x16E68 => 0x16E48,
+ 0x16E69 => 0x16E49,
+ 0x16E6A => 0x16E4A,
+ 0x16E6B => 0x16E4B,
+ 0x16E6C => 0x16E4C,
+ 0x16E6D => 0x16E4D,
+ 0x16E6E => 0x16E4E,
+ 0x16E6F => 0x16E4F,
+ 0x16E70 => 0x16E50,
+ 0x16E71 => 0x16E51,
+ 0x16E72 => 0x16E52,
+ 0x16E73 => 0x16E53,
+ 0x16E74 => 0x16E54,
+ 0x16E75 => 0x16E55,
+ 0x16E76 => 0x16E56,
+ 0x16E77 => 0x16E57,
+ 0x16E78 => 0x16E58,
+ 0x16E79 => 0x16E59,
+ 0x16E7A => 0x16E5A,
+ 0x16E7B => 0x16E5B,
+ 0x16E7C => 0x16E5C,
+ 0x16E7D => 0x16E5D,
+ 0x16E7E => 0x16E5E,
+ 0x16E7F => 0x16E5F,
+ 0x1E922 => 0x1E900,
+ 0x1E923 => 0x1E901,
+ 0x1E924 => 0x1E902,
+ 0x1E925 => 0x1E903,
+ 0x1E926 => 0x1E904,
+ 0x1E927 => 0x1E905,
+ 0x1E928 => 0x1E906,
+ 0x1E929 => 0x1E907,
+ 0x1E92A => 0x1E908,
+ 0x1E92B => 0x1E909,
+ 0x1E92C => 0x1E90A,
+ 0x1E92D => 0x1E90B,
+ 0x1E92E => 0x1E90C,
+ 0x1E92F => 0x1E90D,
+ 0x1E930 => 0x1E90E,
+ 0x1E931 => 0x1E90F,
+ 0x1E932 => 0x1E910,
+ 0x1E933 => 0x1E911,
+ 0x1E934 => 0x1E912,
+ 0x1E935 => 0x1E913,
+ 0x1E936 => 0x1E914,
+ 0x1E937 => 0x1E915,
+ 0x1E938 => 0x1E916,
+ 0x1E939 => 0x1E917,
+ 0x1E93A => 0x1E918,
+ 0x1E93B => 0x1E919,
+ 0x1E93C => 0x1E91A,
+ 0x1E93D => 0x1E91B,
+ 0x1E93E => 0x1E91C,
+ 0x1E93F => 0x1E91D,
+ 0x1E940 => 0x1E91E,
+ 0x1E941 => 0x1E91F,
+ 0x1E942 => 0x1E920,
+ 0x1E943 => 0x1E921,
+);
diff --git a/src/opis/string/src/Exception/InvalidCodePointException.php b/src/opis/string/src/Exception/InvalidCodePointException.php
index f1a3fe96..f93dc6b9 100644
--- a/src/opis/string/src/Exception/InvalidCodePointException.php
+++ b/src/opis/string/src/Exception/InvalidCodePointException.php
@@ -1,5 +1,6 @@
codePoint = $codePoint;
- }
+ /**
+ * @var mixed
+ */
+ protected $codePoint;
- /**
- * @return mixed
- */
- public function codePoint()
- {
- return$this->codePoint;
- }
+ /**
+ * @param $codePoint
+ * @param Throwable|null $previous
+ */
+ public function __construct( $codePoint, Throwable $previous = null ) {
+ parent::__construct( 'Invalid code point', 0, $previous );
+ $this->codePoint = $codePoint;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function codePoint() {
+ return $this->codePoint;
+ }
}
diff --git a/src/opis/string/src/Exception/InvalidStringException.php b/src/opis/string/src/Exception/InvalidStringException.php
index ede9d682..c5731f9e 100644
--- a/src/opis/string/src/Exception/InvalidStringException.php
+++ b/src/opis/string/src/Exception/InvalidStringException.php
@@ -1,5 +1,6 @@
string = $string;
- $this->offset = $offset;
- }
-
- /**
- * @return string
- */
- public function string(): string
- {
- return $this->string;
- }
-
- /**
- * @return int
- */
- public function offset(): int
- {
- return $this->offset;
- }
+class InvalidStringException extends UnicodeException {
+
+ /**
+ * @var string
+ */
+ protected $string;
+
+ /**
+ * @var int
+ */
+ protected $offset;
+
+ /**
+ * @param string $string
+ * @param int $offset
+ * @param Throwable|null $previous
+ */
+ public function __construct( string $string, int $offset = -1, Throwable $previous = null ) {
+ parent::__construct( "Invalid UTF-8 string at offset {$offset}", 0, $previous );
+ $this->string = $string;
+ $this->offset = $offset;
+ }
+
+ /**
+ * @return string
+ */
+ public function string(): string {
+ return $this->string;
+ }
+
+ /**
+ * @return int
+ */
+ public function offset(): int {
+ return $this->offset;
+ }
}
diff --git a/src/opis/string/src/Exception/UnicodeException.php b/src/opis/string/src/Exception/UnicodeException.php
index 22e6d2fa..88993be3 100644
--- a/src/opis/string/src/Exception/UnicodeException.php
+++ b/src/opis/string/src/Exception/UnicodeException.php
@@ -1,5 +1,6 @@
codes = $codes;
- $this->length = count($codes);
- }
-
- /**
- * @return int[]
- */
- public function codePoints(): array
- {
- return $this->codes;
- }
-
- /**
- * @return string[]
- */
- public function chars(): array
- {
- if ($this->chars === null) {
- $this->chars = self::getCharsFromCodePoints($this->codes);
- }
- return $this->chars;
- }
-
- /**
- * @return int
- */
- public function length(): int
- {
- return $this->length;
- }
-
- /**
- * @return bool
- */
- public function isEmpty(): bool
- {
- return $this->length === 0;
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param bool $ignoreCase
- * @return bool
- */
- public function equals($text, $ignoreCase = false): bool
- {
- return $this->compareTo($text, $ignoreCase) === 0;
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param bool $ignoreCase
- * @return int
- */
- public function compareTo($text, $ignoreCase = false): int
- {
- $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
-
- $text = self::resolveCodePoints($text, $mode);
-
- $length = count($text);
-
- if ($length !== $this->length) {
- return $this->length <=> $length;
- }
-
- return $this->getMappedCodes($mode) <=> $text;
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param bool $ignoreCase
- * @return bool
- */
- public function contains($text, $ignoreCase = false): bool
- {
- return $this->indexOf($text, 0, $ignoreCase) !== -1;
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param bool $ignoreCase
- * @return bool
- */
- public function startsWith($text, $ignoreCase = false): bool
- {
- $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
-
- $text = self::resolveCodePoints($text, $mode);
-
- $len = count($text);
-
- if ($len === 0 || $len > $this->length) {
- return false;
- }
-
- return array_slice($this->getMappedCodes($mode), 0, $len) === $text;
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param bool $ignoreCase
- * @return bool
- */
- public function endsWith($text, $ignoreCase = false): bool
- {
- $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
-
- $text = self::resolveCodePoints($text, $mode);
-
- if (empty($text)) {
- return false;
- }
-
- $codes = $this->getMappedCodes($mode);
-
- $offset = $this->length - count($text);
-
- if ($offset < 0) {
- return false;
- }
-
- return array_slice($codes, $offset) === $text;
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param int $offset
- * @param bool $ignoreCase
- * @return int
- */
- public function indexOf($text, $offset = 0, $ignoreCase = false): int
- {
- if ($offset < 0) {
- $offset += $this->length;
- }
- if ($offset < 0 || $offset >= $this->length) {
- return -1;
- }
-
- $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
-
- $text = self::resolveCodePoints($text, $mode);
-
- $len = count($text);
-
- if ($len === 0 || $offset + $len > $this->length) {
- return -1;
- }
-
- return $this->doIndexOf($this->getMappedCodes($mode), $text, $offset);
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param int $offset
- * @param bool $ignoreCase
- * @return int
- */
- public function lastIndexOf($text, $offset = 0, $ignoreCase = false): int
- {
- if ($offset < 0) {
- $start = $this->length + $offset;
- if ($start < 0) {
- return -1;
- }
- $last = 0;
- } else {
- if ($offset >= $this->length) {
- return -1;
- }
- $start = $this->length - 1;
- $last = $offset;
- }
-
- $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
-
- $text = self::resolveCodePoints($text, $mode);
-
- $len = count($text);
-
- if ($len === 0) {
- return -1;
- }
-
- if ($offset < 0) {
- if ($len > $this->length) {
- return -1;
- }
- $start = min($start, $this->length - $len);
- } elseif ($offset + $len > $this->length) {
- return -1;
- }
-
- $codes = $this->getMappedCodes($mode);
-
- for ($i = $start; $i >= $last; $i--) {
- $match = true;
-
- for ($j = 0; $j < $len; $j++) {
- if ($codes[$i + $j] !== $text[$j]) {
- $match = false;
- break;
- }
- }
-
- if ($match) {
- return $i;
- }
- }
-
- return -1;
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param bool $ignoreCase
- * @param bool $allowPrefixOnly If true the result can contain only the prefix
- * @return $this
- */
- public function ensurePrefix($text, $ignoreCase = false, $allowPrefixOnly = true): self
- {
- $text = self::resolveCodePoints($text);
-
- $len = count($text);
-
- if ($len === 0) {
- return clone $this;
- }
-
- if ($this->length === 0) {
- return new static($text);
- }
-
- if ($ignoreCase) {
- $prefix = self::getMappedCodePoints($text, self::FOLD_CASE);
- } else {
- $prefix = &$text;
- }
-
- if ($this->length === $len) {
- $part = $this->getMappedCodes($ignoreCase ? self::FOLD_CASE : self::KEEP_CASE);
- if ($allowPrefixOnly && $part === $prefix) {
- return clone $this;
- }
- // Remove last element to avoid double check
- array_pop($part);
- } elseif ($this->length < $len) {
- $part = $this->getMappedCodes($ignoreCase ? self::FOLD_CASE : self::KEEP_CASE);
- // Checks if this can be a suffix
- if ($allowPrefixOnly && (array_slice($prefix, 0, $this->length) === $part)) {
- $text = array_slice($text, $this->length);
- return new static(array_merge($this->codes, $text));
- }
- } else {
- $part = array_slice($this->codes, 0, $len);
- if ($ignoreCase) {
- $part = self::getMappedCodePoints($part, self::FOLD_CASE);
- }
- if ($part === $prefix) {
- return clone $this;
- }
- // Remove last element to avoid double check
- array_pop($part);
- }
-
- $copy = $len;
-
- $part_len = count($part);
-
- while ($part_len) {
- if ($part === array_slice($prefix, -$part_len)) {
- $copy = $len - $part_len;
- break;
- }
- array_pop($part);
- $part_len--;
- }
-
- if ($copy === 0) {
- return clone $this;
- }
-
- if ($copy < $len) {
- $text = array_slice($text, 0, $copy);
- }
-
- return new static(array_merge($text, $this->codes));
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param bool $ignoreCase
- * @param bool $allowSuffixOnly If true the result can contain only the suffix
- * @return static
- */
- public function ensureSuffix($text, $ignoreCase = false, $allowSuffixOnly = true): self
- {
- $text = self::resolveCodePoints($text);
-
- $len = count($text);
-
- if ($len === 0) {
- return clone $this;
- }
-
- if ($this->length === 0) {
- return new static($text);
- }
-
- if ($ignoreCase) {
- $suffix = self::getMappedCodePoints($text, self::FOLD_CASE);
- } else {
- $suffix = &$text;
- }
-
- if ($this->length === $len) {
- $part = $this->getMappedCodes($ignoreCase ? self::FOLD_CASE : self::KEEP_CASE);
- if ($allowSuffixOnly && $part === $suffix) {
- return clone $this;
- }
- // Remove first element to avoid double check
- array_shift($part);
- } elseif ($this->length < $len) {
- $part = $this->getMappedCodes($ignoreCase ? self::FOLD_CASE : self::KEEP_CASE);
- // Checks if this can be a prefix
- if ($allowSuffixOnly && (array_slice($suffix, -$this->length) === $part)) {
- $text = array_slice($text, 0, $len - $this->length);
- return new static(array_merge($text, $this->codes));
- }
- } else {
- $part = array_slice($this->codes, -$len);
- if ($ignoreCase) {
- $part = self::getMappedCodePoints($part, self::FOLD_CASE);
- }
- if ($part === $suffix) {
- return clone $this;
- }
- // Remove first element to avoid double check
- array_shift($part);
- }
-
- $skip = 0;
-
- $part_len = count($part);
-
- while ($part_len) {
- if ($part === array_slice($suffix, 0, $part_len)) {
- $skip = $part_len;
- break;
- }
- array_shift($part);
- $part_len--;
- }
-
- if ($skip === $len) {
- return clone $this;
- }
-
- if ($skip) {
- array_splice($text, 0, $skip);
- }
-
- return new static(array_merge($this->codes, $text));
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param int $mode
- * @return static
- */
- public function append($text, $mode = self::KEEP_CASE): self
- {
- return new static(array_merge($this->codes, self::resolveCodePoints($text, $mode)));
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param int $mode
- * @return static
- */
- public function prepend($text, $mode = self::KEEP_CASE): self
- {
- return new static(array_merge(self::resolveCodePoints($text, $mode), $this->codes));
- }
-
- /**
- * @param string|self|int[]|string[] $text
- * @param int $offset
- * @param int $mode
- * @return static
- */
- public function insert($text, $offset, $mode = self::KEEP_CASE): self
- {
- $codes = $this->codes;
-
- array_splice($codes, $offset, 0, self::resolveCodePoints($text, $mode));
-
- return new static($codes);
- }
-
- /**
- * @param int $offset
- * @param int|null $length
- * @return static
- */
- public function remove($offset, $length = null): self
- {
- $codes = $this->codes;
-
- if ($length === null) {
- array_splice($codes, $offset);
- } else {
- array_splice($codes, $offset, $length);
- }
-
- return new static($codes);
- }
-
- /**
- * @param string|self|int[]|string[] $mask
- * @return static
- */
- public function trim($mask = " \t\n\r\0\x0B"): self
- {
- return $this->doTrim($mask, true, true);
- }
-
- /**
- * @param string|self|int[]|string[] $mask
- * @return static
- */
- public function trimLeft($mask = " \t\n\r\0\x0B"): self
- {
- return $this->doTrim($mask, true, false);
- }
-
- /**
- * @param string|self|int[]|string[] $mask
- * @return static
- */
- public function trimRight($mask = " \t\n\r\0\x0B"): self
- {
- return $this->doTrim($mask, false, true);
- }
-
- /**
- * @return static
- */
- public function reverse(): self
- {
- return new static(array_reverse($this->codes));
- }
-
- /**
- * @param int $times
- * @return static
- */
- public function repeat($times = 1): self
- {
- if ($times <= 1) {
- return clone $this;
- }
-
- $codes = [];
-
- while ($times--) {
- $codes = array_merge($codes, $this->codes);
- }
-
- return new static($codes);
- }
-
- /**
- * @param string|self|int[]|string[] $subject
- * @param string|self|int[]|string[] $replace
- * @param int $offset
- * @param bool $ignoreCase
- * @return static
- */
- public function replace($subject, $replace, $offset = 0, $ignoreCase = false): self
- {
- if ($offset < 0) {
- $offset += $this->length;
- }
- if ($offset < 0 || $offset >= $this->length) {
- return clone $this;
- }
-
- $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
-
- $subject = self::resolveCodePoints($subject, $mode);
-
- $len = count($subject);
-
- if ($len === 0 || $offset + $len > $this->length) {
- return clone $this;
- }
-
- $offset = $this->doIndexOf($this->getMappedCodes($mode), $subject, $offset);
-
- if ($offset === -1) {
- return clone $this;
- }
-
- $codes = $this->codes;
-
- array_splice($codes, $offset, count($subject), self::resolveCodePoints($replace));
-
- return new static($codes);
- }
-
- /**
- * @param string|self|int[]|string[] $subject
- * @param string|self|int[]|string[] $replace
- * @param bool $ignoreCase
- * @param int $offset
- * @return static
- */
- public function replaceAll($subject, $replace, $offset = 0, $ignoreCase = false): self
- {
- if ($offset < 0) {
- $offset += $this->length;
- }
- if ($offset < 0 || $offset >= $this->length) {
- return clone $this;
- }
-
- $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
-
- $subject = self::resolveCodePoints($subject, $mode);
-
- $len = count($subject);
-
- if ($len === 0 || $offset + $len > $this->length) {
- return clone $this;
- }
-
- $replace = self::resolveCodePoints($replace);
-
- $codes = $this->getMappedCodes($mode);
-
- $copy = $this->codes;
-
- $fix = count($replace) - $len;
-
- $t = 0;
-
- while (($pos = $this->doIndexOf($codes, $subject, $offset)) >= 0) {
- array_splice($copy, $pos + $t * $fix, $len, $replace);
- $offset = $pos + $len;
- $t++;
- }
-
- return new static($copy);
- }
-
- /**
- * @param string|self|int[]|string[] $delimiter
- * @param bool $ignoreCase
- * @return array
- */
- public function split($delimiter = '', $ignoreCase = false): array
- {
- $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
- $delimiter = self::resolveCodePoints($delimiter, $mode);
- $len = count($delimiter);
-
- $ret = [];
-
- if ($len === 0) {
- foreach ($this->codes as $code) {
- $ret[] = new static([$code]);
- }
- } else {
- $codes = $this->getMappedCodes($mode);
-
- $offset = 0;
-
- while (($pos = $this->doIndexOf($codes, $delimiter, $offset)) >= 0) {
- $ret[] = new static(array_slice($this->codes, $offset, $pos - $offset));
- $offset = $pos + $len;
- }
-
- $ret[] = new static(array_slice($this->codes, $offset));
- }
-
- return $ret;
- }
-
- /**
- * @param int $start
- * @param int|null $length
- * @return static
- */
- public function substring($start, $length = null): self
- {
- return new static(array_slice($this->codes, $start, $length));
- }
-
- /**
- * @param int $size If negative then pad left otherwise pad right
- * @param self|string|int $char A char or a code point
- * @return static
- */
- public function pad($size, $char = 0x20): self
- {
- return new static(array_pad($this->codes, $size, self::resolveFirstCodePoint($char, 0x20)));
- }
-
- /**
- * @param int $size
- * @param self|string|int $char
- * @return static
- */
- public function padLeft($size, $char = 0x20): self
- {
- if ($size > 0) {
- $size = -$size;
- }
-
- return $this->pad($size, $char);
- }
-
- /**
- * @param int $size
- * @param self|string|int $char
- * @return static
- */
- public function padRight($size, $char = 0x20): self
- {
- if ($size < 0) {
- $size = -$size;
- }
-
- return $this->pad($size, $char);
- }
-
- /**
- * @return bool
- */
- public function isLowerCase(): bool
- {
- return $this->isCase(self::LOWER_CASE);
- }
-
- /**
- * @return bool
- */
- public function isUpperCase(): bool
- {
- return $this->isCase(self::UPPER_CASE);
- }
-
- /**
- * @return bool
- */
- public function isAscii(): bool
- {
- $key = 'i' . self::ASCII_CONV;
-
- if (!isset($this->cache[$key])) {
- $ok = true;
-
- foreach ($this->codes as $code) {
- if ($code >= 0x80) {
- $ok = false;
- break;
- }
- }
-
- $this->cache[$key] = $ok;
- }
-
- return $this->cache[$key];
- }
-
- /**
- * Convert all chars to lower case (where possible)
- * @return static
- */
- public function toLower(): self
- {
- if ($this->cache['i' . self::LOWER_CASE] ?? false) {
- return clone $this;
- }
- return new static($this->getMappedCodes(self::LOWER_CASE));
- }
-
- /**
- * Convert all chars to upper case (where possible)
- * @return static
- */
- public function toUpper(): self
- {
- if ($this->cache['i' . self::UPPER_CASE] ?? false) {
- return clone $this;
- }
- return new static($this->getMappedCodes(self::UPPER_CASE));
- }
-
- /**
- * Converts all chars to their ASCII equivalent (if any)
- * @return static
- */
- public function toAscii(): self
- {
- if ($this->cache['i' . self::ASCII_CONV] ?? false) {
- return clone $this;
- }
- return new static($this->getMappedCodes(self::ASCII_CONV));
- }
-
- /**
- * @param int $index
- * @return string
- */
- public function charAt($index): string
- {
- // Allow negative index
- if ($index < 0 && $index + $this->length >= 0) {
- $index += $this->length;
- }
-
- if ($index < 0 || $index >= $this->length) {
- return '';
- }
-
- return $this->chars()[$index];
- }
-
- /**
- * @param int $index
- * @return int
- */
- public function codePointAt($index): int
- {
- // Allow negative index
- if ($index < 0 && $index + $this->length >= 0) {
- $index += $this->length;
- }
-
- if ($index < 0 || $index >= $this->length) {
- return -1;
- }
-
- return $this->codes[$index];
- }
-
- /**
- * @param int $offset
- * @return int
- */
- public function __invoke(int $offset): int
- {
- if ($offset < 0) {
- if ($offset + $this->length < 0) {
- throw new OutOfBoundsException("Undefined offset: {$offset}");
- }
- $offset += $this->length;
- } elseif ($offset >= $this->length) {
- throw new OutOfBoundsException("Undefined offset: {$offset}");
- }
-
- return $this->codes[$offset];
- }
-
- /**
- * @inheritDoc
- */
- public function offsetExists($offset): bool
- {
- // Allow negative index
- if ($offset < 0) {
- $offset += $this->length;
- }
-
- return isset($this->codes[$offset]);
- }
-
- /**
- * @inheritDoc
- */
- public function offsetGet($offset): string
- {
- if ($offset < 0) {
- if ($offset + $this->length < 0) {
- throw new OutOfBoundsException("Undefined offset: {$offset}");
- }
- $offset += $this->length;
- } elseif ($offset >= $this->length) {
- throw new OutOfBoundsException("Undefined offset: {$offset}");
- }
-
- return $this->chars()[$offset];
- }
-
- /**
- * @inheritDoc
- */
- #[\ReturnTypeWillChange]
- public function offsetSet($offset, $value)
- {
- // Allow negative index
- if ($offset < 0) {
- $offset += $this->length;
- }
-
- if (!isset($this->codes[$offset])) {
- return;
- }
-
-
- $value = self::resolveFirstCodePoint($value);
- if ($value === -1) {
- return;
- }
-
- if ($value === $this->codes[$offset]) {
- // Same value, nothing to do
- return;
- }
-
- $this->codes[$offset] = $value;
-
- // Clear cache
- $this->str = null;
- $this->cache = null;
- if ($this->chars) {
- $this->chars[$offset] = self::getCharFromCodePoint($value);
- }
- }
-
- /**
- * @inheritDoc
- */
- #[\ReturnTypeWillChange]
- public function offsetUnset($offset)
- {
- throw new RuntimeException("Invalid operation");
- }
-
- /**
- * @inheritDoc
- */
- public function count(): int
- {
- return $this->length;
- }
-
- /**
- * @return string
- */
- public function __toString(): string
- {
- if ($this->str === null) {
- $this->str = self::getStringFromCodePoints($this->codes);
- }
-
- return $this->str;
- }
-
- /**
- * @inheritDoc
- */
- public function jsonSerialize(): string
- {
- return $this->__toString();
- }
-
- public function __serialize(): array
- {
- return [
- 'value' => $this->__toString(),
- ];
- }
-
- public function __unserialize(array $data)
- {
- $this->str = $data['value'];
- $this->codes = self::getCodePointsFromString($this->str);
- $this->length = count($this->codes);
- }
-
- /**
- * Creates an unicode string instance from raw string
- * @param string $string
- * @param string|null $encoding Defaults to UTF-8
- * @param int $mode
- * @return static
- * @throws InvalidStringException
- */
- public static function from($string, $encoding = null, $mode = self::KEEP_CASE): self
- {
- if ($encoding !== null && strcasecmp($encoding, 'UTF-8') !== 0) {
- if (false === $string = @iconv($encoding, 'UTF-8', $string)) {
- throw new UnicodeException("Could not convert string from '$encoding' encoding to UTF-8 encoding");
- }
- }
-
- $instance = new static(self::getCodePointsFromString($string, $mode));
- if ($mode === self::KEEP_CASE) {
- $instance->str = $string;
- }
- return $instance;
- }
-
- /**
- * Creates an unicode string instance from code points
- * @param int[] $codes
- * @param int $mode
- * @return static
- * @throws InvalidCodePointException
- */
- public static function fromCodePoints($codes, $mode = self::KEEP_CASE): self
- {
- $map = self::getMapByMode($mode);
-
- foreach ($codes as &$code) {
- if (!is_int($codes) || !self::isValidCodePoint($code)) {
- throw new InvalidCodePointException($code);
- } else {
- $code = $map[$code] ?? $code;
- }
- }
-
- return new static(array_values($codes));
- }
-
- /**
- * Converts the code point to corresponding char
- * @param int $code
- * @return string The char or an empty string if code point is invalid
- */
- public static function getCharFromCodePoint($code): string
- {
- if ($code < 0) {
- return '';
- }
-
- if ($code < 0x80) {
- return chr($code);
- }
-
- if ($code < 0x800) {
- return chr(($code >> 6) + 0xC0) . chr(($code & 0x3F) + 0x80);
- }
-
- if ($code >= 0xD800 && $code <= 0xDFFF) {
- /*
- The definition of UTF-8 prohibits encoding character numbers between
- U+D800 and U+DFFF, which are reserved for use with the UTF-16
- encoding form (as surrogate pairs) and do not directly represent characters.
- */
- return '';
- }
-
- if ($code <= 0xFFFF) {
- return
- chr(($code >> 12) + 0xE0) .
- chr((($code >> 6) & 0x3F) + 0x80) .
- chr(($code & 0x3F) + 0x80);
- }
-
- if ($code <= 0x10FFFF) {
- return
- chr(($code >> 18) + 0xF0) .
- chr((($code >> 12) & 0x3F) + 0x80) .
- chr((($code >> 6) & 0x3F) + 0x80) .
- chr(($code & 0x3F) + 0x80);
- }
-
- /*
- Restricted the range of characters to 0000-10FFFF (the UTF-16 accessible range).
- */
-
- return '';
- }
-
- /**
- * Convert a string to a code point array
- * @param string $str
- * @param int $mode
- * @return array
- * @throws InvalidStringException
- */
- public static function getCodePointsFromString($str, $mode = self::KEEP_CASE): array
- {
- // 0x00-0x7F
- // 0xC2-0xDF 0x80-0xBF
- // 0xE0-0xE0 0xA0-0xBF 0x80-0xBF
- // 0xE1-0xEC 0x80-0xBF 0x80-0xBF
- // 0xED-0xED 0x80-0x9F 0x80-0xBF
- // 0xEE-0xEF 0x80-0xBF 0x80-0xBF
- // 0xF0-0xF0 0x90-0xBF 0x80-0xBF 0x80-0xBF
- // 0xF1-0xF3 0x80-0xBF 0x80-0xBF 0x80-0xBF
- // 0xF4-0xF4 0x80-0x8F 0x80-0xBF 0x80-0xBF
-
- $codes = [];
- $length = strlen($str);
- $mode = self::getMapByMode($mode);
-
- $i = 0;
- while ($i < $length) {
- $ord0 = ord($str[$i++]);
-
- if ($ord0 < 0x80) {
- $codes[] = $mode[$ord0] ?? $ord0;
- continue;
- }
-
- if ($i === $length || $ord0 < 0xC2 || $ord0 > 0xF4) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- $ord1 = ord($str[$i++]);
-
- if ($ord0 < 0xE0) {
- if ($ord1 < 0x80 || $ord1 >= 0xC0) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- $ord1 = ($ord0 - 0xC0) * 64 + $ord1 - 0x80;
- $codes[] = $mode[$ord1] ?? $ord1;
-
- continue;
- }
-
- if ($i === $length) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- $ord2 = ord($str[$i++]);
-
- if ($ord0 < 0xF0) {
- if ($ord0 === 0xE0) {
- if ($ord1 < 0xA0 || $ord1 >= 0xC0) {
- throw new InvalidStringException($str, $i - 2);
- }
- } elseif ($ord0 === 0xED) {
- if ($ord1 < 0x80 || $ord1 >= 0xA0) {
- throw new InvalidStringException($str, $i - 2);
- }
- } elseif ($ord1 < 0x80 || $ord1 >= 0xC0) {
- throw new InvalidStringException($str, $i - 2);
- }
-
- if ($ord2 < 0x80 || $ord2 >= 0xC0) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- $ord2 = ($ord0 - 0xE0) * 0x1000 + ($ord1 - 0x80) * 64 + $ord2 - 0x80;
- $codes[] = $mode[$ord2] ?? $ord2;
-
- continue;
- }
-
- if ($i === $length) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- $ord3 = ord($str[$i++]);
-
- if ($ord0 < 0xF5) {
- if ($ord0 === 0xF0) {
- if ($ord1 < 0x90 || $ord1 >= 0xC0) {
- throw new InvalidStringException($str, $i - 3);
- }
- } elseif ($ord0 === 0xF4) {
- if ($ord1 < 0x80 || $ord1 >= 0x90) {
- throw new InvalidStringException($str, $i - 3);
- }
- } elseif ($ord1 < 0x80 || $ord1 >= 0xC0) {
- throw new InvalidStringException($str, $i - 3);
- }
-
- if ($ord2 < 0x80 || $ord2 >= 0xC0) {
- throw new InvalidStringException($str, $i - 2);
- }
-
- if ($ord3 < 0x80 || $ord3 >= 0xC0) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- $ord3 = ($ord0 - 0xF0) * 0x40000 + ($ord1 - 0x80) * 0x1000 + ($ord2 - 0x80) * 64 + $ord3 - 0x80;
- $codes[] = $mode[$ord3] ?? $ord3;
-
- continue;
- }
-
- throw new InvalidStringException($str, $i - 1);
- }
-
- return $codes;
- }
-
- /**
- * @param string $str
- * @return iterable
- *
- * The key represents the current char index
- * Value is a two element array
- * - first element is an integer representing the code point
- * - second element is an array of integers (length 1 to 4) representing bytes
- */
- public static function walkString($str)
- {
- $i = 0;
- $length = strlen($str);
-
- while ($i < $length) {
- $index = $i;
-
- $ord0 = ord($str[$i++]);
-
- if ($ord0 < 0x80) {
- yield $index => [
- $ord0,
- [$ord0]
- ];
- continue;
- }
-
- if ($i === $length || $ord0 < 0xC2 || $ord0 > 0xF4) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- $ord1 = ord($str[$i++]);
-
- if ($ord0 < 0xE0) {
- if ($ord1 < 0x80 || $ord1 >= 0xC0) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- yield $index => [
- ($ord0 - 0xC0) * 64 + $ord1 - 0x80,
- [$ord0, $ord1]
- ];
-
- continue;
- }
-
- if ($i === $length) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- $ord2 = ord($str[$i++]);
-
- if ($ord0 < 0xF0) {
- if ($ord0 === 0xE0) {
- if ($ord1 < 0xA0 || $ord1 >= 0xC0) {
- throw new InvalidStringException($str, $i - 2);
- }
- } elseif ($ord0 === 0xED) {
- if ($ord1 < 0x80 || $ord1 >= 0xA0) {
- throw new InvalidStringException($str, $i - 2);
- }
- } elseif ($ord1 < 0x80 || $ord1 >= 0xC0) {
- throw new InvalidStringException($str, $i - 2);
- }
-
- if ($ord2 < 0x80 || $ord2 >= 0xC0) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- yield $index => [
- ($ord0 - 0xE0) * 0x1000 + ($ord1 - 0x80) * 64 + $ord2 - 0x80,
- [$ord0, $ord1, $ord2]
- ];
-
- continue;
- }
-
- if ($i === $length) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- $ord3 = ord($str[$i++]);
-
- if ($ord0 < 0xF5) {
- if ($ord0 === 0xF0) {
- if ($ord1 < 0x90 || $ord1 >= 0xC0) {
- throw new InvalidStringException($str, $i - 3);
- }
- } elseif ($ord0 === 0xF4) {
- if ($ord1 < 0x80 || $ord1 >= 0x90) {
- throw new InvalidStringException($str, $i - 3);
- }
- } elseif ($ord1 < 0x80 || $ord1 >= 0xC0) {
- throw new InvalidStringException($str, $i - 3);
- }
-
- if ($ord2 < 0x80 || $ord2 >= 0xC0) {
- throw new InvalidStringException($str, $i - 2);
- }
-
- if ($ord3 < 0x80 || $ord3 >= 0xC0) {
- throw new InvalidStringException($str, $i - 1);
- }
-
- yield $index => [
- ($ord0 - 0xF0) * 0x40000 + ($ord1 - 0x80) * 0x1000 + ($ord2 - 0x80) * 64 + $ord3 - 0x80,
- [$ord0, $ord1, $ord2, $ord3]
- ];
-
- continue;
- }
-
- throw new InvalidStringException($str, $i - 1);
- }
- }
-
- /**
- * Converts each code point to a char
- * @param array $codes
- * @param int $mode
- * @return array
- * @throws InvalidCodePointException
- */
- public static function getCharsFromCodePoints($codes, $mode = self::KEEP_CASE): array
- {
- $mode = self::getMapByMode($mode);
-
- foreach ($codes as &$code) {
- $char = self::getCharFromCodePoint($mode[$code] ?? $code);
- if ($char === '') {
- throw new InvalidCodePointException($code);
- } else {
- $code = $char;
- }
- }
-
- return $codes;
- }
-
- /**
- * @param string $str
- * @param int $mode
- * @return string[]
- */
- public static function getCharsFromString($str, $mode = self::KEEP_CASE): array
- {
- return self::getCharsFromCodePoints(self::getCodePointsFromString($str), $mode);
- }
-
- /**
- * Converts all code points to chars and returns the string
- * Invalid code points are ignored
- * @param array $codes
- * @param int $mode
- * @return string
- */
- public static function getStringFromCodePoints($codes, $mode = self::KEEP_CASE): string
- {
- $str = '';
-
- $mode = self::getMapByMode($mode);
-
- foreach ($codes as $code) {
- if (isset($mode[$code])) {
- $code = $mode[$code];
- }
-
- if ($code < 0x80) {
- $str .= chr($code);
- continue;
- }
-
- if ($code < 0x800) {
- $str .= chr(($code >> 6) + 0xC0) . chr(($code & 0x3F) + 0x80);
- continue;
- }
-
- if ($code >= 0xD800 && $code <= 0xDFFF) {
- continue;
- }
-
- if ($code <= 0xFFFF) {
- $str .=
- chr(($code >> 12) + 0xE0) .
- chr((($code >> 6) & 0x3F) + 0x80) .
- chr(($code & 0x3F) + 0x80);
- continue;
- }
-
- if ($code <= 0x10FFFF) {
- $str .=
- chr(($code >> 18) + 0xF0) .
- chr((($code >> 12) & 0x3F) + 0x80) .
- chr((($code >> 6) & 0x3F) + 0x80) .
- chr(($code & 0x3F) + 0x80);
- }
- }
-
- return $str;
- }
-
- /**
- * @param array $codes
- * @param int $mode
- * @return array
- */
- public static function getMappedCodePoints($codes, $mode): array
- {
- if ($mode === self::KEEP_CASE) {
- return $codes;
- }
-
- $mode = self::getMapByMode($mode);
-
- if (empty($mode)) {
- return $codes;
- }
-
- foreach ($codes as &$code) {
- $code = $mode[$code] ?? $code;
- }
-
- return $codes;
- }
-
- /**
- * Checks if a code point is valid
- * @param int $code
- * @return bool
- */
- public static function isValidCodePoint($code): bool
- {
- if ($code < 0 || $code > 0x10FFFF) {
- return false;
- }
-
- return $code < 0xD800 || $code > 0xDFFF;
- }
-
- /**
- * @param int $mode
- * @return int[]
- */
- private function getMappedCodes(int $mode): array
- {
- if ($mode === self::KEEP_CASE || ($this->cache['i' . $mode] ?? false)) {
- return $this->codes;
- }
-
- $key = 'm' . $mode;
-
- if (!isset($this->cache[$key])) {
- $this->cache[$key] = self::getMappedCodePoints($this->codes, $mode);
- }
-
- return $this->cache[$key];
- }
-
- /**
- * @param int $mode
- * @return bool
- */
- private function isCase(int $mode): bool
- {
- $key = 'i' . $mode;
-
- if (!isset($this->cache[$key])) {
- $list = self::getMapByMode($mode);
- foreach ($this->codes as $code) {
- if (isset($list[$code])) {
- return $this->cache[$key] = false;
- }
- }
-
- return $this->cache[$key] = true;
- }
-
- return $this->cache[$key];
- }
-
- /**
- * @param int[] $codes
- * @param int[] $text
- * @param int $offset
- * @return int
- */
- private function doIndexOf(array $codes, array $text, int $offset = 0): int
- {
- $len = count($text);
-
- for ($i = $offset, $last = count($codes) - $len; $i <= $last; $i++) {
- $match = true;
-
- for ($j = 0; $j < $len; $j++) {
- if ($codes[$i + $j] !== $text[$j]) {
- $match = false;
- break;
- }
- }
-
- if ($match) {
- return $i;
- }
- }
-
- return -1;
- }
-
- /**
- * @param string|self|int[]|string[] $mask
- * @param bool $left
- * @param bool $right
- * @return static
- */
- private function doTrim($mask, bool $left, bool $right): self
- {
- if ($this->length === 0) {
- return clone $this;
- }
-
- $mask = self::resolveCodePoints($mask);
-
- if (empty($mask)) {
- return clone $this;
- }
-
- $codes = $this->codes;
-
- if ($left) {
- while (in_array($codes[0], $mask, true)) {
- array_shift($codes);
- if (empty($codes)) {
- return new static();
- }
- }
- }
-
- if ($right) {
- $last = count($codes) - 1;
- while (in_array($codes[$last], $mask, true)) {
- array_pop($codes);
- if (--$last < 0) {
- return new static();
- }
- }
- }
-
- return new static($codes);
- }
-
-
- /**
- * @param string|self|int[]|string[] $text
- * @param int $mode
- * @return array
- */
- private static function resolveCodePoints($text, int $mode = self::KEEP_CASE): array
- {
- if ($text instanceof self) {
- return $text->getMappedCodes($mode);
- }
-
- if (is_string($text)) {
- return self::getCodePointsFromString($text, $mode);
- }
-
- if ($text && is_array($text) && is_int($text[0])) {
- // assume code point array
- return self::getMappedCodePoints($text, $mode);
- }
-
- return [];
- }
-
- /**
- * @param self|string|int|string[]|int[] $text
- * @param int $invalid
- * @return int
- */
- private static function resolveFirstCodePoint($text, int $invalid = -1): int
- {
- if ($text instanceof self) {
- return $text->length === 0 ? $invalid : $text->codes[0];
- }
-
- if (is_array($text)) {
- if (empty($text)) {
- return $invalid;
- }
- $text = reset($text);
- }
-
- if (is_string($text)) {
- if (isset($text[4])) {
- $text = substr($text, 0, 4);
- }
- return self::getCodePointsFromString($text)[0] ?? $invalid;
- }
-
- if (is_int($text)) {
- return self::isValidCodePoint($text) ? $text : $invalid;
- }
-
- return $invalid;
- }
-
- /**
- * @param int $mode
- * @return int[]
- */
- private static function getMapByMode(int $mode): array
- {
- if (isset(self::$maps[$mode])) {
- return self::$maps[$mode];
- }
-
- switch ($mode) {
- case self::LOWER_CASE:
- $file = 'lower';
- break;
- case self::UPPER_CASE:
- $file = 'upper';
- break;
- case self::ASCII_CONV:
- $file = 'ascii';
- break;
- case self::FOLD_CASE:
- $file = 'fold';
- break;
- default:
- return [];
- }
-
- /** @noinspection PhpIncludeInspection */
- return self::$maps[$mode] = include(__DIR__ . "/../res/{$file}.php");
- }
+class UnicodeString implements Countable, ArrayAccess, JsonSerializable {
+
+ const KEEP_CASE = 0;
+
+ const LOWER_CASE = 1;
+
+ const UPPER_CASE = 2;
+
+ const FOLD_CASE = 3;
+
+ const ASCII_CONV = 4;
+
+ /**
+ * @var int[]
+ */
+ private $codes;
+
+ /**
+ * @var string[]|null
+ */
+ private $chars;
+ /**
+ * @var int
+ */
+ private $length;
+ /**
+ * @var string|null
+ */
+ private $str;
+ /**
+ * @var mixed[]|null
+ */
+ private $cache;
+
+ /**
+ * @var int[][]
+ */
+ private static $maps = array();
+
+ /**
+ * @param int[] $codes
+ */
+ private function __construct( array $codes = array() ) {
+ $this->codes = $codes;
+ $this->length = count( $codes );
+ }
+
+ /**
+ * @return int[]
+ */
+ public function codePoints(): array {
+ return $this->codes;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function chars(): array {
+ if ( $this->chars === null ) {
+ $this->chars = self::getCharsFromCodePoints( $this->codes );
+ }
+ return $this->chars;
+ }
+
+ /**
+ * @return int
+ */
+ public function length(): int {
+ return $this->length;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isEmpty(): bool {
+ return $this->length === 0;
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param bool $ignoreCase
+ * @return bool
+ */
+ public function equals( $text, $ignoreCase = false ): bool {
+ return $this->compareTo( $text, $ignoreCase ) === 0;
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param bool $ignoreCase
+ * @return int
+ */
+ public function compareTo( $text, $ignoreCase = false ): int {
+ $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
+
+ $text = self::resolveCodePoints( $text, $mode );
+
+ $length = count( $text );
+
+ if ( $length !== $this->length ) {
+ return $this->length <=> $length;
+ }
+
+ return $this->getMappedCodes( $mode ) <=> $text;
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param bool $ignoreCase
+ * @return bool
+ */
+ public function contains( $text, $ignoreCase = false ): bool {
+ return $this->indexOf( $text, 0, $ignoreCase ) !== -1;
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param bool $ignoreCase
+ * @return bool
+ */
+ public function startsWith( $text, $ignoreCase = false ): bool {
+ $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
+
+ $text = self::resolveCodePoints( $text, $mode );
+
+ $len = count( $text );
+
+ if ( $len === 0 || $len > $this->length ) {
+ return false;
+ }
+
+ return array_slice( $this->getMappedCodes( $mode ), 0, $len ) === $text;
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param bool $ignoreCase
+ * @return bool
+ */
+ public function endsWith( $text, $ignoreCase = false ): bool {
+ $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
+
+ $text = self::resolveCodePoints( $text, $mode );
+
+ if ( empty( $text ) ) {
+ return false;
+ }
+
+ $codes = $this->getMappedCodes( $mode );
+
+ $offset = $this->length - count( $text );
+
+ if ( $offset < 0 ) {
+ return false;
+ }
+
+ return array_slice( $codes, $offset ) === $text;
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param int $offset
+ * @param bool $ignoreCase
+ * @return int
+ */
+ public function indexOf( $text, $offset = 0, $ignoreCase = false ): int {
+ if ( $offset < 0 ) {
+ $offset += $this->length;
+ }
+ if ( $offset < 0 || $offset >= $this->length ) {
+ return -1;
+ }
+
+ $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
+
+ $text = self::resolveCodePoints( $text, $mode );
+
+ $len = count( $text );
+
+ if ( $len === 0 || $offset + $len > $this->length ) {
+ return -1;
+ }
+
+ return $this->doIndexOf( $this->getMappedCodes( $mode ), $text, $offset );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param int $offset
+ * @param bool $ignoreCase
+ * @return int
+ */
+ public function lastIndexOf( $text, $offset = 0, $ignoreCase = false ): int {
+ if ( $offset < 0 ) {
+ $start = $this->length + $offset;
+ if ( $start < 0 ) {
+ return -1;
+ }
+ $last = 0;
+ } else {
+ if ( $offset >= $this->length ) {
+ return -1;
+ }
+ $start = $this->length - 1;
+ $last = $offset;
+ }
+
+ $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
+
+ $text = self::resolveCodePoints( $text, $mode );
+
+ $len = count( $text );
+
+ if ( $len === 0 ) {
+ return -1;
+ }
+
+ if ( $offset < 0 ) {
+ if ( $len > $this->length ) {
+ return -1;
+ }
+ $start = min( $start, $this->length - $len );
+ } elseif ( $offset + $len > $this->length ) {
+ return -1;
+ }
+
+ $codes = $this->getMappedCodes( $mode );
+
+ for ( $i = $start; $i >= $last; $i-- ) {
+ $match = true;
+
+ for ( $j = 0; $j < $len; $j++ ) {
+ if ( $codes[ $i + $j ] !== $text[ $j ] ) {
+ $match = false;
+ break;
+ }
+ }
+
+ if ( $match ) {
+ return $i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param bool $ignoreCase
+ * @param bool $allowPrefixOnly If true the result can contain only the prefix
+ * @return $this
+ */
+ public function ensurePrefix( $text, $ignoreCase = false, $allowPrefixOnly = true ): self {
+ $text = self::resolveCodePoints( $text );
+
+ $len = count( $text );
+
+ if ( $len === 0 ) {
+ return clone $this;
+ }
+
+ if ( $this->length === 0 ) {
+ return new static( $text );
+ }
+
+ if ( $ignoreCase ) {
+ $prefix = self::getMappedCodePoints( $text, self::FOLD_CASE );
+ } else {
+ $prefix = &$text;
+ }
+
+ if ( $this->length === $len ) {
+ $part = $this->getMappedCodes( $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE );
+ if ( $allowPrefixOnly && $part === $prefix ) {
+ return clone $this;
+ }
+ // Remove last element to avoid double check
+ array_pop( $part );
+ } elseif ( $this->length < $len ) {
+ $part = $this->getMappedCodes( $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE );
+ // Checks if this can be a suffix
+ if ( $allowPrefixOnly && ( array_slice( $prefix, 0, $this->length ) === $part ) ) {
+ $text = array_slice( $text, $this->length );
+ return new static( array_merge( $this->codes, $text ) );
+ }
+ } else {
+ $part = array_slice( $this->codes, 0, $len );
+ if ( $ignoreCase ) {
+ $part = self::getMappedCodePoints( $part, self::FOLD_CASE );
+ }
+ if ( $part === $prefix ) {
+ return clone $this;
+ }
+ // Remove last element to avoid double check
+ array_pop( $part );
+ }
+
+ $copy = $len;
+
+ $part_len = count( $part );
+
+ while ( $part_len ) {
+ if ( $part === array_slice( $prefix, -$part_len ) ) {
+ $copy = $len - $part_len;
+ break;
+ }
+ array_pop( $part );
+ --$part_len;
+ }
+
+ if ( $copy === 0 ) {
+ return clone $this;
+ }
+
+ if ( $copy < $len ) {
+ $text = array_slice( $text, 0, $copy );
+ }
+
+ return new static( array_merge( $text, $this->codes ) );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param bool $ignoreCase
+ * @param bool $allowSuffixOnly If true the result can contain only the suffix
+ * @return static
+ */
+ public function ensureSuffix( $text, $ignoreCase = false, $allowSuffixOnly = true ): self {
+ $text = self::resolveCodePoints( $text );
+
+ $len = count( $text );
+
+ if ( $len === 0 ) {
+ return clone $this;
+ }
+
+ if ( $this->length === 0 ) {
+ return new static( $text );
+ }
+
+ if ( $ignoreCase ) {
+ $suffix = self::getMappedCodePoints( $text, self::FOLD_CASE );
+ } else {
+ $suffix = &$text;
+ }
+
+ if ( $this->length === $len ) {
+ $part = $this->getMappedCodes( $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE );
+ if ( $allowSuffixOnly && $part === $suffix ) {
+ return clone $this;
+ }
+ // Remove first element to avoid double check
+ array_shift( $part );
+ } elseif ( $this->length < $len ) {
+ $part = $this->getMappedCodes( $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE );
+ // Checks if this can be a prefix
+ if ( $allowSuffixOnly && ( array_slice( $suffix, -$this->length ) === $part ) ) {
+ $text = array_slice( $text, 0, $len - $this->length );
+ return new static( array_merge( $text, $this->codes ) );
+ }
+ } else {
+ $part = array_slice( $this->codes, -$len );
+ if ( $ignoreCase ) {
+ $part = self::getMappedCodePoints( $part, self::FOLD_CASE );
+ }
+ if ( $part === $suffix ) {
+ return clone $this;
+ }
+ // Remove first element to avoid double check
+ array_shift( $part );
+ }
+
+ $skip = 0;
+
+ $part_len = count( $part );
+
+ while ( $part_len ) {
+ if ( $part === array_slice( $suffix, 0, $part_len ) ) {
+ $skip = $part_len;
+ break;
+ }
+ array_shift( $part );
+ --$part_len;
+ }
+
+ if ( $skip === $len ) {
+ return clone $this;
+ }
+
+ if ( $skip ) {
+ array_splice( $text, 0, $skip );
+ }
+
+ return new static( array_merge( $this->codes, $text ) );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param int $mode
+ * @return static
+ */
+ public function append( $text, $mode = self::KEEP_CASE ): self {
+ return new static( array_merge( $this->codes, self::resolveCodePoints( $text, $mode ) ) );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param int $mode
+ * @return static
+ */
+ public function prepend( $text, $mode = self::KEEP_CASE ): self {
+ return new static( array_merge( self::resolveCodePoints( $text, $mode ), $this->codes ) );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param int $offset
+ * @param int $mode
+ * @return static
+ */
+ public function insert( $text, $offset, $mode = self::KEEP_CASE ): self {
+ $codes = $this->codes;
+
+ array_splice( $codes, $offset, 0, self::resolveCodePoints( $text, $mode ) );
+
+ return new static( $codes );
+ }
+
+ /**
+ * @param int $offset
+ * @param int|null $length
+ * @return static
+ */
+ public function remove( $offset, $length = null ): self {
+ $codes = $this->codes;
+
+ if ( $length === null ) {
+ array_splice( $codes, $offset );
+ } else {
+ array_splice( $codes, $offset, $length );
+ }
+
+ return new static( $codes );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $mask
+ * @return static
+ */
+ public function trim( $mask = " \t\n\r\0\x0B" ): self {
+ return $this->doTrim( $mask, true, true );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $mask
+ * @return static
+ */
+ public function trimLeft( $mask = " \t\n\r\0\x0B" ): self {
+ return $this->doTrim( $mask, true, false );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $mask
+ * @return static
+ */
+ public function trimRight( $mask = " \t\n\r\0\x0B" ): self {
+ return $this->doTrim( $mask, false, true );
+ }
+
+ /**
+ * @return static
+ */
+ public function reverse(): self {
+ return new static( array_reverse( $this->codes ) );
+ }
+
+ /**
+ * @param int $times
+ * @return static
+ */
+ public function repeat( $times = 1 ): self {
+ if ( $times <= 1 ) {
+ return clone $this;
+ }
+
+ $codes = array();
+
+ while ( $times-- ) {
+ $codes = array_merge( $codes, $this->codes );
+ }
+
+ return new static( $codes );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $subject
+ * @param string|self|int[]|string[] $replace
+ * @param int $offset
+ * @param bool $ignoreCase
+ * @return static
+ */
+ public function replace( $subject, $replace, $offset = 0, $ignoreCase = false ): self {
+ if ( $offset < 0 ) {
+ $offset += $this->length;
+ }
+ if ( $offset < 0 || $offset >= $this->length ) {
+ return clone $this;
+ }
+
+ $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
+
+ $subject = self::resolveCodePoints( $subject, $mode );
+
+ $len = count( $subject );
+
+ if ( $len === 0 || $offset + $len > $this->length ) {
+ return clone $this;
+ }
+
+ $offset = $this->doIndexOf( $this->getMappedCodes( $mode ), $subject, $offset );
+
+ if ( $offset === -1 ) {
+ return clone $this;
+ }
+
+ $codes = $this->codes;
+
+ array_splice( $codes, $offset, count( $subject ), self::resolveCodePoints( $replace ) );
+
+ return new static( $codes );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $subject
+ * @param string|self|int[]|string[] $replace
+ * @param bool $ignoreCase
+ * @param int $offset
+ * @return static
+ */
+ public function replaceAll( $subject, $replace, $offset = 0, $ignoreCase = false ): self {
+ if ( $offset < 0 ) {
+ $offset += $this->length;
+ }
+ if ( $offset < 0 || $offset >= $this->length ) {
+ return clone $this;
+ }
+
+ $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
+
+ $subject = self::resolveCodePoints( $subject, $mode );
+
+ $len = count( $subject );
+
+ if ( $len === 0 || $offset + $len > $this->length ) {
+ return clone $this;
+ }
+
+ $replace = self::resolveCodePoints( $replace );
+
+ $codes = $this->getMappedCodes( $mode );
+
+ $copy = $this->codes;
+
+ $fix = count( $replace ) - $len;
+
+ $t = 0;
+
+ while ( ( $pos = $this->doIndexOf( $codes, $subject, $offset ) ) >= 0 ) {
+ array_splice( $copy, $pos + $t * $fix, $len, $replace );
+ $offset = $pos + $len;
+ ++$t;
+ }
+
+ return new static( $copy );
+ }
+
+ /**
+ * @param string|self|int[]|string[] $delimiter
+ * @param bool $ignoreCase
+ * @return array
+ */
+ public function split( $delimiter = '', $ignoreCase = false ): array {
+ $mode = $ignoreCase ? self::FOLD_CASE : self::KEEP_CASE;
+ $delimiter = self::resolveCodePoints( $delimiter, $mode );
+ $len = count( $delimiter );
+
+ $ret = array();
+
+ if ( $len === 0 ) {
+ foreach ( $this->codes as $code ) {
+ $ret[] = new static( array( $code ) );
+ }
+ } else {
+ $codes = $this->getMappedCodes( $mode );
+
+ $offset = 0;
+
+ while ( ( $pos = $this->doIndexOf( $codes, $delimiter, $offset ) ) >= 0 ) {
+ $ret[] = new static( array_slice( $this->codes, $offset, $pos - $offset ) );
+ $offset = $pos + $len;
+ }
+
+ $ret[] = new static( array_slice( $this->codes, $offset ) );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * @param int $start
+ * @param int|null $length
+ * @return static
+ */
+ public function substring( $start, $length = null ): self {
+ return new static( array_slice( $this->codes, $start, $length ) );
+ }
+
+ /**
+ * @param int $size If negative then pad left otherwise pad right
+ * @param self|string|int $char A char or a code point
+ * @return static
+ */
+ public function pad( $size, $char = 0x20 ): self {
+ return new static( array_pad( $this->codes, $size, self::resolveFirstCodePoint( $char, 0x20 ) ) );
+ }
+
+ /**
+ * @param int $size
+ * @param self|string|int $char
+ * @return static
+ */
+ public function padLeft( $size, $char = 0x20 ): self {
+ if ( $size > 0 ) {
+ $size = -$size;
+ }
+
+ return $this->pad( $size, $char );
+ }
+
+ /**
+ * @param int $size
+ * @param self|string|int $char
+ * @return static
+ */
+ public function padRight( $size, $char = 0x20 ): self {
+ if ( $size < 0 ) {
+ $size = -$size;
+ }
+
+ return $this->pad( $size, $char );
+ }
+
+ /**
+ * @return bool
+ */
+ public function isLowerCase(): bool {
+ return $this->isCase( self::LOWER_CASE );
+ }
+
+ /**
+ * @return bool
+ */
+ public function isUpperCase(): bool {
+ return $this->isCase( self::UPPER_CASE );
+ }
+
+ /**
+ * @return bool
+ */
+ public function isAscii(): bool {
+ $key = 'i' . self::ASCII_CONV;
+
+ if ( ! isset( $this->cache[ $key ] ) ) {
+ $ok = true;
+
+ foreach ( $this->codes as $code ) {
+ if ( $code >= 0x80 ) {
+ $ok = false;
+ break;
+ }
+ }
+
+ $this->cache[ $key ] = $ok;
+ }
+
+ return $this->cache[ $key ];
+ }
+
+ /**
+ * Convert all chars to lower case (where possible)
+ *
+ * @return static
+ */
+ public function toLower(): self {
+ if ( $this->cache[ 'i' . self::LOWER_CASE ] ?? false ) {
+ return clone $this;
+ }
+ return new static( $this->getMappedCodes( self::LOWER_CASE ) );
+ }
+
+ /**
+ * Convert all chars to upper case (where possible)
+ *
+ * @return static
+ */
+ public function toUpper(): self {
+ if ( $this->cache[ 'i' . self::UPPER_CASE ] ?? false ) {
+ return clone $this;
+ }
+ return new static( $this->getMappedCodes( self::UPPER_CASE ) );
+ }
+
+ /**
+ * Converts all chars to their ASCII equivalent (if any)
+ *
+ * @return static
+ */
+ public function toAscii(): self {
+ if ( $this->cache[ 'i' . self::ASCII_CONV ] ?? false ) {
+ return clone $this;
+ }
+ return new static( $this->getMappedCodes( self::ASCII_CONV ) );
+ }
+
+ /**
+ * @param int $index
+ * @return string
+ */
+ public function charAt( $index ): string {
+ // Allow negative index
+ if ( $index < 0 && $index + $this->length >= 0 ) {
+ $index += $this->length;
+ }
+
+ if ( $index < 0 || $index >= $this->length ) {
+ return '';
+ }
+
+ return $this->chars()[ $index ];
+ }
+
+ /**
+ * @param int $index
+ * @return int
+ */
+ public function codePointAt( $index ): int {
+ // Allow negative index
+ if ( $index < 0 && $index + $this->length >= 0 ) {
+ $index += $this->length;
+ }
+
+ if ( $index < 0 || $index >= $this->length ) {
+ return -1;
+ }
+
+ return $this->codes[ $index ];
+ }
+
+ /**
+ * @param int $offset
+ * @return int
+ */
+ public function __invoke( int $offset ): int {
+ if ( $offset < 0 ) {
+ if ( $offset + $this->length < 0 ) {
+ throw new OutOfBoundsException( "Undefined offset: {$offset}" );
+ }
+ $offset += $this->length;
+ } elseif ( $offset >= $this->length ) {
+ throw new OutOfBoundsException( "Undefined offset: {$offset}" );
+ }
+
+ return $this->codes[ $offset ];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function offsetExists( $offset ): bool {
+ // Allow negative index
+ if ( $offset < 0 ) {
+ $offset += $this->length;
+ }
+
+ return isset( $this->codes[ $offset ] );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function offsetGet( $offset ): string {
+ if ( $offset < 0 ) {
+ if ( $offset + $this->length < 0 ) {
+ throw new OutOfBoundsException( "Undefined offset: {$offset}" );
+ }
+ $offset += $this->length;
+ } elseif ( $offset >= $this->length ) {
+ throw new OutOfBoundsException( "Undefined offset: {$offset}" );
+ }
+
+ return $this->chars()[ $offset ];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetSet( $offset, $value ) {
+ // Allow negative index
+ if ( $offset < 0 ) {
+ $offset += $this->length;
+ }
+
+ if ( ! isset( $this->codes[ $offset ] ) ) {
+ return;
+ }
+
+ $value = self::resolveFirstCodePoint( $value );
+ if ( $value === -1 ) {
+ return;
+ }
+
+ if ( $value === $this->codes[ $offset ] ) {
+ // Same value, nothing to do
+ return;
+ }
+
+ $this->codes[ $offset ] = $value;
+
+ // Clear cache
+ $this->str = null;
+ $this->cache = null;
+ if ( $this->chars ) {
+ $this->chars[ $offset ] = self::getCharFromCodePoint( $value );
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetUnset( $offset ) {
+ throw new RuntimeException( 'Invalid operation' );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function count(): int {
+ return $this->length;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString(): string {
+ if ( $this->str === null ) {
+ $this->str = self::getStringFromCodePoints( $this->codes );
+ }
+
+ return $this->str;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function jsonSerialize(): string {
+ return $this->__toString();
+ }
+
+ public function __serialize(): array {
+ return array(
+ 'value' => $this->__toString(),
+ );
+ }
+
+ public function __unserialize( array $data ) {
+ $this->str = $data['value'];
+ $this->codes = self::getCodePointsFromString( $this->str );
+ $this->length = count( $this->codes );
+ }
+
+ /**
+ * Creates an unicode string instance from raw string
+ *
+ * @param string $string
+ * @param string|null $encoding Defaults to UTF-8
+ * @param int $mode
+ * @return static
+ * @throws InvalidStringException
+ */
+ public static function from( $string, $encoding = null, $mode = self::KEEP_CASE ): self {
+ if ( $encoding !== null && strcasecmp( $encoding, 'UTF-8' ) !== 0 ) {
+ if ( false === $string = @iconv( $encoding, 'UTF-8', $string ) ) {
+ throw new UnicodeException( "Could not convert string from '$encoding' encoding to UTF-8 encoding" );
+ }
+ }
+
+ $instance = new static( self::getCodePointsFromString( $string, $mode ) );
+ if ( $mode === self::KEEP_CASE ) {
+ $instance->str = $string;
+ }
+ return $instance;
+ }
+
+ /**
+ * Creates an unicode string instance from code points
+ *
+ * @param int[] $codes
+ * @param int $mode
+ * @return static
+ * @throws InvalidCodePointException
+ */
+ public static function fromCodePoints( $codes, $mode = self::KEEP_CASE ): self {
+ $map = self::getMapByMode( $mode );
+
+ foreach ( $codes as &$code ) {
+ if ( ! is_int( $codes ) || ! self::isValidCodePoint( $code ) ) {
+ throw new InvalidCodePointException( $code );
+ } else {
+ $code = $map[ $code ] ?? $code;
+ }
+ }
+
+ return new static( array_values( $codes ) );
+ }
+
+ /**
+ * Converts the code point to corresponding char
+ *
+ * @param int $code
+ * @return string The char or an empty string if code point is invalid
+ */
+ public static function getCharFromCodePoint( $code ): string {
+ if ( $code < 0 ) {
+ return '';
+ }
+
+ if ( $code < 0x80 ) {
+ return chr( $code );
+ }
+
+ if ( $code < 0x800 ) {
+ return chr( ( $code >> 6 ) + 0xC0 ) . chr( ( $code & 0x3F ) + 0x80 );
+ }
+
+ if ( $code >= 0xD800 && $code <= 0xDFFF ) {
+ /*
+ The definition of UTF-8 prohibits encoding character numbers between
+ U+D800 and U+DFFF, which are reserved for use with the UTF-16
+ encoding form (as surrogate pairs) and do not directly represent characters.
+ */
+ return '';
+ }
+
+ if ( $code <= 0xFFFF ) {
+ return chr( ( $code >> 12 ) + 0xE0 ) .
+ chr( ( ( $code >> 6 ) & 0x3F ) + 0x80 ) .
+ chr( ( $code & 0x3F ) + 0x80 );
+ }
+
+ if ( $code <= 0x10FFFF ) {
+ return chr( ( $code >> 18 ) + 0xF0 ) .
+ chr( ( ( $code >> 12 ) & 0x3F ) + 0x80 ) .
+ chr( ( ( $code >> 6 ) & 0x3F ) + 0x80 ) .
+ chr( ( $code & 0x3F ) + 0x80 );
+ }
+
+ /*
+ Restricted the range of characters to 0000-10FFFF (the UTF-16 accessible range).
+ */
+
+ return '';
+ }
+
+ /**
+ * Convert a string to a code point array
+ *
+ * @param string $str
+ * @param int $mode
+ * @return array
+ * @throws InvalidStringException
+ */
+ public static function getCodePointsFromString( $str, $mode = self::KEEP_CASE ): array {
+ // 0x00-0x7F
+ // 0xC2-0xDF 0x80-0xBF
+ // 0xE0-0xE0 0xA0-0xBF 0x80-0xBF
+ // 0xE1-0xEC 0x80-0xBF 0x80-0xBF
+ // 0xED-0xED 0x80-0x9F 0x80-0xBF
+ // 0xEE-0xEF 0x80-0xBF 0x80-0xBF
+ // 0xF0-0xF0 0x90-0xBF 0x80-0xBF 0x80-0xBF
+ // 0xF1-0xF3 0x80-0xBF 0x80-0xBF 0x80-0xBF
+ // 0xF4-0xF4 0x80-0x8F 0x80-0xBF 0x80-0xBF
+
+ $codes = array();
+ $length = strlen( $str );
+ $mode = self::getMapByMode( $mode );
+
+ $i = 0;
+ while ( $i < $length ) {
+ $ord0 = ord( $str[ $i++ ] );
+
+ if ( $ord0 < 0x80 ) {
+ $codes[] = $mode[ $ord0 ] ?? $ord0;
+ continue;
+ }
+
+ if ( $i === $length || $ord0 < 0xC2 || $ord0 > 0xF4 ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ $ord1 = ord( $str[ $i++ ] );
+
+ if ( $ord0 < 0xE0 ) {
+ if ( $ord1 < 0x80 || $ord1 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ $ord1 = ( $ord0 - 0xC0 ) * 64 + $ord1 - 0x80;
+ $codes[] = $mode[ $ord1 ] ?? $ord1;
+
+ continue;
+ }
+
+ if ( $i === $length ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ $ord2 = ord( $str[ $i++ ] );
+
+ if ( $ord0 < 0xF0 ) {
+ if ( $ord0 === 0xE0 ) {
+ if ( $ord1 < 0xA0 || $ord1 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 2 );
+ }
+ } elseif ( $ord0 === 0xED ) {
+ if ( $ord1 < 0x80 || $ord1 >= 0xA0 ) {
+ throw new InvalidStringException( $str, $i - 2 );
+ }
+ } elseif ( $ord1 < 0x80 || $ord1 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 2 );
+ }
+
+ if ( $ord2 < 0x80 || $ord2 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ $ord2 = ( $ord0 - 0xE0 ) * 0x1000 + ( $ord1 - 0x80 ) * 64 + $ord2 - 0x80;
+ $codes[] = $mode[ $ord2 ] ?? $ord2;
+
+ continue;
+ }
+
+ if ( $i === $length ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ $ord3 = ord( $str[ $i++ ] );
+
+ if ( $ord0 < 0xF5 ) {
+ if ( $ord0 === 0xF0 ) {
+ if ( $ord1 < 0x90 || $ord1 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 3 );
+ }
+ } elseif ( $ord0 === 0xF4 ) {
+ if ( $ord1 < 0x80 || $ord1 >= 0x90 ) {
+ throw new InvalidStringException( $str, $i - 3 );
+ }
+ } elseif ( $ord1 < 0x80 || $ord1 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 3 );
+ }
+
+ if ( $ord2 < 0x80 || $ord2 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 2 );
+ }
+
+ if ( $ord3 < 0x80 || $ord3 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ $ord3 = ( $ord0 - 0xF0 ) * 0x40000 + ( $ord1 - 0x80 ) * 0x1000 + ( $ord2 - 0x80 ) * 64 + $ord3 - 0x80;
+ $codes[] = $mode[ $ord3 ] ?? $ord3;
+
+ continue;
+ }
+
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ return $codes;
+ }
+
+ /**
+ * @param string $str
+ * @return iterable
+ *
+ * The key represents the current char index
+ * Value is a two element array
+ * - first element is an integer representing the code point
+ * - second element is an array of integers (length 1 to 4) representing bytes
+ */
+ public static function walkString( $str ) {
+ $i = 0;
+ $length = strlen( $str );
+
+ while ( $i < $length ) {
+ $index = $i;
+
+ $ord0 = ord( $str[ $i++ ] );
+
+ if ( $ord0 < 0x80 ) {
+ yield $index => array(
+ $ord0,
+ array( $ord0 ),
+ );
+ continue;
+ }
+
+ if ( $i === $length || $ord0 < 0xC2 || $ord0 > 0xF4 ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ $ord1 = ord( $str[ $i++ ] );
+
+ if ( $ord0 < 0xE0 ) {
+ if ( $ord1 < 0x80 || $ord1 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ yield $index => array(
+ ( $ord0 - 0xC0 ) * 64 + $ord1 - 0x80,
+ array( $ord0, $ord1 ),
+ );
+
+ continue;
+ }
+
+ if ( $i === $length ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ $ord2 = ord( $str[ $i++ ] );
+
+ if ( $ord0 < 0xF0 ) {
+ if ( $ord0 === 0xE0 ) {
+ if ( $ord1 < 0xA0 || $ord1 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 2 );
+ }
+ } elseif ( $ord0 === 0xED ) {
+ if ( $ord1 < 0x80 || $ord1 >= 0xA0 ) {
+ throw new InvalidStringException( $str, $i - 2 );
+ }
+ } elseif ( $ord1 < 0x80 || $ord1 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 2 );
+ }
+
+ if ( $ord2 < 0x80 || $ord2 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ yield $index => array(
+ ( $ord0 - 0xE0 ) * 0x1000 + ( $ord1 - 0x80 ) * 64 + $ord2 - 0x80,
+ array( $ord0, $ord1, $ord2 ),
+ );
+
+ continue;
+ }
+
+ if ( $i === $length ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ $ord3 = ord( $str[ $i++ ] );
+
+ if ( $ord0 < 0xF5 ) {
+ if ( $ord0 === 0xF0 ) {
+ if ( $ord1 < 0x90 || $ord1 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 3 );
+ }
+ } elseif ( $ord0 === 0xF4 ) {
+ if ( $ord1 < 0x80 || $ord1 >= 0x90 ) {
+ throw new InvalidStringException( $str, $i - 3 );
+ }
+ } elseif ( $ord1 < 0x80 || $ord1 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 3 );
+ }
+
+ if ( $ord2 < 0x80 || $ord2 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 2 );
+ }
+
+ if ( $ord3 < 0x80 || $ord3 >= 0xC0 ) {
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+
+ yield $index => array(
+ ( $ord0 - 0xF0 ) * 0x40000 + ( $ord1 - 0x80 ) * 0x1000 + ( $ord2 - 0x80 ) * 64 + $ord3 - 0x80,
+ array( $ord0, $ord1, $ord2, $ord3 ),
+ );
+
+ continue;
+ }
+
+ throw new InvalidStringException( $str, $i - 1 );
+ }
+ }
+
+ /**
+ * Converts each code point to a char
+ *
+ * @param array $codes
+ * @param int $mode
+ * @return array
+ * @throws InvalidCodePointException
+ */
+ public static function getCharsFromCodePoints( $codes, $mode = self::KEEP_CASE ): array {
+ $mode = self::getMapByMode( $mode );
+
+ foreach ( $codes as &$code ) {
+ $char = self::getCharFromCodePoint( $mode[ $code ] ?? $code );
+ if ( $char === '' ) {
+ throw new InvalidCodePointException( $code );
+ } else {
+ $code = $char;
+ }
+ }
+
+ return $codes;
+ }
+
+ /**
+ * @param string $str
+ * @param int $mode
+ * @return string[]
+ */
+ public static function getCharsFromString( $str, $mode = self::KEEP_CASE ): array {
+ return self::getCharsFromCodePoints( self::getCodePointsFromString( $str ), $mode );
+ }
+
+ /**
+ * Converts all code points to chars and returns the string
+ * Invalid code points are ignored
+ *
+ * @param array $codes
+ * @param int $mode
+ * @return string
+ */
+ public static function getStringFromCodePoints( $codes, $mode = self::KEEP_CASE ): string {
+ $str = '';
+
+ $mode = self::getMapByMode( $mode );
+
+ foreach ( $codes as $code ) {
+ if ( isset( $mode[ $code ] ) ) {
+ $code = $mode[ $code ];
+ }
+
+ if ( $code < 0x80 ) {
+ $str .= chr( $code );
+ continue;
+ }
+
+ if ( $code < 0x800 ) {
+ $str .= chr( ( $code >> 6 ) + 0xC0 ) . chr( ( $code & 0x3F ) + 0x80 );
+ continue;
+ }
+
+ if ( $code >= 0xD800 && $code <= 0xDFFF ) {
+ continue;
+ }
+
+ if ( $code <= 0xFFFF ) {
+ $str .=
+ chr( ( $code >> 12 ) + 0xE0 ) .
+ chr( ( ( $code >> 6 ) & 0x3F ) + 0x80 ) .
+ chr( ( $code & 0x3F ) + 0x80 );
+ continue;
+ }
+
+ if ( $code <= 0x10FFFF ) {
+ $str .=
+ chr( ( $code >> 18 ) + 0xF0 ) .
+ chr( ( ( $code >> 12 ) & 0x3F ) + 0x80 ) .
+ chr( ( ( $code >> 6 ) & 0x3F ) + 0x80 ) .
+ chr( ( $code & 0x3F ) + 0x80 );
+ }
+ }
+
+ return $str;
+ }
+
+ /**
+ * @param array $codes
+ * @param int $mode
+ * @return array
+ */
+ public static function getMappedCodePoints( $codes, $mode ): array {
+ if ( $mode === self::KEEP_CASE ) {
+ return $codes;
+ }
+
+ $mode = self::getMapByMode( $mode );
+
+ if ( empty( $mode ) ) {
+ return $codes;
+ }
+
+ foreach ( $codes as &$code ) {
+ $code = $mode[ $code ] ?? $code;
+ }
+
+ return $codes;
+ }
+
+ /**
+ * Checks if a code point is valid
+ *
+ * @param int $code
+ * @return bool
+ */
+ public static function isValidCodePoint( $code ): bool {
+ if ( $code < 0 || $code > 0x10FFFF ) {
+ return false;
+ }
+
+ return $code < 0xD800 || $code > 0xDFFF;
+ }
+
+ /**
+ * @param int $mode
+ * @return int[]
+ */
+ private function getMappedCodes( int $mode ): array {
+ if ( $mode === self::KEEP_CASE || ( $this->cache[ 'i' . $mode ] ?? false ) ) {
+ return $this->codes;
+ }
+
+ $key = 'm' . $mode;
+
+ if ( ! isset( $this->cache[ $key ] ) ) {
+ $this->cache[ $key ] = self::getMappedCodePoints( $this->codes, $mode );
+ }
+
+ return $this->cache[ $key ];
+ }
+
+ /**
+ * @param int $mode
+ * @return bool
+ */
+ private function isCase( int $mode ): bool {
+ $key = 'i' . $mode;
+
+ if ( ! isset( $this->cache[ $key ] ) ) {
+ $list = self::getMapByMode( $mode );
+ foreach ( $this->codes as $code ) {
+ if ( isset( $list[ $code ] ) ) {
+ return $this->cache[ $key ] = false;
+ }
+ }
+
+ return $this->cache[ $key ] = true;
+ }
+
+ return $this->cache[ $key ];
+ }
+
+ /**
+ * @param int[] $codes
+ * @param int[] $text
+ * @param int $offset
+ * @return int
+ */
+ private function doIndexOf( array $codes, array $text, int $offset = 0 ): int {
+ $len = count( $text );
+
+ for ( $i = $offset, $last = count( $codes ) - $len; $i <= $last; $i++ ) {
+ $match = true;
+
+ for ( $j = 0; $j < $len; $j++ ) {
+ if ( $codes[ $i + $j ] !== $text[ $j ] ) {
+ $match = false;
+ break;
+ }
+ }
+
+ if ( $match ) {
+ return $i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * @param string|self|int[]|string[] $mask
+ * @param bool $left
+ * @param bool $right
+ * @return static
+ */
+ private function doTrim( $mask, bool $left, bool $right ): self {
+ if ( $this->length === 0 ) {
+ return clone $this;
+ }
+
+ $mask = self::resolveCodePoints( $mask );
+
+ if ( empty( $mask ) ) {
+ return clone $this;
+ }
+
+ $codes = $this->codes;
+
+ if ( $left ) {
+ while ( in_array( $codes[0], $mask, true ) ) {
+ array_shift( $codes );
+ if ( empty( $codes ) ) {
+ return new static();
+ }
+ }
+ }
+
+ if ( $right ) {
+ $last = count( $codes ) - 1;
+ while ( in_array( $codes[ $last ], $mask, true ) ) {
+ array_pop( $codes );
+ if ( --$last < 0 ) {
+ return new static();
+ }
+ }
+ }
+
+ return new static( $codes );
+ }
+
+
+ /**
+ * @param string|self|int[]|string[] $text
+ * @param int $mode
+ * @return array
+ */
+ private static function resolveCodePoints( $text, int $mode = self::KEEP_CASE ): array {
+ if ( $text instanceof self ) {
+ return $text->getMappedCodes( $mode );
+ }
+
+ if ( is_string( $text ) ) {
+ return self::getCodePointsFromString( $text, $mode );
+ }
+
+ if ( $text && is_array( $text ) && is_int( $text[0] ) ) {
+ // assume code point array
+ return self::getMappedCodePoints( $text, $mode );
+ }
+
+ return array();
+ }
+
+ /**
+ * @param self|string|int|string[]|int[] $text
+ * @param int $invalid
+ * @return int
+ */
+ private static function resolveFirstCodePoint( $text, int $invalid = -1 ): int {
+ if ( $text instanceof self ) {
+ return $text->length === 0 ? $invalid : $text->codes[0];
+ }
+
+ if ( is_array( $text ) ) {
+ if ( empty( $text ) ) {
+ return $invalid;
+ }
+ $text = reset( $text );
+ }
+
+ if ( is_string( $text ) ) {
+ if ( isset( $text[4] ) ) {
+ $text = substr( $text, 0, 4 );
+ }
+ return self::getCodePointsFromString( $text )[0] ?? $invalid;
+ }
+
+ if ( is_int( $text ) ) {
+ return self::isValidCodePoint( $text ) ? $text : $invalid;
+ }
+
+ return $invalid;
+ }
+
+ /**
+ * @param int $mode
+ * @return int[]
+ */
+ private static function getMapByMode( int $mode ): array {
+ if ( isset( self::$maps[ $mode ] ) ) {
+ return self::$maps[ $mode ];
+ }
+
+ switch ( $mode ) {
+ case self::LOWER_CASE:
+ $file = 'lower';
+ break;
+ case self::UPPER_CASE:
+ $file = 'upper';
+ break;
+ case self::ASCII_CONV:
+ $file = 'ascii';
+ break;
+ case self::FOLD_CASE:
+ $file = 'fold';
+ break;
+ default:
+ return array();
+ }
+
+ /** @noinspection PhpIncludeInspection */
+ return self::$maps[ $mode ] = include __DIR__ . "/../res/{$file}.php";
+ }
}
diff --git a/src/opis/uri/autoload.php b/src/opis/uri/autoload.php
index 8aa754c5..6ebeb341 100644
--- a/src/opis/uri/autoload.php
+++ b/src/opis/uri/autoload.php
@@ -1,5 +1,6 @@
= $n && $input[$i] < $m) {
- $m = $input[$i];
- }
- }
-
- if (($m - $n) > intdiv(self::MAX_INT - $delta, $handled + 1)) {
- throw new PunycodeException("Punycode overflow");
- }
-
- $delta += ($m - $n) * ($handled + 1);
-
- $n = $m;
-
- for ($i = 0; $i < $input_len; $i++) {
- if ($input[$i] < $n && (++$delta === 0)) {
- throw new PunycodeException("Punycode overflow");
- }
-
- if ($input[$i] === $n) {
- $q = $delta;
- for ($k = self::BASE; ; $k += self::BASE) {
- $t = self::threshold($k, $bias);
- if ($q < $t) {
- break;
- }
+final class Punycode {
- $base_minus_t = self::BASE - $t;
+ const BASE = 36;
+ const TMIN = 1;
+ const TMAX = 26;
+ const SKEW = 38;
+ const DAMP = 700;
+ const INITIAL_BIAS = 72;
+ const INITIAL_N = 0x80;
+ const PREFIX = 'xn--';
+ const PREFIX_LEN = 4;
+ const DELIMITER = 0x2D;
+ const MAX_INT = 0x7FFFFFFF;
+ const NON_ASCII = '#[^\0-\x7E]#';
- $q -= $t;
+ public static function encode( string $input ): string {
+ return implode( '.', array_map( array( self::class, 'encodePart' ), explode( '.', $input ) ) );
+ }
- $output[] = self::encodeDigit($t + ($q % $base_minus_t));
+ public static function decode( string $input ): string {
+ return implode( '.', array_map( array( self::class, 'decodePart' ), explode( '.', $input ) ) );
+ }
+
+ public static function normalize( string $input ): string {
+ return implode( '.', array_map( array( self::class, 'normalizePart' ), explode( '.', $input ) ) );
+ }
- $q = intdiv($q, $base_minus_t);
- }
+ public static function encodePart( string $input ): string {
+ if ( ! preg_match( self::NON_ASCII, $input ) ) {
+ return $input;
+ }
+
+ $input = UnicodeString::getCodePointsFromString( $input, UnicodeString::LOWER_CASE );
+ $input_len = count( $input );
+
+ $output = array_filter(
+ $input,
+ static function ( int $code ): bool {
+ return $code < 0x80;
+ }
+ );
+
+ if ( $output ) {
+ $output = array_values( $output );
+ }
+
+ $delta = 0;
+ $n = self::INITIAL_N;
+ $bias = self::INITIAL_BIAS;
+
+ $handled = $basic_length = count( $output );
+
+ if ( $basic_length ) {
+ $output[] = self::DELIMITER;
+ }
+
+ while ( $handled < $input_len ) {
+ $m = self::MAX_INT;
+
+ for ( $i = 0; $i < $input_len; $i++ ) {
+ if ( $input[ $i ] >= $n && $input[ $i ] < $m ) {
+ $m = $input[ $i ];
+ }
+ }
+
+ if ( ( $m - $n ) > intdiv( self::MAX_INT - $delta, $handled + 1 ) ) {
+ throw new PunycodeException( 'Punycode overflow' );
+ }
+
+ $delta += ( $m - $n ) * ( $handled + 1 );
+
+ $n = $m;
+
+ for ( $i = 0; $i < $input_len; $i++ ) {
+ if ( $input[ $i ] < $n && ( ++$delta === 0 ) ) {
+ throw new PunycodeException( 'Punycode overflow' );
+ }
- $output[] = self::encodeDigit($q);
+ if ( $input[ $i ] === $n ) {
+ $q = $delta;
+ for ( $k = self::BASE; ; $k += self::BASE ) {
+ $t = self::threshold( $k, $bias );
+ if ( $q < $t ) {
+ break;
+ }
- $bias = self::adapt($delta, $handled + 1, $handled === $basic_length);
- $delta = 0;
- $handled++;
- }
- }
+ $base_minus_t = self::BASE - $t;
- $delta++; $n++;
- }
+ $q -= $t;
- return self::PREFIX . UnicodeString::getStringFromCodePoints($output);
- }
+ $output[] = self::encodeDigit( $t + ( $q % $base_minus_t ) );
- public static function decodePart(string $input): string
- {
- if (stripos($input, self::PREFIX) !== 0) {
- return $input;
- }
+ $q = intdiv( $q, $base_minus_t );
+ }
- $input = UnicodeString::getCodePointsFromString(substr($input, self::PREFIX_LEN), UnicodeString::LOWER_CASE);
- $input_len = count($input);
+ $output[] = self::encodeDigit( $q );
- $pos = array_keys($input, self::DELIMITER, true);
- if ($pos) {
- $pos = end($pos);
- } else {
- $pos = -1;
- }
+ $bias = self::adapt( $delta, $handled + 1, $handled === $basic_length );
+ $delta = 0;
+ ++$handled;
+ }
+ }
- /** @var int $pos */
+ ++$delta;
+ ++$n;
+ }
- if ($pos === -1) {
- $output = [];
- $pos = $output_len = 0;
- } else {
- $output = array_slice($input, 0, ++$pos);
- $output_len = $pos;
- for ($i = 0; $i < $pos; $i++) {
- if ($output[$i] >= 0x80) {
- throw new PunycodeException("Non-basic code point is not allowed: {$output[$i]}");
- }
- }
- }
+ return self::PREFIX . UnicodeString::getStringFromCodePoints( $output );
+ }
- $i = 0;
- $n = self::INITIAL_N;
- $bias = self::INITIAL_BIAS;
+ public static function decodePart( string $input ): string {
+ if ( stripos( $input, self::PREFIX ) !== 0 ) {
+ return $input;
+ }
- while ($pos < $input_len) {
- $old_i = $i;
+ $input = UnicodeString::getCodePointsFromString( substr( $input, self::PREFIX_LEN ), UnicodeString::LOWER_CASE );
+ $input_len = count( $input );
- for ($w = 1, $k = self::BASE; ; $k += self::BASE) {
- if ($pos >= $input_len) {
- throw new PunycodeException("Punycode bad input");
- }
+ $pos = array_keys( $input, self::DELIMITER, true );
+ if ( $pos ) {
+ $pos = end( $pos );
+ } else {
+ $pos = -1;
+ }
- $digit = self::decodeDigit($input[$pos++]);
+ /** @var int $pos */
- if ($digit >= self::BASE || $digit > intdiv(self::MAX_INT - $i, $w)) {
- throw new PunycodeException("Punycode overflow");
- }
+ if ( $pos === -1 ) {
+ $output = array();
+ $pos = $output_len = 0;
+ } else {
+ $output = array_slice( $input, 0, ++$pos );
+ $output_len = $pos;
+ for ( $i = 0; $i < $pos; $i++ ) {
+ if ( $output[ $i ] >= 0x80 ) {
+ throw new PunycodeException( "Non-basic code point is not allowed: {$output[$i]}" );
+ }
+ }
+ }
- $i += $digit * $w;
+ $i = 0;
+ $n = self::INITIAL_N;
+ $bias = self::INITIAL_BIAS;
- $t = self::threshold($k, $bias);
- if ($digit < $t) {
- break;
- }
+ while ( $pos < $input_len ) {
+ $old_i = $i;
- $t = self::BASE - $t;
+ for ( $w = 1, $k = self::BASE; ; $k += self::BASE ) {
+ if ( $pos >= $input_len ) {
+ throw new PunycodeException( 'Punycode bad input' );
+ }
- if ($w > intdiv(self::MAX_INT, $t)) {
- throw new PunycodeException("Punycode overflow");
- }
+ $digit = self::decodeDigit( $input[ $pos++ ] );
- $w *= $t;
- }
+ if ( $digit >= self::BASE || $digit > intdiv( self::MAX_INT - $i, $w ) ) {
+ throw new PunycodeException( 'Punycode overflow' );
+ }
- $output_len++;
+ $i += $digit * $w;
- if (intdiv($i, $output_len) > self::MAX_INT - $n) {
- throw new PunycodeException("Punycode overflow");
- }
+ $t = self::threshold( $k, $bias );
+ if ( $digit < $t ) {
+ break;
+ }
- $n += intdiv($i, $output_len);
+ $t = self::BASE - $t;
- $bias = self::adapt($i - $old_i, $output_len, $old_i === 0);
+ if ( $w > intdiv( self::MAX_INT, $t ) ) {
+ throw new PunycodeException( 'Punycode overflow' );
+ }
- $i %= $output_len;
+ $w *= $t;
+ }
- array_splice($output, $i, 0, $n);
+ ++$output_len;
- $i++;
- }
+ if ( intdiv( $i, $output_len ) > self::MAX_INT - $n ) {
+ throw new PunycodeException( 'Punycode overflow' );
+ }
- return UnicodeString::getStringFromCodePoints($output);
- }
+ $n += intdiv( $i, $output_len );
- public static function normalizePart(string $input): string
- {
- $input = strtolower($input);
+ $bias = self::adapt( $i - $old_i, $output_len, $old_i === 0 );
- if (strpos($input, self::DELIMITER) === 0) {
- self::decodePart($input); // just validate
- return $input;
- }
+ $i %= $output_len;
- return self::encodePart($input);
- }
+ array_splice( $output, $i, 0, $n );
- private static function encodeDigit(int $digit): int
- {
- return $digit + 0x16 + ($digit < 0x1A ? 0x4B: 0x00);
- }
+ ++$i;
+ }
- private static function decodeDigit(int $code): int
- {
- if ($code < 0x3A) {
- return $code - 0x16;
- }
- if ($code < 0x5B) {
- return $code - 0x41;
- }
- if ($code < 0x7B) {
- return $code - 0x61;
- }
+ return UnicodeString::getStringFromCodePoints( $output );
+ }
- return self::BASE;
- }
+ public static function normalizePart( string $input ): string {
+ $input = strtolower( $input );
- private static function threshold(int $k, int $bias): int
- {
- $d = $k - $bias;
+ if ( strpos( $input, self::DELIMITER ) === 0 ) {
+ self::decodePart( $input ); // just validate
+ return $input;
+ }
- if ($d <= self::TMIN) {
- return self::TMIN;
- }
+ return self::encodePart( $input );
+ }
- if ($d >= self::TMAX) {
- return self::TMAX;
- }
+ private static function encodeDigit( int $digit ): int {
+ return $digit + 0x16 + ( $digit < 0x1A ? 0x4B : 0x00 );
+ }
- return $d;
- }
+ private static function decodeDigit( int $code ): int {
+ if ( $code < 0x3A ) {
+ return $code - 0x16;
+ }
+ if ( $code < 0x5B ) {
+ return $code - 0x41;
+ }
+ if ( $code < 0x7B ) {
+ return $code - 0x61;
+ }
- private static function adapt(int $delta, int $num_points, bool $first_time = false): int
- {
- $delta = intdiv($delta, $first_time ? self::DAMP : 2);
- $delta += intdiv($delta, $num_points);
+ return self::BASE;
+ }
- $k = 0;
- $base_tmin_diff = self::BASE - self::TMIN;
- $lim = $base_tmin_diff * self::TMAX / 2;
+ private static function threshold( int $k, int $bias ): int {
+ $d = $k - $bias;
- while ($delta > $lim) {
- $delta = intdiv($delta, $base_tmin_diff);
- $k += self::BASE;
- }
+ if ( $d <= self::TMIN ) {
+ return self::TMIN;
+ }
- $k += intdiv(($base_tmin_diff + 1) * $delta, $delta + self::SKEW);
+ if ( $d >= self::TMAX ) {
+ return self::TMAX;
+ }
- return $k;
- }
+ return $d;
+ }
+
+ private static function adapt( int $delta, int $num_points, bool $first_time = false ): int {
+ $delta = intdiv( $delta, $first_time ? self::DAMP : 2 );
+ $delta += intdiv( $delta, $num_points );
+
+ $k = 0;
+ $base_tmin_diff = self::BASE - self::TMIN;
+ $lim = $base_tmin_diff * self::TMAX / 2;
+
+ while ( $delta > $lim ) {
+ $delta = intdiv( $delta, $base_tmin_diff );
+ $k += self::BASE;
+ }
+
+ $k += intdiv( ( $base_tmin_diff + 1 ) * $delta, $delta + self::SKEW );
+
+ return $k;
+ }
}
diff --git a/src/opis/uri/src/PunycodeException.php b/src/opis/uri/src/PunycodeException.php
index 6eb1c129..dde604ee 100644
--- a/src/opis/uri/src/PunycodeException.php
+++ b/src/opis/uri/src/PunycodeException.php
@@ -1,5 +1,6 @@
[^:]+)(?::(?.*))?$`';
-
- const HOST_LABEL_REGEX = '`^(?:(?:%[a-f0-9]{2})+|[a-z0-9-]+)*$`i';
-
- const AUTHORITY_REGEX = '`^(?:(?[^@]+)\@)?(?(\[[a-f0-9:]+\]|[^:]+))(?::(?\d+))?$`i';
-
- const PATH_REGEX = '`^(?:(?:%[a-f0-9]{2})+|[a-z0-9-._~!$&\'()*+,;=:@/]+)*$`i';
-
- const QUERY_OR_FRAGMENT_REGEX = '`^(?:(?:%[a-f0-9]{2})+|[a-z0-9-._~!$&\'"()\[\]*+,;=:@?/%]+)*$`i';
-
- /**
- * @var mixed[]
- */
- protected $components;
-
- /**
- * @var string|null
- */
- protected $str;
-
- /**
- * @param array $components An array of normalized components
- */
- public function __construct(array $components)
- {
- $this->components = $components + [
- 'scheme' => null,
- 'user' => null,
- 'pass' => null,
- 'host' => null,
- 'port' => null,
- 'path' => null,
- 'query' => null,
- 'fragment' => null,
- ];
- }
-
- /**
- * @return string|null
- */
- public function scheme()
- {
- return $this->components['scheme'];
- }
-
- /**
- * @return string|null
- */
- public function user()
- {
- return $this->components['user'];
- }
-
- /**
- * @return string|null
- */
- public function pass()
- {
- return $this->components['pass'];
- }
-
- /**
- * @return string|null
- */
- public function userInfo()
- {
- if ($this->components['user'] === null) {
- return null;
- }
-
- if ($this->components['pass'] === null) {
- return $this->components['user'];
- }
-
- return $this->components['user'] . ':' . $this->components['pass'];
- }
-
- /**
- * @return string|null
- */
- public function host()
- {
- return $this->components['host'];
- }
-
- /**
- * @return int|null
- */
- public function port()
- {
- return $this->components['port'];
- }
-
- /**
- * @return string|null
- */
- public function authority()
- {
- if ($this->components['host'] === null) {
- return null;
- }
-
- $authority = $this->userInfo();
- if ($authority !== null) {
- $authority .= '@';
- }
-
- $authority .= $this->components['host'];
-
- if ($this->components['port'] !== null) {
- $authority .= ':' . $this->components['port'];
- }
-
- return $authority;
- }
-
- /**
- * @return string|null
- */
- public function path()
- {
- return $this->components['path'];
- }
-
- /**
- * @return string|null
- */
- public function query()
- {
- return $this->components['query'];
- }
-
- /**
- * @return string|null
- */
- public function fragment()
- {
- return $this->components['fragment'];
- }
-
- /**
- * @return array|null[]
- */
- public function components(): array
- {
- return $this->components;
- }
-
- /**
- * @return bool
- */
- public function isAbsolute(): bool
- {
- return $this->components['scheme'] !== null;
- }
-
- /**
- * Use this URI as base to resolve the reference
- * @param static|string|array $ref
- * @param bool $normalize
- * @return $this|null
- */
- public function resolveRef($ref, $normalize = false)
- {
- $ref = self::resolveComponents($ref);
- if ($ref === null) {
- return $this;
- }
-
- return new static(self::mergeComponents($ref, $this->components, $normalize));
- }
-
- /**
- * Resolve this URI reference using a base URI
- * @param static|string|array $base
- * @param bool $normalize
- * @return static
- */
- public function resolve($base, $normalize = false): self
- {
- if ($this->isAbsolute()) {
- return $this;
- }
-
- $base = self::resolveComponents($base);
-
- if ($base === null) {
- return $this;
- }
-
- return new static(self::mergeComponents($this->components, $base, $normalize));
- }
-
- /**
- * @return string
- */
- public function __toString(): string
- {
- if ($this->str !== null) {
- return $this->str;
- }
-
- $str = '';
-
- if ($this->components['scheme'] !== null) {
- $str .= $this->components['scheme'] . ':';
- }
-
- if ($this->components['host'] !== null) {
- $str .= '//' . $this->authority();
- }
-
- $str .= $this->components['path'];
-
- if ($this->components['query'] !== null) {
- $str .= '?' . $this->components['query'];
- }
-
- if ($this->components['fragment'] !== null) {
- $str .= '#' . $this->components['fragment'];
- }
-
- return $this->str = $str;
- }
-
- /**
- * @param string $uri
- * @param bool $normalize
- * @return static|null
- */
- public static function create($uri, $normalize = false)
- {
- $comp = self::parseComponents($uri);
- if (!$comp) {
- return null;
- }
-
- if ($normalize) {
- $comp = self::normalizeComponents($comp);
- }
-
- return new static($comp);
- }
-
- /**
- * Checks if the scheme contains valid chars
- * @param string $scheme
- * @return bool
- */
- public static function isValidScheme($scheme): bool
- {
- return (bool)preg_match(self::SCHEME_REGEX, $scheme);
- }
-
- /**
- * Checks if user contains valid chars
- * @param string $user
- * @return bool
- */
- public static function isValidUser($user): bool
- {
- return (bool)preg_match(self::USER_OR_PASS_REGEX, $user);
- }
-
- /**
- * Checks if pass contains valid chars
- * @param string $pass
- * @return bool
- */
- public static function isValidPass($pass): bool
- {
- return (bool)preg_match(self::USER_OR_PASS_REGEX, $pass);
- }
-
- /**
- * @param string $userInfo
- * @return bool
- */
- public static function isValidUserInfo($userInfo): bool
- {
- /** @var array|string $userInfo */
-
- if (!preg_match(self::USERINFO_REGEX, $userInfo, $userInfo)) {
- return false;
- }
-
- if (!self::isValidUser($userInfo['user'])) {
- return false;
- }
-
- if (isset($userInfo['pass'])) {
- return self::isValidPass($userInfo['pass']);
- }
-
- return true;
- }
-
- /**
- * Checks if host is valid
- * @param string $host
- * @return bool
- */
- public static function isValidHost($host): bool
- {
- // min and max length
- if ($host === '' || isset($host[253])) {
- return false;
- }
-
- // check ipv6
- if ($host[0] === '[') {
- if ($host[-1] !== ']') {
- return false;
- }
-
- return filter_var(
- substr($host, 1, -1),
- \FILTER_VALIDATE_IP,
- \FILTER_FLAG_IPV6
- ) !== false;
- }
-
- // check ipv4
- if (preg_match('`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\$`', $host)) {
- return \filter_var($host, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4) !== false;
- }
-
- foreach (explode('.', $host) as $host) {
- // empty or too long label
- if ($host === '' || isset($host[63])) {
- return false;
- }
- if ($host[0] === '-' || $host[-1] === '-') {
- return false;
- }
- if (!preg_match(self::HOST_LABEL_REGEX, $host)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Checks if the port is valid
- * @param int $port
- * @return bool
- */
- public static function isValidPort($port): bool
- {
- return $port >= 0 && $port <= 65535;
- }
-
- /**
- * Checks if authority contains valid chars
- * @param string $authority
- * @return bool
- */
- public static function isValidAuthority($authority): bool
- {
- if ($authority === '') {
- return true;
- }
-
- /** @var array|string $authority */
-
- if (!preg_match(self::AUTHORITY_REGEX, $authority, $authority)) {
- return false;
- }
-
- if (isset($authority['port']) && !self::isValidPort((int)$authority['port'])) {
- return false;
- }
-
- if (isset($authority['userinfo']) && !self::isValidUserInfo($authority['userinfo'])) {
- return false;
- }
-
- return self::isValidHost($authority['host']);
- }
-
- /**
- * Checks if the path contains valid chars
- * @param string $path
- * @return bool
- */
- public static function isValidPath($path): bool
- {
- return $path === '' || (bool)preg_match(self::PATH_REGEX, $path);
- }
-
- /**
- * Checks if the query string contains valid chars
- * @param string $query
- * @return bool
- */
- public static function isValidQuery($query): bool
- {
- return $query === '' || (bool)preg_match(self::QUERY_OR_FRAGMENT_REGEX, $query);
- }
-
- /**
- * Checks if the fragment contains valid chars
- * @param string $fragment
- * @return bool
- */
- public static function isValidFragment($fragment): bool
- {
- return $fragment === '' || (bool)preg_match(self::QUERY_OR_FRAGMENT_REGEX, $fragment);
- }
-
- /**
- * @param string $uri
- * @param bool $expand_authority
- * @param bool $validate
- * @return array|null
- */
- public static function parseComponents($uri, $expand_authority = true, $validate = true)
- {
- if (!preg_match(self::URI_REGEX, $uri, $uri)) {
- return null;
- }
-
- $comp = [];
-
- // scheme
- if (isset($uri[2]) && $uri[2] !== '') {
- if ($validate && !self::isValidScheme($uri[2])) {
- return null;
- }
- $comp['scheme'] = $uri[2];
- }
-
- // authority
- if (isset($uri[4]) && isset($uri[3][0])) {
- if ($uri[4] === '') {
- if ($expand_authority) {
- $comp['host'] = '';
- } else {
- $comp['authority'] = '';
- }
- } elseif ($expand_authority) {
- $au = self::parseAuthorityComponents($uri[4], $validate);
- if ($au === null) {
- return null;
- }
- $comp += $au;
- unset($au);
- } else {
- if ($validate && !self::isValidAuthority($uri[4])) {
- return null;
- }
- $comp['authority'] = $uri[4];
- }
- }
-
- // path
- if (isset($uri[5])) {
- if ($validate && !self::isValidPath($uri[5])) {
- return null;
- }
- $comp['path'] = $uri[5];
- // not a relative uri, remove dot segments
- if (isset($comp['scheme']) || isset($comp['authority']) || isset($comp['host'])) {
- $comp['path'] = self::removeDotSegmentsFromPath($comp['path']);
- }
- }
-
- // query
- if (isset($uri[7]) && isset($uri[6][0])) {
- if ($validate && !self::isValidQuery($uri[7])) {
- return null;
- }
- $comp['query'] = $uri[7];
- }
-
- // fragment
- if (isset($uri[9]) && isset($uri[8][0])) {
- if ($validate && !self::isValidFragment($uri[9])) {
- return null;
- }
- $comp['fragment'] = $uri[9];
- }
-
- return $comp;
- }
-
- /**
- * @param self|string|array $uri
- * @return array|null
- */
- public static function resolveComponents($uri)
- {
- if ($uri instanceof self) {
- return $uri->components;
- }
-
- if (is_string($uri)) {
- return self::parseComponents($uri);
- }
-
- if (is_array($uri)) {
- if (isset($uri['host'])) {
- unset($uri['authority']);
- } elseif (isset($uri['authority'])) {
- $au = self::parseAuthorityComponents($uri['authority']);
- unset($uri['authority']);
- if ($au !== null) {
- unset($uri['user'], $uri['pass'], $uri['host'], $uri['port']);
- $uri += $au;
- }
- }
- return $uri;
- }
-
- return null;
- }
-
- /**
- * @param string $authority
- * @param bool $validate
- * @return array|null
- */
- public static function parseAuthorityComponents($authority, $validate = true)
- {
- /** @var array|string $authority */
-
- if (!preg_match(self::AUTHORITY_REGEX, $authority, $authority)) {
- return null;
- }
-
- $comp = [];
-
- // userinfo
- if (isset($authority['userinfo']) && $authority['userinfo'] !== '') {
- if (!preg_match(self::USERINFO_REGEX, $authority['userinfo'], $ui)) {
- return null;
- }
-
- // user
- if ($validate && !self::isValidUser($ui['user'])) {
- return null;
- }
- $comp['user'] = $ui['user'];
-
- // pass
- if (isset($ui['pass']) && $ui['pass'] !== '') {
- if ($validate && !self::isValidPass($ui['pass'])) {
- return null;
- }
- $comp['pass'] = $ui['pass'];
- }
-
- unset($ui);
- }
-
- // host
- if ($validate && !self::isValidHost($authority['host'])) {
- return null;
- }
- $comp['host'] = $authority['host'];
-
-
- // port
- if (isset($authority['port'])) {
- $authority['port'] = (int)$authority['port'];
- if (!self::isValidPort($authority['port'])) {
- return null;
- }
- $comp['port'] = $authority['port'];
- }
-
- return $comp;
- }
-
- /**
- * @param array $ref
- * @param array $base
- * @param bool $normalize
- * @return array
- */
- public static function mergeComponents($ref, $base, $normalize = false): array
- {
- if (isset($ref['scheme'])) {
- $dest = $ref;
- } else {
- $dest = [];
-
- $dest['scheme'] = $base['scheme'] ?? null;
-
- if (isset($ref['authority']) || isset($ref['host'])) {
- $dest += $ref;
- } else {
- if (isset($base['authority'])) {
- $dest['authority'] = $base['authority'];
- } else {
- $dest['user'] = $base['user'] ?? null;
- $dest['pass'] = $base['pass'] ?? null;
- $dest['host'] = $base['host'] ?? null;
- $dest['port'] = $base['port'] ?? null;
- }
-
- if (!isset($ref['path'])) {
- $ref['path'] = '';
- }
- if (!isset($base['path'])) {
- $base['path'] = '';
- }
-
- if ($ref['path'] === '') {
- $dest['path'] = $base['path'];
- $dest['query'] = $ref['query'] ?? $base['query'] ?? null;
- } else {
- if ($ref['path'][0] === '/') {
- $dest['path'] = $ref['path'];
- } else {
- if ((isset($base['authority']) || isset($base['host'])) && $base['path'] === '') {
- $dest['path'] = '/' . $ref['path'];
- } else {
- $dest['path'] = $base['path'];
-
- if ($dest['path'] !== '') {
- $pos = strrpos($dest['path'], '/');
- if ($pos === false) {
- $dest['path'] = '';
- } else {
- $dest['path'] = substr($dest['path'], 0, $pos);
- }
-
- unset($pos);
- }
- $dest['path'] .= '/' . $ref['path'];
- }
- }
-
- $dest['query'] = $ref['query'] ?? null;
- }
- }
- }
-
- $dest['fragment'] = $ref['fragment'] ?? null;
-
- if ($normalize) {
- return self::normalizeComponents($dest);
- }
-
- if (isset($dest['path'])) {
- $dest['path'] = self::removeDotSegmentsFromPath($dest['path']);
- }
-
- return $dest;
- }
-
- /**
- * @param mixed[] $components
- */
- public static function normalizeComponents($components): array
- {
- if (isset($components['scheme'])) {
- $components['scheme'] = strtolower($components['scheme']);
- // Remove default port
- if (isset($components['port']) && self::getSchemePort($components['scheme']) === $components['port']) {
- $components['port'] = null;
- }
- }
-
- if (isset($components['host'])) {
- $components['host'] = strtolower($components['host']);
- }
-
- if (isset($components['path'])) {
- $components['path'] = self::removeDotSegmentsFromPath($components['path']);
- }
-
- if (isset($components['query'])) {
- $components['query'] = self::normalizeQueryString($components['query']);
- }
-
- return $components;
- }
-
- /**
- * Removes dot segments from path
- * @param string $path
- * @return string
- */
- public static function removeDotSegmentsFromPath($path): string
- {
- // Fast check common simple paths
- if ($path === '' || $path === '/') {
- return $path;
- }
-
- $output = '';
- $last_slash = 0;
-
- $len = strlen($path);
- $i = 0;
-
- while ($i < $len) {
- if ($path[$i] === '.') {
- $j = $i + 1;
- // search for .
- if ($j >= $len) {
- break;
- }
-
- // search for ./
- if ($path[$j] === '/') {
- $i = $j + 1;
- continue;
- }
-
- // search for ../
- if ($path[$j] === '.') {
- $k = $j + 1;
- if ($k >= $len) {
- break;
- }
- if ($path[$k] === '/') {
- $i = $k + 1;
- continue;
- }
- }
- } elseif ($path[$i] === '/') {
- $j = $i + 1;
- if ($j >= $len) {
- $output .= '/';
- break;
- }
-
- // search for /.
- if ($path[$j] === '.') {
- $k = $j + 1;
- if ($k >= $len) {
- $output .= '/';
- break;
- }
- // search for /./
- if ($path[$k] === '/') {
- $i = $k;
- continue;
- }
- // search for /..
- if ($path[$k] === '.') {
- $n = $k + 1;
- if ($n >= $len) {
- // keep the slash
- $output = substr($output, 0, $last_slash + 1);
- break;
- }
- // search for /../
- if ($path[$n] === '/') {
- $output = substr($output, 0, $last_slash);
- $last_slash = (int)strrpos($output, '/');
- $i = $n;
- continue;
- }
- }
- }
- }
-
- $pos = strpos($path, '/', $i + 1);
-
- if ($pos === false) {
- $output .= substr($path, $i);
- break;
- }
-
- $last_slash = strlen($output);
- $output .= substr($path, $i, $pos - $i);
-
- $i = $pos;
- }
-
- return $output;
- }
-
- /**
- * @param string|null $query
- * @return array
- */
- public static function parseQueryString($query): array
- {
- if ($query === null) {
- return [];
- }
-
- $list = [];
-
- foreach (explode('&', $query) as $name) {
- $value = null;
- if (($pos = strpos($name, '=')) !== false) {
- $value = self::decodeComponent(substr($name, $pos + 1));
- $name = self::decodeComponent(substr($name, 0, $pos));
- } else {
- $name = self::decodeComponent($name);
- }
- $list[$name] = $value;
- }
-
- return $list;
- }
-
- /**
- * @param array $qs
- * @param string|null $prefix
- * @param string $separator
- * @param bool $sort
- * @return string
- */
- public static function buildQueryString($qs, $prefix = null,
- $separator = '&', $sort = false): string
- {
- $isIndexed = static function (array $array): bool {
- for ($i = 0, $max = count($array); $i < $max; $i++) {
- if (!array_key_exists($i, $array)) {
- return false;
- }
- }
- return true;
- };
-
- $f = static function (array $arr, $prefix = null) use (&$f, &$isIndexed) {
- $indexed = $prefix !== null && $isIndexed($arr);
-
- foreach ($arr as $key => $value) {
- if ($prefix !== null) {
- $key = $prefix . ($indexed ? "[]" : "[{$key}]");
- }
- if (is_array($value)) {
- yield from $f($value, $key);
- } else {
- yield $key => $value;
- }
- }
- };
-
- $data = [];
-
- foreach ($f($qs, $prefix) as $key => $value) {
- $item = is_string($key) ? self::encodeComponent($key) : $key;
- if ($value !== null) {
- $item .= '=';
- $item .= is_string($value) ? self::encodeComponent($value) : $value;
- }
- if ($item === '' || $item === '=') {
- continue;
- }
- $data[] = $item;
- }
-
- if (!$data) {
- return '';
- }
-
- if ($sort) {
- sort($data);
- }
-
- return implode($separator, $data);
- }
-
- /**
- * @param string $query
- * @return string
- */
- public static function normalizeQueryString($query): string
- {
- return static::buildQueryString(self::parseQueryString($query), null, '&', true);
- }
-
- /**
- * @param string $component
- */
- public static function decodeComponent($component): string
- {
- return rawurldecode($component);
- }
-
- /**
- * @param string $component
- * @param mixed[]|null $skip
- */
- public static function encodeComponent($component, $skip = null): string
- {
- if (!$skip) {
- return rawurlencode($component);
- }
-
- $str = '';
-
- foreach (UnicodeString::walkString($component) as list($cp, $chars)) {
- if ($cp < 0x80) {
- if ($cp === 0x2D || $cp === 0x2E ||
- $cp === 0x5F || $cp === 0x7E ||
- ($cp >= 0x41 && $cp <= 0x5A) ||
- ($cp >= 0x61 && $cp <= 0x7A) ||
- ($cp >= 0x30 && $cp <= 0x39) ||
- in_array($cp, $skip, true)
- ) {
- $str .= chr($cp);
- } else {
- $str .= '%' . strtoupper(dechex($cp));
- }
- } else {
- $i = 0;
- while (isset($chars[$i])) {
- $str .= '%' . strtoupper(dechex($chars[$i++]));
- }
- }
- }
-
- return $str;
- }
-
- /**
- * @param string $scheme
- * @param int|null $port
- */
- public static function setSchemePort($scheme, $port)
- {
- $scheme = strtolower($scheme);
-
- if ($port === null) {
- unset(self::$KNOWN_PORTS[$scheme]);
- } else {
- self::$KNOWN_PORTS[$scheme] = $port;
- }
- }
-
- /**
- * @param string $scheme
- */
- public static function getSchemePort($scheme)
- {
- return self::$KNOWN_PORTS[strtolower($scheme)] ?? null;
- }
-
- /**
- * @var mixed[]
- */
- protected static $KNOWN_PORTS = [
- 'ftp' => 21,
- 'ssh' => 22,
- 'telnet' => 23,
- 'smtp' => 25,
- 'tftp' => 69,
- 'http' => 80,
- 'pop' => 110,
- 'sftp' => 115,
- 'imap' => 143,
- 'irc' => 194,
- 'ldap' => 389,
- 'https' => 443,
- 'ldaps' => 636,
- 'telnets' => 992,
- 'imaps' => 993,
- 'ircs' => 994,
- 'pops' => 995,
- ];
+class Uri {
+
+ const URI_REGEX = '`^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$`';
+
+ const SCHEME_REGEX = '`^[a-z][a-z0-9-+.]*$`i';
+
+ const USER_OR_PASS_REGEX = '`^(?:(?:%[a-f0-9]{2})+|[a-z0-9-._~!$&\'()*+,:;=]+)*$`i';
+
+ const USERINFO_REGEX = '`^(?[^:]+)(?::(?.*))?$`';
+
+ const HOST_LABEL_REGEX = '`^(?:(?:%[a-f0-9]{2})+|[a-z0-9-]+)*$`i';
+
+ const AUTHORITY_REGEX = '`^(?:(?[^@]+)\@)?(?(\[[a-f0-9:]+\]|[^:]+))(?::(?\d+))?$`i';
+
+ const PATH_REGEX = '`^(?:(?:%[a-f0-9]{2})+|[a-z0-9-._~!$&\'()*+,;=:@/]+)*$`i';
+
+ const QUERY_OR_FRAGMENT_REGEX = '`^(?:(?:%[a-f0-9]{2})+|[a-z0-9-._~!$&\'"()\[\]*+,;=:@?/%]+)*$`i';
+
+ /**
+ * @var mixed[]
+ */
+ protected $components;
+
+ /**
+ * @var string|null
+ */
+ protected $str;
+
+ /**
+ * @param array $components An array of normalized components
+ */
+ public function __construct( array $components ) {
+ $this->components = $components + array(
+ 'scheme' => null,
+ 'user' => null,
+ 'pass' => null,
+ 'host' => null,
+ 'port' => null,
+ 'path' => null,
+ 'query' => null,
+ 'fragment' => null,
+ );
+ }
+
+ /**
+ * @return string|null
+ */
+ public function scheme() {
+ return $this->components['scheme'];
+ }
+
+ /**
+ * @return string|null
+ */
+ public function user() {
+ return $this->components['user'];
+ }
+
+ /**
+ * @return string|null
+ */
+ public function pass() {
+ return $this->components['pass'];
+ }
+
+ /**
+ * @return string|null
+ */
+ public function userInfo() {
+ if ( $this->components['user'] === null ) {
+ return null;
+ }
+
+ if ( $this->components['pass'] === null ) {
+ return $this->components['user'];
+ }
+
+ return $this->components['user'] . ':' . $this->components['pass'];
+ }
+
+ /**
+ * @return string|null
+ */
+ public function host() {
+ return $this->components['host'];
+ }
+
+ /**
+ * @return int|null
+ */
+ public function port() {
+ return $this->components['port'];
+ }
+
+ /**
+ * @return string|null
+ */
+ public function authority() {
+ if ( $this->components['host'] === null ) {
+ return null;
+ }
+
+ $authority = $this->userInfo();
+ if ( $authority !== null ) {
+ $authority .= '@';
+ }
+
+ $authority .= $this->components['host'];
+
+ if ( $this->components['port'] !== null ) {
+ $authority .= ':' . $this->components['port'];
+ }
+
+ return $authority;
+ }
+
+ /**
+ * @return string|null
+ */
+ public function path() {
+ return $this->components['path'];
+ }
+
+ /**
+ * @return string|null
+ */
+ public function query() {
+ return $this->components['query'];
+ }
+
+ /**
+ * @return string|null
+ */
+ public function fragment() {
+ return $this->components['fragment'];
+ }
+
+ /**
+ * @return array|null[]
+ */
+ public function components(): array {
+ return $this->components;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isAbsolute(): bool {
+ return $this->components['scheme'] !== null;
+ }
+
+ /**
+ * Use this URI as base to resolve the reference
+ *
+ * @param static|string|array $ref
+ * @param bool $normalize
+ * @return $this|null
+ */
+ public function resolveRef( $ref, $normalize = false ) {
+ $ref = self::resolveComponents( $ref );
+ if ( $ref === null ) {
+ return $this;
+ }
+
+ return new static( self::mergeComponents( $ref, $this->components, $normalize ) );
+ }
+
+ /**
+ * Resolve this URI reference using a base URI
+ *
+ * @param static|string|array $base
+ * @param bool $normalize
+ * @return static
+ */
+ public function resolve( $base, $normalize = false ): self {
+ if ( $this->isAbsolute() ) {
+ return $this;
+ }
+
+ $base = self::resolveComponents( $base );
+
+ if ( $base === null ) {
+ return $this;
+ }
+
+ return new static( self::mergeComponents( $this->components, $base, $normalize ) );
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString(): string {
+ if ( $this->str !== null ) {
+ return $this->str;
+ }
+
+ $str = '';
+
+ if ( $this->components['scheme'] !== null ) {
+ $str .= $this->components['scheme'] . ':';
+ }
+
+ if ( $this->components['host'] !== null ) {
+ $str .= '//' . $this->authority();
+ }
+
+ $str .= $this->components['path'];
+
+ if ( $this->components['query'] !== null ) {
+ $str .= '?' . $this->components['query'];
+ }
+
+ if ( $this->components['fragment'] !== null ) {
+ $str .= '#' . $this->components['fragment'];
+ }
+
+ return $this->str = $str;
+ }
+
+ /**
+ * @param string $uri
+ * @param bool $normalize
+ * @return static|null
+ */
+ public static function create( $uri, $normalize = false ) {
+ $comp = self::parseComponents( $uri );
+ if ( ! $comp ) {
+ return null;
+ }
+
+ if ( $normalize ) {
+ $comp = self::normalizeComponents( $comp );
+ }
+
+ return new static( $comp );
+ }
+
+ /**
+ * Checks if the scheme contains valid chars
+ *
+ * @param string $scheme
+ * @return bool
+ */
+ public static function isValidScheme( $scheme ): bool {
+ return (bool) preg_match( self::SCHEME_REGEX, $scheme );
+ }
+
+ /**
+ * Checks if user contains valid chars
+ *
+ * @param string $user
+ * @return bool
+ */
+ public static function isValidUser( $user ): bool {
+ return (bool) preg_match( self::USER_OR_PASS_REGEX, $user );
+ }
+
+ /**
+ * Checks if pass contains valid chars
+ *
+ * @param string $pass
+ * @return bool
+ */
+ public static function isValidPass( $pass ): bool {
+ return (bool) preg_match( self::USER_OR_PASS_REGEX, $pass );
+ }
+
+ /**
+ * @param string $userInfo
+ * @return bool
+ */
+ public static function isValidUserInfo( $userInfo ): bool {
+ /** @var array|string $userInfo */
+
+ if ( ! preg_match( self::USERINFO_REGEX, $userInfo, $userInfo ) ) {
+ return false;
+ }
+
+ if ( ! self::isValidUser( $userInfo['user'] ) ) {
+ return false;
+ }
+
+ if ( isset( $userInfo['pass'] ) ) {
+ return self::isValidPass( $userInfo['pass'] );
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if host is valid
+ *
+ * @param string $host
+ * @return bool
+ */
+ public static function isValidHost( $host ): bool {
+ // min and max length
+ if ( $host === '' || isset( $host[253] ) ) {
+ return false;
+ }
+
+ // check ipv6
+ if ( $host[0] === '[' ) {
+ if ( $host[-1] !== ']' ) {
+ return false;
+ }
+
+ return filter_var(
+ substr( $host, 1, -1 ),
+ \FILTER_VALIDATE_IP,
+ \FILTER_FLAG_IPV6
+ ) !== false;
+ }
+
+ // check ipv4
+ if ( preg_match( '`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\$`', $host ) ) {
+ return \filter_var( $host, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4 ) !== false;
+ }
+
+ foreach ( explode( '.', $host ) as $host ) {
+ // empty or too long label
+ if ( $host === '' || isset( $host[63] ) ) {
+ return false;
+ }
+ if ( $host[0] === '-' || $host[-1] === '-' ) {
+ return false;
+ }
+ if ( ! preg_match( self::HOST_LABEL_REGEX, $host ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if the port is valid
+ *
+ * @param int $port
+ * @return bool
+ */
+ public static function isValidPort( $port ): bool {
+ return $port >= 0 && $port <= 65535;
+ }
+
+ /**
+ * Checks if authority contains valid chars
+ *
+ * @param string $authority
+ * @return bool
+ */
+ public static function isValidAuthority( $authority ): bool {
+ if ( $authority === '' ) {
+ return true;
+ }
+
+ /** @var array|string $authority */
+
+ if ( ! preg_match( self::AUTHORITY_REGEX, $authority, $authority ) ) {
+ return false;
+ }
+
+ if ( isset( $authority['port'] ) && ! self::isValidPort( (int) $authority['port'] ) ) {
+ return false;
+ }
+
+ if ( isset( $authority['userinfo'] ) && ! self::isValidUserInfo( $authority['userinfo'] ) ) {
+ return false;
+ }
+
+ return self::isValidHost( $authority['host'] );
+ }
+
+ /**
+ * Checks if the path contains valid chars
+ *
+ * @param string $path
+ * @return bool
+ */
+ public static function isValidPath( $path ): bool {
+ return $path === '' || (bool) preg_match( self::PATH_REGEX, $path );
+ }
+
+ /**
+ * Checks if the query string contains valid chars
+ *
+ * @param string $query
+ * @return bool
+ */
+ public static function isValidQuery( $query ): bool {
+ return $query === '' || (bool) preg_match( self::QUERY_OR_FRAGMENT_REGEX, $query );
+ }
+
+ /**
+ * Checks if the fragment contains valid chars
+ *
+ * @param string $fragment
+ * @return bool
+ */
+ public static function isValidFragment( $fragment ): bool {
+ return $fragment === '' || (bool) preg_match( self::QUERY_OR_FRAGMENT_REGEX, $fragment );
+ }
+
+ /**
+ * @param string $uri
+ * @param bool $expand_authority
+ * @param bool $validate
+ * @return array|null
+ */
+ public static function parseComponents( $uri, $expand_authority = true, $validate = true ) {
+ if ( ! preg_match( self::URI_REGEX, $uri, $uri ) ) {
+ return null;
+ }
+
+ $comp = array();
+
+ // scheme
+ if ( isset( $uri[2] ) && $uri[2] !== '' ) {
+ if ( $validate && ! self::isValidScheme( $uri[2] ) ) {
+ return null;
+ }
+ $comp['scheme'] = $uri[2];
+ }
+
+ // authority
+ if ( isset( $uri[4] ) && isset( $uri[3][0] ) ) {
+ if ( $uri[4] === '' ) {
+ if ( $expand_authority ) {
+ $comp['host'] = '';
+ } else {
+ $comp['authority'] = '';
+ }
+ } elseif ( $expand_authority ) {
+ $au = self::parseAuthorityComponents( $uri[4], $validate );
+ if ( $au === null ) {
+ return null;
+ }
+ $comp += $au;
+ unset( $au );
+ } else {
+ if ( $validate && ! self::isValidAuthority( $uri[4] ) ) {
+ return null;
+ }
+ $comp['authority'] = $uri[4];
+ }
+ }
+
+ // path
+ if ( isset( $uri[5] ) ) {
+ if ( $validate && ! self::isValidPath( $uri[5] ) ) {
+ return null;
+ }
+ $comp['path'] = $uri[5];
+ // not a relative uri, remove dot segments
+ if ( isset( $comp['scheme'] ) || isset( $comp['authority'] ) || isset( $comp['host'] ) ) {
+ $comp['path'] = self::removeDotSegmentsFromPath( $comp['path'] );
+ }
+ }
+
+ // query
+ if ( isset( $uri[7] ) && isset( $uri[6][0] ) ) {
+ if ( $validate && ! self::isValidQuery( $uri[7] ) ) {
+ return null;
+ }
+ $comp['query'] = $uri[7];
+ }
+
+ // fragment
+ if ( isset( $uri[9] ) && isset( $uri[8][0] ) ) {
+ if ( $validate && ! self::isValidFragment( $uri[9] ) ) {
+ return null;
+ }
+ $comp['fragment'] = $uri[9];
+ }
+
+ return $comp;
+ }
+
+ /**
+ * @param self|string|array $uri
+ * @return array|null
+ */
+ public static function resolveComponents( $uri ) {
+ if ( $uri instanceof self ) {
+ return $uri->components;
+ }
+
+ if ( is_string( $uri ) ) {
+ return self::parseComponents( $uri );
+ }
+
+ if ( is_array( $uri ) ) {
+ if ( isset( $uri['host'] ) ) {
+ unset( $uri['authority'] );
+ } elseif ( isset( $uri['authority'] ) ) {
+ $au = self::parseAuthorityComponents( $uri['authority'] );
+ unset( $uri['authority'] );
+ if ( $au !== null ) {
+ unset( $uri['user'], $uri['pass'], $uri['host'], $uri['port'] );
+ $uri += $au;
+ }
+ }
+ return $uri;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $authority
+ * @param bool $validate
+ * @return array|null
+ */
+ public static function parseAuthorityComponents( $authority, $validate = true ) {
+ /** @var array|string $authority */
+
+ if ( ! preg_match( self::AUTHORITY_REGEX, $authority, $authority ) ) {
+ return null;
+ }
+
+ $comp = array();
+
+ // userinfo
+ if ( isset( $authority['userinfo'] ) && $authority['userinfo'] !== '' ) {
+ if ( ! preg_match( self::USERINFO_REGEX, $authority['userinfo'], $ui ) ) {
+ return null;
+ }
+
+ // user
+ if ( $validate && ! self::isValidUser( $ui['user'] ) ) {
+ return null;
+ }
+ $comp['user'] = $ui['user'];
+
+ // pass
+ if ( isset( $ui['pass'] ) && $ui['pass'] !== '' ) {
+ if ( $validate && ! self::isValidPass( $ui['pass'] ) ) {
+ return null;
+ }
+ $comp['pass'] = $ui['pass'];
+ }
+
+ unset( $ui );
+ }
+
+ // host
+ if ( $validate && ! self::isValidHost( $authority['host'] ) ) {
+ return null;
+ }
+ $comp['host'] = $authority['host'];
+
+ // port
+ if ( isset( $authority['port'] ) ) {
+ $authority['port'] = (int) $authority['port'];
+ if ( ! self::isValidPort( $authority['port'] ) ) {
+ return null;
+ }
+ $comp['port'] = $authority['port'];
+ }
+
+ return $comp;
+ }
+
+ /**
+ * @param array $ref
+ * @param array $base
+ * @param bool $normalize
+ * @return array
+ */
+ public static function mergeComponents( $ref, $base, $normalize = false ): array {
+ if ( isset( $ref['scheme'] ) ) {
+ $dest = $ref;
+ } else {
+ $dest = array();
+
+ $dest['scheme'] = $base['scheme'] ?? null;
+
+ if ( isset( $ref['authority'] ) || isset( $ref['host'] ) ) {
+ $dest += $ref;
+ } else {
+ if ( isset( $base['authority'] ) ) {
+ $dest['authority'] = $base['authority'];
+ } else {
+ $dest['user'] = $base['user'] ?? null;
+ $dest['pass'] = $base['pass'] ?? null;
+ $dest['host'] = $base['host'] ?? null;
+ $dest['port'] = $base['port'] ?? null;
+ }
+
+ if ( ! isset( $ref['path'] ) ) {
+ $ref['path'] = '';
+ }
+ if ( ! isset( $base['path'] ) ) {
+ $base['path'] = '';
+ }
+
+ if ( $ref['path'] === '' ) {
+ $dest['path'] = $base['path'];
+ $dest['query'] = $ref['query'] ?? $base['query'] ?? null;
+ } else {
+ if ( $ref['path'][0] === '/' ) {
+ $dest['path'] = $ref['path'];
+ } elseif ( ( isset( $base['authority'] ) || isset( $base['host'] ) ) && $base['path'] === '' ) {
+ $dest['path'] = '/' . $ref['path'];
+ } else {
+ $dest['path'] = $base['path'];
+
+ if ( $dest['path'] !== '' ) {
+ $pos = strrpos( $dest['path'], '/' );
+ if ( $pos === false ) {
+ $dest['path'] = '';
+ } else {
+ $dest['path'] = substr( $dest['path'], 0, $pos );
+ }
+
+ unset( $pos );
+ }
+ $dest['path'] .= '/' . $ref['path'];
+ }
+
+ $dest['query'] = $ref['query'] ?? null;
+ }
+ }
+ }
+
+ $dest['fragment'] = $ref['fragment'] ?? null;
+
+ if ( $normalize ) {
+ return self::normalizeComponents( $dest );
+ }
+
+ if ( isset( $dest['path'] ) ) {
+ $dest['path'] = self::removeDotSegmentsFromPath( $dest['path'] );
+ }
+
+ return $dest;
+ }
+
+ /**
+ * @param mixed[] $components
+ */
+ public static function normalizeComponents( $components ): array {
+ if ( isset( $components['scheme'] ) ) {
+ $components['scheme'] = strtolower( $components['scheme'] );
+ // Remove default port
+ if ( isset( $components['port'] ) && self::getSchemePort( $components['scheme'] ) === $components['port'] ) {
+ $components['port'] = null;
+ }
+ }
+
+ if ( isset( $components['host'] ) ) {
+ $components['host'] = strtolower( $components['host'] );
+ }
+
+ if ( isset( $components['path'] ) ) {
+ $components['path'] = self::removeDotSegmentsFromPath( $components['path'] );
+ }
+
+ if ( isset( $components['query'] ) ) {
+ $components['query'] = self::normalizeQueryString( $components['query'] );
+ }
+
+ return $components;
+ }
+
+ /**
+ * Removes dot segments from path
+ *
+ * @param string $path
+ * @return string
+ */
+ public static function removeDotSegmentsFromPath( $path ): string {
+ // Fast check common simple paths
+ if ( $path === '' || $path === '/' ) {
+ return $path;
+ }
+
+ $output = '';
+ $last_slash = 0;
+
+ $len = strlen( $path );
+ $i = 0;
+
+ while ( $i < $len ) {
+ if ( $path[ $i ] === '.' ) {
+ $j = $i + 1;
+ // search for .
+ if ( $j >= $len ) {
+ break;
+ }
+
+ // search for ./
+ if ( $path[ $j ] === '/' ) {
+ $i = $j + 1;
+ continue;
+ }
+
+ // search for ../
+ if ( $path[ $j ] === '.' ) {
+ $k = $j + 1;
+ if ( $k >= $len ) {
+ break;
+ }
+ if ( $path[ $k ] === '/' ) {
+ $i = $k + 1;
+ continue;
+ }
+ }
+ } elseif ( $path[ $i ] === '/' ) {
+ $j = $i + 1;
+ if ( $j >= $len ) {
+ $output .= '/';
+ break;
+ }
+
+ // search for /.
+ if ( $path[ $j ] === '.' ) {
+ $k = $j + 1;
+ if ( $k >= $len ) {
+ $output .= '/';
+ break;
+ }
+ // search for /./
+ if ( $path[ $k ] === '/' ) {
+ $i = $k;
+ continue;
+ }
+ // search for /..
+ if ( $path[ $k ] === '.' ) {
+ $n = $k + 1;
+ if ( $n >= $len ) {
+ // keep the slash
+ $output = substr( $output, 0, $last_slash + 1 );
+ break;
+ }
+ // search for /../
+ if ( $path[ $n ] === '/' ) {
+ $output = substr( $output, 0, $last_slash );
+ $last_slash = (int) strrpos( $output, '/' );
+ $i = $n;
+ continue;
+ }
+ }
+ }
+ }
+
+ $pos = strpos( $path, '/', $i + 1 );
+
+ if ( $pos === false ) {
+ $output .= substr( $path, $i );
+ break;
+ }
+
+ $last_slash = strlen( $output );
+ $output .= substr( $path, $i, $pos - $i );
+
+ $i = $pos;
+ }
+
+ return $output;
+ }
+
+ /**
+ * @param string|null $query
+ * @return array
+ */
+ public static function parseQueryString( $query ): array {
+ if ( $query === null ) {
+ return array();
+ }
+
+ $list = array();
+
+ foreach ( explode( '&', $query ) as $name ) {
+ $value = null;
+ if ( ( $pos = strpos( $name, '=' ) ) !== false ) {
+ $value = self::decodeComponent( substr( $name, $pos + 1 ) );
+ $name = self::decodeComponent( substr( $name, 0, $pos ) );
+ } else {
+ $name = self::decodeComponent( $name );
+ }
+ $list[ $name ] = $value;
+ }
+
+ return $list;
+ }
+
+ /**
+ * @param array $qs
+ * @param string|null $prefix
+ * @param string $separator
+ * @param bool $sort
+ * @return string
+ */
+ public static function buildQueryString(
+ $qs,
+ $prefix = null,
+ $separator = '&',
+ $sort = false
+ ): string {
+ $isIndexed = static function ( array $array ): bool {
+ for ( $i = 0, $max = count( $array ); $i < $max; $i++ ) {
+ if ( ! array_key_exists( $i, $array ) ) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ $f = static function ( array $arr, $prefix = null ) use ( &$f, &$isIndexed ) {
+ $indexed = $prefix !== null && $isIndexed( $arr );
+
+ foreach ( $arr as $key => $value ) {
+ if ( $prefix !== null ) {
+ $key = $prefix . ( $indexed ? '[]' : "[{$key}]" );
+ }
+ if ( is_array( $value ) ) {
+ yield from $f( $value, $key );
+ } else {
+ yield $key => $value;
+ }
+ }
+ };
+
+ $data = array();
+
+ foreach ( $f( $qs, $prefix ) as $key => $value ) {
+ $item = is_string( $key ) ? self::encodeComponent( $key ) : $key;
+ if ( $value !== null ) {
+ $item .= '=';
+ $item .= is_string( $value ) ? self::encodeComponent( $value ) : $value;
+ }
+ if ( $item === '' || $item === '=' ) {
+ continue;
+ }
+ $data[] = $item;
+ }
+
+ if ( ! $data ) {
+ return '';
+ }
+
+ if ( $sort ) {
+ sort( $data );
+ }
+
+ return implode( $separator, $data );
+ }
+
+ /**
+ * @param string $query
+ * @return string
+ */
+ public static function normalizeQueryString( $query ): string {
+ return static::buildQueryString( self::parseQueryString( $query ), null, '&', true );
+ }
+
+ /**
+ * @param string $component
+ */
+ public static function decodeComponent( $component ): string {
+ return rawurldecode( $component );
+ }
+
+ /**
+ * @param string $component
+ * @param mixed[]|null $skip
+ */
+ public static function encodeComponent( $component, $skip = null ): string {
+ if ( ! $skip ) {
+ return rawurlencode( $component );
+ }
+
+ $str = '';
+
+ foreach ( UnicodeString::walkString( $component ) as list($cp, $chars) ) {
+ if ( $cp < 0x80 ) {
+ if ( $cp === 0x2D || $cp === 0x2E ||
+ $cp === 0x5F || $cp === 0x7E ||
+ ( $cp >= 0x41 && $cp <= 0x5A ) ||
+ ( $cp >= 0x61 && $cp <= 0x7A ) ||
+ ( $cp >= 0x30 && $cp <= 0x39 ) ||
+ in_array( $cp, $skip, true )
+ ) {
+ $str .= chr( $cp );
+ } else {
+ $str .= '%' . strtoupper( dechex( $cp ) );
+ }
+ } else {
+ $i = 0;
+ while ( isset( $chars[ $i ] ) ) {
+ $str .= '%' . strtoupper( dechex( $chars[ $i++ ] ) );
+ }
+ }
+ }
+
+ return $str;
+ }
+
+ /**
+ * @param string $scheme
+ * @param int|null $port
+ */
+ public static function setSchemePort( $scheme, $port ) {
+ $scheme = strtolower( $scheme );
+
+ if ( $port === null ) {
+ unset( self::$KNOWN_PORTS[ $scheme ] );
+ } else {
+ self::$KNOWN_PORTS[ $scheme ] = $port;
+ }
+ }
+
+ /**
+ * @param string $scheme
+ */
+ public static function getSchemePort( $scheme ) {
+ return self::$KNOWN_PORTS[ strtolower( $scheme ) ] ?? null;
+ }
+
+ /**
+ * @var mixed[]
+ */
+ protected static $KNOWN_PORTS = array(
+ 'ftp' => 21,
+ 'ssh' => 22,
+ 'telnet' => 23,
+ 'smtp' => 25,
+ 'tftp' => 69,
+ 'http' => 80,
+ 'pop' => 110,
+ 'sftp' => 115,
+ 'imap' => 143,
+ 'irc' => 194,
+ 'ldap' => 389,
+ 'https' => 443,
+ 'ldaps' => 636,
+ 'telnets' => 992,
+ 'imaps' => 993,
+ 'ircs' => 994,
+ 'pops' => 995,
+ );
}
diff --git a/src/opis/uri/src/UriTemplate.php b/src/opis/uri/src/UriTemplate.php
index 3de35d6e..04b896ab 100644
--- a/src/opis/uri/src/UriTemplate.php
+++ b/src/opis/uri/src/UriTemplate.php
@@ -1,5 +1,6 @@
[a-zA-Z0-9\_\%\.]+)(?:(?\*)?|\:(?\d+))?$~';
+class UriTemplate {
- /** @var string */
- const TEMPLATE_REGEX = <<<'REGEX'
+ /** @var string */
+ const TEMPLATE_VARSPEC_REGEX = '~^(?[a-zA-Z0-9\_\%\.]+)(?:(?\*)?|\:(?\d+))?$~';
+
+ /** @var string */
+ const TEMPLATE_REGEX = <<<'REGEX'
~\{
(?[+#./;&=,!@|\?])?
(?
@@ -38,486 +39,472 @@ class UriTemplate
\}~x
REGEX;
- /** @var array */
- const TEMPLATE_TABLE = [
- '' => [
- 'first' => '',
- 'sep' => ',',
- 'named' => false,
- 'ifemp' => '',
- 'allow' => false,
- ],
- '+' => [
- 'first' => '',
- 'sep' => ',',
- 'named' => false,
- 'ifemp' => '',
- 'allow' => true,
- ],
- '.' => [
- 'first' => '.',
- 'sep' => '.',
- 'named' => false,
- 'ifemp' => '',
- 'allow' => false,
- ],
- '/' => [
- 'first' => '/',
- 'sep' => '/',
- 'named' => false,
- 'ifemp' => '',
- 'allow' => false,
- ],
- ';' => [
- 'first' => ';',
- 'sep' => ';',
- 'named' => true,
- 'ifemp' => '',
- 'allow' => false,
- ],
- '?' => [
- 'first' => '?',
- 'sep' => '&',
- 'named' => true,
- 'ifemp' => '=',
- 'allow' => false,
- ],
- '&' => [
- 'first' => '&',
- 'sep' => '&',
- 'named' => true,
- 'ifemp' => '=',
- 'allow' => false,
- ],
- '#' => [
- 'first' => '#',
- 'sep' => ',',
- 'named' => false,
- 'ifemp' => '',
- 'allow' => true,
- ],
- ];
-
- /**
- * @var string
- */
- protected $uri;
-
- /** @var bool|null|array */
- protected $parsed = false;
-
- /**
- * UriTemplate constructor.
- * @param string $uri_template
- */
- public function __construct(string $uri_template)
- {
- $this->uri = $uri_template;
- }
-
- /**
- * @param array $vars
- * @return string
- */
- public function resolve($vars): string
- {
- if ($this->parsed === false) {
- $this->parsed = $this->parse($this->uri);
- }
- if ($this->parsed === null || !$vars) {
- return $this->uri;
- }
-
- $data = '';
- $vars = $this->prepareVars($vars);
-
- foreach ($this->parsed as $item) {
- if (!is_array($item)) {
- $data .= $item;
- continue;
- }
-
- $data .= $this->parseTemplateExpression(
- self::TEMPLATE_TABLE[$item['operator']],
- $this->resolveVars($item['vars'], $vars)
- );
- }
-
- return $data;
- }
-
- /**
- * @return bool
- */
- public function hasPlaceholders(): bool
- {
- if ($this->parsed === false) {
- $this->parse($this->uri);
- }
-
- return $this->parsed !== null;
- }
-
- /**
- * @param string $uri
- * @return array|null
- */
- protected function parse($uri)
- {
- $placeholders = null;
- preg_match_all(self::TEMPLATE_REGEX, $uri, $placeholders, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
-
- if (!$placeholders) {
- return null;
- }
-
- $dataIndex = -1;
- $data = [];
-
- $hasVars = false;
- $nextOffset = 0;
- foreach ($placeholders as &$p) {
- $offset = $p[0][1];
- if ($nextOffset < $offset) {
- $data[] = substr($uri, $nextOffset, $offset - $nextOffset);
- $dataIndex++;
- }
- $matched = $p[0][0];
- $nextOffset = $offset + strlen($matched);
-
- $operator = $p['operator'][0] ?? null;
- if ($operator === null || !isset(self::TEMPLATE_TABLE[$operator])) {
- if ($dataIndex >= 0 && is_string($data[$dataIndex])) {
- $data[$dataIndex] .= $matched;
- } else {
- $data[] = $matched;
- $dataIndex++;
- }
- continue;
- }
-
- $varList = $p['varlist'][0] ?? '';
- $varList = $varList === '' ? [] : explode(',', $varList);
- $p = null;
-
- $varData = [];
-
- foreach ($varList as $var) {
- if (!preg_match(self::TEMPLATE_VARSPEC_REGEX, $var, $spec)) {
- continue;
- }
-
- $varData[] = [
- 'name' => $spec['varname'],
- 'explode' => isset($spec['explode']) && $spec['explode'] === '*',
- 'prefix' => isset($spec['prefix']) ? (int)$spec['prefix'] : 0,
- ];
-
- unset($var, $spec);
- }
-
- if ($varData) {
- $hasVars = true;
- $data[] = [
- 'operator' => $operator,
- 'vars' => $varData,
- ];
- $dataIndex++;
- } else {
- if ($dataIndex >= 0 && is_string($data[$dataIndex])) {
- $data[$dataIndex] .= $matched;
- } else {
- $data[] = $matched;
- $dataIndex++;
- }
- }
-
- unset($varData, $varList, $operator);
- }
-
- if (!$hasVars) {
- return null;
- }
-
- $matched = substr($uri, $nextOffset);
- if ($matched !== false && $matched !== '') {
- if ($dataIndex >= 0 && is_string($data[$dataIndex])) {
- $data[$dataIndex] .= $matched;
- } else {
- $data[] = $matched;
- }
- }
-
- return $data;
- }
-
- /**
- * Convert assoc arrays to objects
- * @param array $vars
- * @return array
- */
- protected function prepareVars($vars): array
- {
- foreach ($vars as &$value) {
- if (is_scalar($value)) {
- if (!is_string($value)) {
- $value = (string)$value;
- }
- continue;
- }
-
- if (!is_array($value)) {
- continue;
- }
-
- $len = count($value);
- for ($i = 0; $i < $len; $i++) {
- if (!array_key_exists($i, $value)) {
- $value = (object)$value;
- break;
- }
- }
- }
-
- return $vars;
- }
-
- /**
- * @param array $vars
- * @param array $data
- * @return array
- */
- protected function resolveVars($vars, $data): array
- {
- $resolved = [];
-
- foreach ($vars as $info) {
- $name = $info['name'];
-
- if (!isset($data[$name])) {
- continue;
- }
-
- $resolved[] = $info + ['value' => &$data[$name]];
- }
-
- return $resolved;
- }
-
- /**
- * @param array $table
- * @param array $data
- * @return string
- */
- protected function parseTemplateExpression($table, $data): string
- {
- $result = [];
- foreach ($data as $var) {
- $str = "";
- if (is_string($var['value'])) {
- if ($table['named']) {
- $str .= $var['name'];
- if ($var['value'] === '') {
- $str .= $table['ifemp'];
- } else {
- $str .= '=';
- }
- }
- if ($var['prefix']) {
- $str .= $this->encodeTemplateString(self::prefix($var['value'], $var['prefix']), $table['allow']);
- } else {
- $str .= $this->encodeTemplateString($var['value'], $table['allow']);
- }
- } elseif ($var['explode']) {
- $list = [];
- if ($table['named']) {
- if (is_array($var['value'])) {
- foreach ($var['value'] as $v) {
- if (is_null($v) || !is_scalar($v)) {
- continue;
- }
- $v = $this->encodeTemplateString((string)$v, $table['allow']);
- if ($v === '') {
- $list[] = $var['name'] . $table['ifemp'];
- } else {
- $list[] = $var['name'] . '=' . $v;
- }
- }
- } elseif (is_object($var['value'])) {
- foreach ($var['value'] as $prop => $v) {
- if (is_null($v) || !is_scalar($v)) {
- continue;
- }
- $v = $this->encodeTemplateString((string)$v, $table['allow']);
- $prop = $this->encodeTemplateString((string)$prop, $table['allow']);
- if ($v === '') {
- $list[] = $prop . $table['ifemp'];
- } else {
- $list[] = $prop . '=' . $v;
- }
- }
- }
- } else {
- if (is_array($var['value'])) {
- foreach ($var['value'] as $v) {
- if (is_null($v) || !is_scalar($v)) {
- continue;
- }
- $list[] = $this->encodeTemplateString($v, $table['allow']);
- }
- } elseif (is_object($var['value'])) {
- foreach ($var['value'] as $prop => $v) {
- if (is_null($v) || !is_scalar($v)) {
- continue;
- }
- $v = $this->encodeTemplateString((string)$v, $table['allow']);
- $prop = $this->encodeTemplateString((string)$prop, $table['allow']);
- $list[] = $prop . '=' . $v;
- }
- }
- }
-
- if ($list) {
- $str .= implode($table['sep'], $list);
- }
- unset($list);
- } else {
- if ($table['named']) {
- $str .= $var['name'];
- if ($var['value'] === '') {
- $str .= $table['ifemp'];
- } else {
- $str .= '=';
- }
- }
- $list = [];
- if (is_array($var['value'])) {
- foreach ($var['value'] as $v) {
- $list[] = $this->encodeTemplateString($v, $table['allow']);
- }
- } elseif (is_object($var['value'])) {
- foreach ($var['value'] as $prop => $v) {
- $list[] = $this->encodeTemplateString((string)$prop, $table['allow']);
- $list[] = $this->encodeTemplateString((string)$v, $table['allow']);
- }
- }
- if ($list) {
- $str .= implode(',', $list);
- }
- unset($list);
- }
-
- if ($str !== '') {
- $result[] = $str;
- }
- }
-
- if (!$result) {
- return '';
- }
-
- $result = implode($table['sep'], $result);
-
- if ($result !== '') {
- $result = $table['first'] . $result;
- }
-
- return $result;
- }
-
- /**
- * @param string $data
- * @param bool $reserved
- * @return string
- */
- protected function encodeTemplateString($data, $reserved): string
- {
- $skip = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~';
-
- if ($reserved) {
- $skip .= ':/?#[]@!$&\'()*+,;=';
- }
-
- $result = '';
- $temp = '';
- for ($i = 0, $len = strlen($data); $i < $len; $i++) {
- if (strpos($skip, $data[$i]) !== false) {
- if ($temp !== '') {
- $result .= Uri::encodeComponent($temp);
- $temp = '';
- }
- $result .= $data[$i];
- continue;
- }
- if ($reserved && $data[$i] === '%') {
- if (isset($data[$i + 1]) && isset($data[$i + 2])
- && strpos('ABCDEF0123456789', $data[$i + 1]) !== false
- && strpos('ABCDEF0123456789', $data[$i + 2]) !== false) {
- if ($temp !== '') {
- $result .= Uri::encodeComponent($temp);
- }
- $result .= '%' . $data[$i + 1] . $data[$i + 2];
- $i += 3;
- continue;
- }
- }
- $temp .= $data[$i];
- }
-
- if ($temp !== '') {
- $result .= Uri::encodeComponent($temp);
- }
-
- return $result;
- }
-
- /**
- * @return string
- */
- public function value(): string
- {
- return $this->uri;
- }
-
- public function __toString(): string
- {
- return $this->uri;
- }
-
- /**
- * @param string $uri
- * @return bool
- */
- public static function isTemplate($uri): bool
- {
- $open = substr_count($uri, '{');
- if ($open === 0) {
- return false;
- }
- $close = substr_count($uri, '}');
- if ($open !== $close) {
- return false;
- }
-
- return (bool)preg_match(self::TEMPLATE_REGEX, $uri);
- }
-
- /**
- * @param string $str
- * @param int $len
- * @return string
- */
- protected static function prefix($str, $len): string
- {
- if ($len === 0) {
- return '';
- }
-
- if ($len >= strlen($str)) {
- // Prefix is longer than string length
- return $str;
- }
-
- return (string)UnicodeString::from($str)->substring(0, $len);
- }
+ /** @var array */
+ const TEMPLATE_TABLE = array(
+ '' => array(
+ 'first' => '',
+ 'sep' => ',',
+ 'named' => false,
+ 'ifemp' => '',
+ 'allow' => false,
+ ),
+ '+' => array(
+ 'first' => '',
+ 'sep' => ',',
+ 'named' => false,
+ 'ifemp' => '',
+ 'allow' => true,
+ ),
+ '.' => array(
+ 'first' => '.',
+ 'sep' => '.',
+ 'named' => false,
+ 'ifemp' => '',
+ 'allow' => false,
+ ),
+ '/' => array(
+ 'first' => '/',
+ 'sep' => '/',
+ 'named' => false,
+ 'ifemp' => '',
+ 'allow' => false,
+ ),
+ ';' => array(
+ 'first' => ';',
+ 'sep' => ';',
+ 'named' => true,
+ 'ifemp' => '',
+ 'allow' => false,
+ ),
+ '?' => array(
+ 'first' => '?',
+ 'sep' => '&',
+ 'named' => true,
+ 'ifemp' => '=',
+ 'allow' => false,
+ ),
+ '&' => array(
+ 'first' => '&',
+ 'sep' => '&',
+ 'named' => true,
+ 'ifemp' => '=',
+ 'allow' => false,
+ ),
+ '#' => array(
+ 'first' => '#',
+ 'sep' => ',',
+ 'named' => false,
+ 'ifemp' => '',
+ 'allow' => true,
+ ),
+ );
+
+ /**
+ * @var string
+ */
+ protected $uri;
+
+ /** @var bool|null|array */
+ protected $parsed = false;
+
+ /**
+ * UriTemplate constructor.
+ *
+ * @param string $uri_template
+ */
+ public function __construct( string $uri_template ) {
+ $this->uri = $uri_template;
+ }
+
+ /**
+ * @param array $vars
+ * @return string
+ */
+ public function resolve( $vars ): string {
+ if ( $this->parsed === false ) {
+ $this->parsed = $this->parse( $this->uri );
+ }
+ if ( $this->parsed === null || ! $vars ) {
+ return $this->uri;
+ }
+
+ $data = '';
+ $vars = $this->prepareVars( $vars );
+
+ foreach ( $this->parsed as $item ) {
+ if ( ! is_array( $item ) ) {
+ $data .= $item;
+ continue;
+ }
+
+ $data .= $this->parseTemplateExpression(
+ self::TEMPLATE_TABLE[ $item['operator'] ],
+ $this->resolveVars( $item['vars'], $vars )
+ );
+ }
+
+ return $data;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasPlaceholders(): bool {
+ if ( $this->parsed === false ) {
+ $this->parse( $this->uri );
+ }
+
+ return $this->parsed !== null;
+ }
+
+ /**
+ * @param string $uri
+ * @return array|null
+ */
+ protected function parse( $uri ) {
+ $placeholders = null;
+ preg_match_all( self::TEMPLATE_REGEX, $uri, $placeholders, PREG_SET_ORDER | PREG_OFFSET_CAPTURE );
+
+ if ( ! $placeholders ) {
+ return null;
+ }
+
+ $dataIndex = -1;
+ $data = array();
+
+ $hasVars = false;
+ $nextOffset = 0;
+ foreach ( $placeholders as &$p ) {
+ $offset = $p[0][1];
+ if ( $nextOffset < $offset ) {
+ $data[] = substr( $uri, $nextOffset, $offset - $nextOffset );
+ ++$dataIndex;
+ }
+ $matched = $p[0][0];
+ $nextOffset = $offset + strlen( $matched );
+
+ $operator = $p['operator'][0] ?? null;
+ if ( $operator === null || ! isset( self::TEMPLATE_TABLE[ $operator ] ) ) {
+ if ( $dataIndex >= 0 && is_string( $data[ $dataIndex ] ) ) {
+ $data[ $dataIndex ] .= $matched;
+ } else {
+ $data[] = $matched;
+ ++$dataIndex;
+ }
+ continue;
+ }
+
+ $varList = $p['varlist'][0] ?? '';
+ $varList = $varList === '' ? array() : explode( ',', $varList );
+ $p = null;
+
+ $varData = array();
+
+ foreach ( $varList as $var ) {
+ if ( ! preg_match( self::TEMPLATE_VARSPEC_REGEX, $var, $spec ) ) {
+ continue;
+ }
+
+ $varData[] = array(
+ 'name' => $spec['varname'],
+ 'explode' => isset( $spec['explode'] ) && $spec['explode'] === '*',
+ 'prefix' => isset( $spec['prefix'] ) ? (int) $spec['prefix'] : 0,
+ );
+
+ unset( $var, $spec );
+ }
+
+ if ( $varData ) {
+ $hasVars = true;
+ $data[] = array(
+ 'operator' => $operator,
+ 'vars' => $varData,
+ );
+ ++$dataIndex;
+ } elseif ( $dataIndex >= 0 && is_string( $data[ $dataIndex ] ) ) {
+ $data[ $dataIndex ] .= $matched;
+ } else {
+ $data[] = $matched;
+ ++$dataIndex;
+ }
+
+ unset( $varData, $varList, $operator );
+ }
+
+ if ( ! $hasVars ) {
+ return null;
+ }
+
+ $matched = substr( $uri, $nextOffset );
+ if ( $matched !== false && $matched !== '' ) {
+ if ( $dataIndex >= 0 && is_string( $data[ $dataIndex ] ) ) {
+ $data[ $dataIndex ] .= $matched;
+ } else {
+ $data[] = $matched;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Convert assoc arrays to objects
+ *
+ * @param array $vars
+ * @return array
+ */
+ protected function prepareVars( $vars ): array {
+ foreach ( $vars as &$value ) {
+ if ( is_scalar( $value ) ) {
+ if ( ! is_string( $value ) ) {
+ $value = (string) $value;
+ }
+ continue;
+ }
+
+ if ( ! is_array( $value ) ) {
+ continue;
+ }
+
+ $len = count( $value );
+ for ( $i = 0; $i < $len; $i++ ) {
+ if ( ! array_key_exists( $i, $value ) ) {
+ $value = (object) $value;
+ break;
+ }
+ }
+ }
+
+ return $vars;
+ }
+
+ /**
+ * @param array $vars
+ * @param array $data
+ * @return array
+ */
+ protected function resolveVars( $vars, $data ): array {
+ $resolved = array();
+
+ foreach ( $vars as $info ) {
+ $name = $info['name'];
+
+ if ( ! isset( $data[ $name ] ) ) {
+ continue;
+ }
+
+ $resolved[] = $info + array( 'value' => &$data[ $name ] );
+ }
+
+ return $resolved;
+ }
+
+ /**
+ * @param array $table
+ * @param array $data
+ * @return string
+ */
+ protected function parseTemplateExpression( $table, $data ): string {
+ $result = array();
+ foreach ( $data as $var ) {
+ $str = '';
+ if ( is_string( $var['value'] ) ) {
+ if ( $table['named'] ) {
+ $str .= $var['name'];
+ if ( $var['value'] === '' ) {
+ $str .= $table['ifemp'];
+ } else {
+ $str .= '=';
+ }
+ }
+ if ( $var['prefix'] ) {
+ $str .= $this->encodeTemplateString( self::prefix( $var['value'], $var['prefix'] ), $table['allow'] );
+ } else {
+ $str .= $this->encodeTemplateString( $var['value'], $table['allow'] );
+ }
+ } elseif ( $var['explode'] ) {
+ $list = array();
+ if ( $table['named'] ) {
+ if ( is_array( $var['value'] ) ) {
+ foreach ( $var['value'] as $v ) {
+ if ( is_null( $v ) || ! is_scalar( $v ) ) {
+ continue;
+ }
+ $v = $this->encodeTemplateString( (string) $v, $table['allow'] );
+ if ( $v === '' ) {
+ $list[] = $var['name'] . $table['ifemp'];
+ } else {
+ $list[] = $var['name'] . '=' . $v;
+ }
+ }
+ } elseif ( is_object( $var['value'] ) ) {
+ foreach ( $var['value'] as $prop => $v ) {
+ if ( is_null( $v ) || ! is_scalar( $v ) ) {
+ continue;
+ }
+ $v = $this->encodeTemplateString( (string) $v, $table['allow'] );
+ $prop = $this->encodeTemplateString( (string) $prop, $table['allow'] );
+ if ( $v === '' ) {
+ $list[] = $prop . $table['ifemp'];
+ } else {
+ $list[] = $prop . '=' . $v;
+ }
+ }
+ }
+ } elseif ( is_array( $var['value'] ) ) {
+ foreach ( $var['value'] as $v ) {
+ if ( is_null( $v ) || ! is_scalar( $v ) ) {
+ continue;
+ }
+ $list[] = $this->encodeTemplateString( $v, $table['allow'] );
+ }
+ } elseif ( is_object( $var['value'] ) ) {
+ foreach ( $var['value'] as $prop => $v ) {
+ if ( is_null( $v ) || ! is_scalar( $v ) ) {
+ continue;
+ }
+ $v = $this->encodeTemplateString( (string) $v, $table['allow'] );
+ $prop = $this->encodeTemplateString( (string) $prop, $table['allow'] );
+ $list[] = $prop . '=' . $v;
+ }
+ }
+
+ if ( $list ) {
+ $str .= implode( $table['sep'], $list );
+ }
+ unset( $list );
+ } else {
+ if ( $table['named'] ) {
+ $str .= $var['name'];
+ if ( $var['value'] === '' ) {
+ $str .= $table['ifemp'];
+ } else {
+ $str .= '=';
+ }
+ }
+ $list = array();
+ if ( is_array( $var['value'] ) ) {
+ foreach ( $var['value'] as $v ) {
+ $list[] = $this->encodeTemplateString( $v, $table['allow'] );
+ }
+ } elseif ( is_object( $var['value'] ) ) {
+ foreach ( $var['value'] as $prop => $v ) {
+ $list[] = $this->encodeTemplateString( (string) $prop, $table['allow'] );
+ $list[] = $this->encodeTemplateString( (string) $v, $table['allow'] );
+ }
+ }
+ if ( $list ) {
+ $str .= implode( ',', $list );
+ }
+ unset( $list );
+ }
+
+ if ( $str !== '' ) {
+ $result[] = $str;
+ }
+ }
+
+ if ( ! $result ) {
+ return '';
+ }
+
+ $result = implode( $table['sep'], $result );
+
+ if ( $result !== '' ) {
+ $result = $table['first'] . $result;
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param string $data
+ * @param bool $reserved
+ * @return string
+ */
+ protected function encodeTemplateString( $data, $reserved ): string {
+ $skip = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~';
+
+ if ( $reserved ) {
+ $skip .= ':/?#[]@!$&\'()*+,;=';
+ }
+
+ $result = '';
+ $temp = '';
+ for ( $i = 0, $len = strlen( $data ); $i < $len; $i++ ) {
+ if ( strpos( $skip, $data[ $i ] ) !== false ) {
+ if ( $temp !== '' ) {
+ $result .= Uri::encodeComponent( $temp );
+ $temp = '';
+ }
+ $result .= $data[ $i ];
+ continue;
+ }
+ if ( $reserved && $data[ $i ] === '%' ) {
+ if ( isset( $data[ $i + 1 ] ) && isset( $data[ $i + 2 ] )
+ && strpos( 'ABCDEF0123456789', $data[ $i + 1 ] ) !== false
+ && strpos( 'ABCDEF0123456789', $data[ $i + 2 ] ) !== false ) {
+ if ( $temp !== '' ) {
+ $result .= Uri::encodeComponent( $temp );
+ }
+ $result .= '%' . $data[ $i + 1 ] . $data[ $i + 2 ];
+ $i += 3;
+ continue;
+ }
+ }
+ $temp .= $data[ $i ];
+ }
+
+ if ( $temp !== '' ) {
+ $result .= Uri::encodeComponent( $temp );
+ }
+
+ return $result;
+ }
+
+ /**
+ * @return string
+ */
+ public function value(): string {
+ return $this->uri;
+ }
+
+ public function __toString(): string {
+ return $this->uri;
+ }
+
+ /**
+ * @param string $uri
+ * @return bool
+ */
+ public static function isTemplate( $uri ): bool {
+ $open = substr_count( $uri, '{' );
+ if ( $open === 0 ) {
+ return false;
+ }
+ $close = substr_count( $uri, '}' );
+ if ( $open !== $close ) {
+ return false;
+ }
+
+ return (bool) preg_match( self::TEMPLATE_REGEX, $uri );
+ }
+
+ /**
+ * @param string $str
+ * @param int $len
+ * @return string
+ */
+ protected static function prefix( $str, $len ): string {
+ if ( $len === 0 ) {
+ return '';
+ }
+
+ if ( $len >= strlen( $str ) ) {
+ // Prefix is longer than string length
+ return $str;
+ }
+
+ return (string) UnicodeString::from( $str )->substring( 0, $len );
+ }
}