allow vendord
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s
This commit is contained in:
19
vendor/rize/uri-template/.php-cs-fixer.dist.php
vendored
Normal file
19
vendor/rize/uri-template/.php-cs-fixer.dist.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PhpCsFixer\Config;
|
||||
use PhpCsFixer\Finder;
|
||||
use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
|
||||
|
||||
return (new Config())
|
||||
->setParallelConfig(ParallelConfigFactory::detect())
|
||||
->setRiskyAllowed(true)
|
||||
->setUsingCache(false)
|
||||
->setRules([
|
||||
'@PER-CS2.0' => true,
|
||||
])
|
||||
->setFinder(
|
||||
(new Finder())
|
||||
->in([__DIR__ . '/src', __DIR__ . '/tests'])
|
||||
);
|
||||
21
vendor/rize/uri-template/LICENSE
vendored
Normal file
21
vendor/rize/uri-template/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) [2014] [Marut Khumtong]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
253
vendor/rize/uri-template/README.md
vendored
Normal file
253
vendor/rize/uri-template/README.md
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
# PHP URI Template
|
||||
|
||||
This is a URI Template implementation in PHP based on [RFC 6570 URI Template](http://tools.ietf.org/html/rfc6570). In addition to URI expansion, it also supports URI extraction (used by [Google Cloud Core](https://github.com/googleapis/google-cloud-php-core) and [Google Cloud Client Library](https://github.com/googleapis/google-cloud-php)).
|
||||
|
||||
 [](https://packagist.org/packages/rize/uri-template) [](https://packagist.org/packages/rize/uri-template) [](https://packagist.org/packages/rize/uri-template)
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> Due to the deprecation of implictly nullable parameter types in [PHP 8.4](https://wiki.php.net/rfc/deprecate-implicitly-nullable-types), we must introduce breaking change by adding explicit nullable types (`?T`) which requires PHP 7.1+.
|
||||
>
|
||||
> As a result, version [0.4.0](https://github.com/rize/UriTemplate/releases/tag/0.4.0) and later will no longer support PHP versions below 8.1.
|
||||
|
||||
## Usage
|
||||
|
||||
### Expansion
|
||||
|
||||
A very simple usage (string expansion).
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Rize\UriTemplate;
|
||||
|
||||
$uri = new UriTemplate();
|
||||
$uri->expand('/{username}/profile', ['username' => 'john']);
|
||||
|
||||
>> '/john/profile'
|
||||
```
|
||||
|
||||
`Rize\UriTemplate` supports all `Expression Types` and `Levels` specified by RFC6570.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Rize\UriTemplate;
|
||||
|
||||
$uri = new UriTemplate();
|
||||
$uri->expand('/search/{term:1}/{term}/{?q*,limit}', [
|
||||
'term' => 'john',
|
||||
'q' => ['a', 'b'],
|
||||
'limit' => 10,
|
||||
])
|
||||
|
||||
>> '/search/j/john/?q=a&q=b&limit=10'
|
||||
```
|
||||
|
||||
#### `/` Path segment expansion
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Rize\UriTemplate;
|
||||
|
||||
$uri = new UriTemplate();
|
||||
$uri->expand('http://{host}{/segments*}/{file}{.extensions*}', [
|
||||
'host' => 'www.host.com',
|
||||
'segments' => ['path', 'to', 'a'],
|
||||
'file' => 'file',
|
||||
'extensions' => ['x', 'y'],
|
||||
]);
|
||||
|
||||
>> 'http://www.host.com/path/to/a/file.x.y'
|
||||
```
|
||||
|
||||
`Rize\UriTemplate` accepts `base-uri` as a 1st argument and `default params` as a 2nd argument. This is very useful when you're working with API endpoint.
|
||||
|
||||
Take a look at real world example.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Rize\UriTemplate;
|
||||
|
||||
$uri = new UriTemplate('https://api.twitter.com/{version}', ['version' => 1.1]);
|
||||
$uri->expand('/statuses/show/{id}.json', ['id' => '210462857140252672']);
|
||||
|
||||
>> https://api.twitter.com/1.1/statuses/show/210462857140252672.json
|
||||
```
|
||||
|
||||
### Extraction
|
||||
|
||||
It also supports URI Extraction (extract all variables from URI). Let's take a look at the example.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Rize\UriTemplate;
|
||||
|
||||
$uri = new UriTemplate('https://api.twitter.com/{version}', ['version' => 1.1]);
|
||||
|
||||
$params = $uri->extract('/search/{term:1}/{term}/{?q*,limit}', '/search/j/john/?q=a&q=b&limit=10');
|
||||
|
||||
>> print_r($params);
|
||||
(
|
||||
[term:1] => j
|
||||
[term] => john
|
||||
[q] => Array
|
||||
(
|
||||
[0] => a
|
||||
[1] => b
|
||||
)
|
||||
|
||||
[limit] => 10
|
||||
)
|
||||
```
|
||||
|
||||
Note that in the example above, result returned by `extract` method has an extra keys named `term:1` for `prefix` modifier. This key was added just for our convenience to access prefix data.
|
||||
|
||||
#### `strict` mode
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Rize\UriTemplate;
|
||||
|
||||
$uri = new UriTemplate();
|
||||
$uri->extract($template, $uri, $strict = false)
|
||||
```
|
||||
|
||||
Normally `extract` method will try to extract vars from a uri even if it's partially matched. For example
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Rize\UriTemplate;
|
||||
|
||||
$uri = new UriTemplate();
|
||||
$params = $uri->extract('/{?a,b}', '/?a=1')
|
||||
|
||||
>> print_r($params);
|
||||
(
|
||||
[a] => 1
|
||||
[b] => null
|
||||
)
|
||||
```
|
||||
|
||||
With `strict mode`, it will allow you to extract uri only when variables in template are fully matched with given uri.
|
||||
|
||||
Which is useful when you want to determine whether the given uri is matched against your template or not (in case you want to use it as routing service).
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Rize\UriTemplate;
|
||||
|
||||
$uri = new UriTemplate();
|
||||
|
||||
// Note that variable `b` is absent in uri
|
||||
$params = $uri->extract('/{?a,b}', '/?a=1', true);
|
||||
|
||||
>>> null
|
||||
|
||||
// Now we give `b` some value
|
||||
$params = $uri->extract('/{?a,b}', '/?a=1&b=2', true);
|
||||
|
||||
>>> print_r($params)
|
||||
(
|
||||
[a] => 1
|
||||
[b] => 2
|
||||
)
|
||||
```
|
||||
|
||||
#### Array modifier `%`
|
||||
|
||||
By default, RFC 6570 only has 2 types of operators `:` and `*`. This `%` array operator was added to the library because current spec can't handle array style query e.g. `list[]=a` or `key[user]=john`.
|
||||
|
||||
Example usage for `%` modifier
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$uri->expand('{?list%,keys%}', [
|
||||
'list' => [
|
||||
'a', 'b',
|
||||
),
|
||||
'keys' => [
|
||||
'a' => 1,
|
||||
'b' => 2,
|
||||
),
|
||||
]);
|
||||
|
||||
// '?list[]=a&list[]=b&keys[a]=1&keys[b]=2'
|
||||
>> '?list%5B%5D=a&list%5B%5D=b&keys%5Ba%5D=1&keys%5Bb%5D=2'
|
||||
|
||||
// [] get encoded to %5B%5D i.e. '?list[]=a&list[]=b&keys[a]=1&keys[b]=2'
|
||||
$params = $uri->extract('{?list%,keys%}', '?list%5B%5D=a&list%5B%5D=b&keys%5Ba%5D=1&keys%5Bb%5D=2', )
|
||||
|
||||
>> print_r($params);
|
||||
(
|
||||
[list] => Array
|
||||
(
|
||||
[0] => a
|
||||
[1] => b
|
||||
)
|
||||
|
||||
[keys] => Array
|
||||
(
|
||||
[a] => 1
|
||||
[b] => 2
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
Using `composer`
|
||||
|
||||
```
|
||||
{
|
||||
"require": {
|
||||
"rize/uri-template": "~0.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Changelogs
|
||||
|
||||
* **0.2.0** Add a new modifier `%` which allows user to use `list[]=a&list[]=b` query pattern.
|
||||
* **0.2.1** Add nested array support for `%` modifier
|
||||
* **0.2.5** Add strict mode support for `extract` method
|
||||
* **0.3.0** Improve code quality + RFC3986 support for `extract` method by @Maks3w
|
||||
* **0.3.1** Improve `extract` method to parse two or more adjacent variables separated by dot by @corleonis
|
||||
* **0.4.0** Fixes the deprecation of implicitly nullable parameter types introduced in PHP 8.4. This version requires PHP 8.1 or later.
|
||||
|
||||
## Contributors
|
||||
|
||||
### Code Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||
<a href="https://github.com/rize/UriTemplate/graphs/contributors"><img src="https://opencollective.com/rize-uri-template/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
### Financial Contributors
|
||||
|
||||
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/rize-uri-template/contribute)]
|
||||
|
||||
#### Individuals
|
||||
|
||||
<a href="https://opencollective.com/rize-uri-template"><img src="https://opencollective.com/rize-uri-template/individuals.svg?width=890"></a>
|
||||
|
||||
#### Organizations
|
||||
|
||||
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/rize-uri-template/contribute)]
|
||||
|
||||
<a href="https://opencollective.com/rize-uri-template/organization/0/website"><img src="https://opencollective.com/rize-uri-template/organization/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/rize-uri-template/organization/1/website"><img src="https://opencollective.com/rize-uri-template/organization/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/rize-uri-template/organization/2/website"><img src="https://opencollective.com/rize-uri-template/organization/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/rize-uri-template/organization/3/website"><img src="https://opencollective.com/rize-uri-template/organization/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/rize-uri-template/organization/4/website"><img src="https://opencollective.com/rize-uri-template/organization/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/rize-uri-template/organization/5/website"><img src="https://opencollective.com/rize-uri-template/organization/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/rize-uri-template/organization/6/website"><img src="https://opencollective.com/rize-uri-template/organization/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/rize-uri-template/organization/7/website"><img src="https://opencollective.com/rize-uri-template/organization/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/rize-uri-template/organization/8/website"><img src="https://opencollective.com/rize-uri-template/organization/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/rize-uri-template/organization/9/website"><img src="https://opencollective.com/rize-uri-template/organization/9/avatar.svg"></a>
|
||||
32
vendor/rize/uri-template/composer.json
vendored
Normal file
32
vendor/rize/uri-template/composer.json
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "rize/uri-template",
|
||||
"type": "library",
|
||||
"description": "PHP URI Template (RFC 6570) supports both expansion & extraction",
|
||||
"keywords": ["URI", "Template", "RFC 6570"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marut K",
|
||||
"homepage": "http://twitter.com/rezigned"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~10.0",
|
||||
"phpstan/phpstan": "^1.12",
|
||||
"friendsofphp/php-cs-fixer": "^3.63"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Rize\\": "src/Rize"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "vendor/bin/phpunit",
|
||||
"cs": "vendor/bin/php-cs-fixer fix --dry-run",
|
||||
"cs-fix": "vendor/bin/php-cs-fixer fix",
|
||||
"phpstan": "vendor/bin/phpstan"
|
||||
}
|
||||
}
|
||||
5
vendor/rize/uri-template/phpstan.neon
vendored
Normal file
5
vendor/rize/uri-template/phpstan.neon
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
parameters:
|
||||
level: 5
|
||||
paths:
|
||||
- src
|
||||
- tests
|
||||
22
vendor/rize/uri-template/phpunit.xml
vendored
Normal file
22
vendor/rize/uri-template/phpunit.xml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
executionOrder="depends,defects"
|
||||
requireCoverageMetadata="false"
|
||||
beStrictAboutCoverageMetadata="false"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true">
|
||||
<testsuites>
|
||||
<testsuite name="default">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<source restrictDeprecations="true" restrictNotices="true" restrictWarnings="true">
|
||||
<include>
|
||||
<directory>src</directory>
|
||||
</include>
|
||||
</source>
|
||||
</phpunit>
|
||||
98
vendor/rize/uri-template/src/Rize/UriTemplate.php
vendored
Normal file
98
vendor/rize/uri-template/src/Rize/UriTemplate.php
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Rize;
|
||||
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
/**
|
||||
* URI Template.
|
||||
*/
|
||||
class UriTemplate
|
||||
{
|
||||
protected Parser $parser;
|
||||
protected array $parsed = [];
|
||||
|
||||
public function __construct(protected string $base_uri = '', protected array $params = [], ?Parser $parser = null)
|
||||
{
|
||||
$this->parser = $parser ?: $this->createNodeParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands URI Template.
|
||||
*
|
||||
* @param mixed $params
|
||||
*/
|
||||
public function expand(string $uri, $params = []): string
|
||||
{
|
||||
$params += $this->params;
|
||||
$uri = $this->base_uri . $uri;
|
||||
$result = [];
|
||||
|
||||
// quick check
|
||||
if (!str_contains($uri, '{')) {
|
||||
return $uri;
|
||||
}
|
||||
|
||||
$parser = $this->parser;
|
||||
$nodes = $parser->parse($uri);
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
$result[] = $node->expand($parser, $params);
|
||||
}
|
||||
|
||||
return implode('', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts variables from URI.
|
||||
*
|
||||
* @return null|array params or null if not match and $strict is true
|
||||
*/
|
||||
public function extract(string $template, string $uri, bool $strict = false): ?array
|
||||
{
|
||||
$params = [];
|
||||
$nodes = $this->parser->parse($template);
|
||||
|
||||
// PHP 8.1.0RC4-dev still throws deprecation warning for `strlen`.
|
||||
// $uri = (string) $uri;
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
// if strict is given, and there's no remaining uri just return null
|
||||
if ($strict && (string) $uri === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// URI will be truncated from the start when a match is found
|
||||
$match = $node->match($this->parser, $uri, $params, $strict);
|
||||
|
||||
if ($match === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
[$uri, $params] = $match;
|
||||
}
|
||||
|
||||
// if there's remaining $uri, matching is failed
|
||||
if ($strict && (string) $uri !== '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
public function getParser(): Parser
|
||||
{
|
||||
return $this->parser;
|
||||
}
|
||||
|
||||
protected function createNodeParser(): Parser
|
||||
{
|
||||
static $parser;
|
||||
|
||||
if ($parser) {
|
||||
return $parser;
|
||||
}
|
||||
|
||||
return $parser = new Parser();
|
||||
}
|
||||
}
|
||||
50
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Abstraction.php
vendored
Normal file
50
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Abstraction.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Node;
|
||||
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
/**
|
||||
* Base class for all Nodes.
|
||||
*/
|
||||
abstract class Abstraction
|
||||
{
|
||||
public function __construct(private readonly string $token) {}
|
||||
|
||||
/**
|
||||
* Expands URI template
|
||||
*
|
||||
* @param array<string, mixed> $params
|
||||
*/
|
||||
public function expand(Parser $parser, array $params = []): ?string
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches given URI against current node.
|
||||
*
|
||||
* @param array<string, mixed> $params
|
||||
*
|
||||
* @return null|array{0: string, 1: array<string, mixed>} `uri and params` or `null` if not match and $strict is true
|
||||
*/
|
||||
public function match(Parser $parser, string $uri, array $params = [], bool $strict = false): ?array
|
||||
{
|
||||
// match literal string from start to end
|
||||
if (str_starts_with($uri, $this->token)) {
|
||||
$uri = substr($uri, strlen($this->token));
|
||||
}
|
||||
|
||||
// when there's no match, just return null if strict mode is given
|
||||
elseif ($strict) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [$uri, $params];
|
||||
}
|
||||
|
||||
public function getToken(): string
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
}
|
||||
124
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Expression.php
vendored
Normal file
124
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Expression.php
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Node;
|
||||
|
||||
use Rize\UriTemplate\Operator;
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
class Expression extends Abstraction
|
||||
{
|
||||
/**
|
||||
* @param string $forwardLookupSeparator
|
||||
*/
|
||||
public function __construct(string $token, private readonly Operator\Abstraction $operator, private readonly ?array $variables = null, /**
|
||||
* Whether to do a forward lookup for a given separator.
|
||||
*/
|
||||
private $forwardLookupSeparator = null)
|
||||
{
|
||||
parent::__construct($token);
|
||||
}
|
||||
|
||||
public function getOperator(): Operator\Abstraction
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
public function getVariables(): ?array
|
||||
{
|
||||
return $this->variables;
|
||||
}
|
||||
|
||||
public function getForwardLookupSeparator(): string
|
||||
{
|
||||
return $this->forwardLookupSeparator;
|
||||
}
|
||||
|
||||
public function setForwardLookupSeparator(string $forwardLookupSeparator): void
|
||||
{
|
||||
$this->forwardLookupSeparator = $forwardLookupSeparator;
|
||||
}
|
||||
|
||||
public function expand(Parser $parser, array $params = []): ?string
|
||||
{
|
||||
$data = [];
|
||||
$op = $this->operator;
|
||||
|
||||
if ($this->variables === null) {
|
||||
return $op->first;
|
||||
}
|
||||
|
||||
// check for variable modifiers
|
||||
foreach ($this->variables as $var) {
|
||||
$val = $op->expand($parser, $var, $params);
|
||||
|
||||
// skip null value
|
||||
if (!is_null($val)) {
|
||||
$data[] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $data ? $op->first . implode($op->sep, $data) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches given URI against current node.
|
||||
*
|
||||
* @return null|array `uri and params` or `null` if not match and $strict is true
|
||||
*/
|
||||
public function match(Parser $parser, string $uri, array $params = [], bool $strict = false): ?array
|
||||
{
|
||||
$op = $this->operator;
|
||||
|
||||
// check expression operator first
|
||||
if ($op->id && isset($uri[0]) && $uri[0] !== $op->id) {
|
||||
return [$uri, $params];
|
||||
}
|
||||
|
||||
// remove operator from input
|
||||
if ($op->id) {
|
||||
$uri = substr($uri, 1);
|
||||
}
|
||||
|
||||
foreach ($this->sortVariables($this->variables) as $var) {
|
||||
$regex = '#' . $op->toRegex($parser, $var) . '#';
|
||||
$val = null;
|
||||
|
||||
// do a forward lookup and get just the relevant part
|
||||
$remainingUri = '';
|
||||
$preparedUri = $uri;
|
||||
if ($this->forwardLookupSeparator) {
|
||||
$lastOccurrenceOfSeparator = stripos($uri, $this->forwardLookupSeparator);
|
||||
$preparedUri = substr($uri, 0, $lastOccurrenceOfSeparator);
|
||||
$remainingUri = substr($uri, $lastOccurrenceOfSeparator);
|
||||
}
|
||||
|
||||
if (preg_match($regex, $preparedUri, $match)) {
|
||||
// remove matched part from input
|
||||
$preparedUri = preg_replace($regex, '', $preparedUri, 1);
|
||||
$val = $op->extract($parser, $var, $match[0]);
|
||||
}
|
||||
|
||||
// if strict is given, we quit immediately when there's no match
|
||||
elseif ($strict) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$uri = $preparedUri . $remainingUri;
|
||||
|
||||
$params[$var->getToken()] = $val;
|
||||
}
|
||||
|
||||
return [$uri, $params];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort variables before extracting data from uri.
|
||||
* We have to sort vars by non-explode to explode.
|
||||
*/
|
||||
protected function sortVariables(array $vars): array
|
||||
{
|
||||
usort($vars, static fn($a, $b) => $a->options['modifier'] <=> $b->options['modifier']);
|
||||
|
||||
return $vars;
|
||||
}
|
||||
}
|
||||
5
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Literal.php
vendored
Normal file
5
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Literal.php
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Node;
|
||||
|
||||
class Literal extends Abstraction {}
|
||||
27
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Variable.php
vendored
Normal file
27
vendor/rize/uri-template/src/Rize/UriTemplate/Node/Variable.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Node;
|
||||
|
||||
class Variable extends Abstraction
|
||||
{
|
||||
/**
|
||||
* Variable name without modifier
|
||||
* e.g. 'term:1' becomes 'term'.
|
||||
*/
|
||||
public string $name;
|
||||
public array $options = ['modifier' => null, 'value' => null];
|
||||
|
||||
public function __construct(string $token, array $options = [])
|
||||
{
|
||||
parent::__construct($token);
|
||||
$this->options = $options + $this->options;
|
||||
|
||||
// normalize var name e.g. from 'term:1' becomes 'term'
|
||||
$name = $token;
|
||||
if ($options['modifier'] === ':') {
|
||||
$name = strstr($name, $options['modifier'], true);
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
373
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/Abstraction.php
vendored
Normal file
373
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/Abstraction.php
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Operator;
|
||||
|
||||
use Rize\UriTemplate\Node;
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
/**
|
||||
* .------------------------------------------------------------------.
|
||||
* | NUL + . / ; ? & # |
|
||||
* |------------------------------------------------------------------|
|
||||
* | first | "" "" "." "/" ";" "?" "&" "#" |
|
||||
* | sep | "," "," "." "/" ";" "&" "&" "," |
|
||||
* | named | false false false false true true true false |
|
||||
* | ifemp | "" "" "" "" "" "=" "=" "" |
|
||||
* | allow | U U+R U U U U U U+R |
|
||||
* `------------------------------------------------------------------'.
|
||||
*
|
||||
* named = false
|
||||
* | 1 | {/list} /red,green,blue | {$value}*(?:,{$value}+)*
|
||||
* | 2 | {/list*} /red/green/blue | {$value}+(?:{$sep}{$value}+)*
|
||||
* | 3 | {/keys} /semi,%3B,dot,.,comma,%2C | /(\w+,?)+
|
||||
* | 4 | {/keys*} /semi=%3B/dot=./comma=%2C | /(?:\w+=\w+/?)*
|
||||
* named = true
|
||||
* | 1 | {?list} ?list=red,green,blue | {name}=(?:\w+(?:,\w+?)*)*
|
||||
* | 2 | {?list*} ?list=red&list=green&list=blue | {name}+=(?:{$value}+(?:{sep}{name}+={$value}*))*
|
||||
* | 3 | {?keys} ?keys=semi,%3B,dot,.,comma,%2C | (same as 1)
|
||||
* | 4 | {?keys*} ?semi=%3B&dot=.&comma=%2C | (same as 2)
|
||||
*
|
||||
* UNRESERVED
|
||||
* ----------
|
||||
* RFC 1738 ALPHA | DIGIT | "-" | "." | "_" | | "$" | "+" | "!" | "*" | "'" | "(" | ")" | ","
|
||||
* RFC 3986 ALPHA | DIGIT | "-" | "." | "_" | "~"
|
||||
* RFC 6570 ALPHA | DIGIT | "-" | "." | "_" | "~"
|
||||
*
|
||||
* RESERVED
|
||||
* --------
|
||||
* RFC 1738 ":" | "/" | "?" | | "@" | "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "=" | "-" | "_" | "." |
|
||||
* RFC 3986 ":" | "/" | "?" | "#" | "[" | "]" | "@" | "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "="
|
||||
* RFC 6570 ":" | "/" | "?" | "#" | "[" | "]" | "@" | "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "="
|
||||
*
|
||||
* PHP_QUERY_RFC3986 was added in PHP 5.4.0
|
||||
*/
|
||||
abstract class Abstraction
|
||||
{
|
||||
/**
|
||||
* start - Variable offset position, level-2 operators start at 1
|
||||
* (exclude operator itself, e.g. {?query})
|
||||
* first - If variables found, prepend this value to it
|
||||
* named - Whether the expansion includes the variable or key name
|
||||
* reserved - union of (unreserved / reserved / pct-encoded).
|
||||
*/
|
||||
public $id;
|
||||
public $named;
|
||||
public $sep;
|
||||
public $empty;
|
||||
public $reserved;
|
||||
public $start;
|
||||
public $first;
|
||||
|
||||
/**
|
||||
* gen-delims | sub-delims.
|
||||
*/
|
||||
public static $reserved_chars = [
|
||||
'%3A' => ':',
|
||||
'%2F' => '/',
|
||||
'%3F' => '?',
|
||||
'%23' => '#',
|
||||
'%5B' => '[',
|
||||
'%5D' => ']',
|
||||
'%40' => '@',
|
||||
'%21' => '!',
|
||||
'%24' => '$',
|
||||
'%26' => '&',
|
||||
'%27' => "'",
|
||||
'%28' => '(',
|
||||
'%29' => ')',
|
||||
'%2A' => '*',
|
||||
'%2B' => '+',
|
||||
'%2C' => ',',
|
||||
'%3B' => ';',
|
||||
'%3D' => '=',
|
||||
];
|
||||
|
||||
protected static $types = [
|
||||
'' => [
|
||||
'sep' => ',',
|
||||
'named' => false,
|
||||
'empty' => '',
|
||||
'reserved' => false,
|
||||
'start' => 0,
|
||||
'first' => null,
|
||||
],
|
||||
'+' => [
|
||||
'sep' => ',',
|
||||
'named' => false,
|
||||
'empty' => '',
|
||||
'reserved' => true,
|
||||
'start' => 1,
|
||||
'first' => null,
|
||||
],
|
||||
'.' => [
|
||||
'sep' => '.',
|
||||
'named' => false,
|
||||
'empty' => '',
|
||||
'reserved' => false,
|
||||
'start' => 1,
|
||||
'first' => '.',
|
||||
],
|
||||
'/' => [
|
||||
'sep' => '/',
|
||||
'named' => false,
|
||||
'empty' => '',
|
||||
'reserved' => false,
|
||||
'start' => 1,
|
||||
'first' => '/',
|
||||
],
|
||||
';' => [
|
||||
'sep' => ';',
|
||||
'named' => true,
|
||||
'empty' => '',
|
||||
'reserved' => false,
|
||||
'start' => 1,
|
||||
'first' => ';',
|
||||
],
|
||||
'?' => [
|
||||
'sep' => '&',
|
||||
'named' => true,
|
||||
'empty' => '=',
|
||||
'reserved' => false,
|
||||
'start' => 1,
|
||||
'first' => '?',
|
||||
],
|
||||
'&' => [
|
||||
'sep' => '&',
|
||||
'named' => true,
|
||||
'empty' => '=',
|
||||
'reserved' => false,
|
||||
'start' => 1,
|
||||
'first' => '&',
|
||||
],
|
||||
'#' => [
|
||||
'sep' => ',',
|
||||
'named' => false,
|
||||
'empty' => '',
|
||||
'reserved' => true,
|
||||
'start' => 1,
|
||||
'first' => '#',
|
||||
],
|
||||
];
|
||||
|
||||
protected static $loaded = [];
|
||||
|
||||
/**
|
||||
* RFC 3986 Allowed path characters regex except the path delimiter '/'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $pathRegex = '(?:[a-zA-Z0-9\-\._~!\$&\'\(\)\*\+,;=%:@]+|%(?![A-Fa-f0-9]{2}))';
|
||||
|
||||
/**
|
||||
* RFC 3986 Allowed query characters regex except the query parameter delimiter '&'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $queryRegex = '(?:[a-zA-Z0-9\-\._~!\$\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))';
|
||||
|
||||
public function __construct($id, $named, $sep, $empty, $reserved, $start, $first)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->named = $named;
|
||||
$this->sep = $sep;
|
||||
$this->empty = $empty;
|
||||
$this->start = $start;
|
||||
$this->first = $first;
|
||||
$this->reserved = $reserved;
|
||||
}
|
||||
|
||||
abstract public function toRegex(Parser $parser, Node\Variable $var): string;
|
||||
|
||||
public function expand(Parser $parser, Node\Variable $var, array $params = [])
|
||||
{
|
||||
$options = $var->options;
|
||||
$name = $var->name;
|
||||
$is_explode = in_array($options['modifier'], ['*', '%']);
|
||||
|
||||
// skip null
|
||||
if (!isset($params[$name])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$val = $params[$name];
|
||||
|
||||
// This algorithm is based on RFC6570 http://tools.ietf.org/html/rfc6570
|
||||
// non-array, e.g. string
|
||||
if (!is_array($val)) {
|
||||
return $this->expandString($parser, $var, $val);
|
||||
}
|
||||
|
||||
// non-explode ':'
|
||||
if (!$is_explode) {
|
||||
return $this->expandNonExplode($parser, $var, $val);
|
||||
}
|
||||
|
||||
// explode '*', '%'
|
||||
|
||||
return $this->expandExplode($parser, $var, $val);
|
||||
}
|
||||
|
||||
public function expandString(Parser $parser, Node\Variable $var, $val)
|
||||
{
|
||||
$val = (string) $val;
|
||||
$options = $var->options;
|
||||
$result = null;
|
||||
|
||||
if ($options['modifier'] === ':') {
|
||||
$val = substr($val, 0, (int) $options['value']);
|
||||
}
|
||||
|
||||
return $result . $this->encode($parser, $var, $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Non explode modifier ':'.
|
||||
*/
|
||||
public function expandNonExplode(Parser $parser, Node\Variable $var, array $val): ?string
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->encode($parser, $var, $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode modifier '*', '%'.
|
||||
*/
|
||||
public function expandExplode(Parser $parser, Node\Variable $var, array $val): ?string
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->encode($parser, $var, $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes variable according to spec (reserved or unreserved).
|
||||
*
|
||||
* @return string encoded string
|
||||
*/
|
||||
public function encode(Parser $parser, Node\Variable $var, mixed $values)
|
||||
{
|
||||
$values = (array) $values;
|
||||
$list = isset($values[0]);
|
||||
$reserved = $this->reserved;
|
||||
$maps = static::$reserved_chars;
|
||||
$sep = $this->sep;
|
||||
$assoc_sep = '=';
|
||||
|
||||
// non-explode modifier always use ',' as a separator
|
||||
if ($var->options['modifier'] !== '*') {
|
||||
$assoc_sep = $sep = ',';
|
||||
}
|
||||
|
||||
array_walk($values, function (&$v, $k) use ($assoc_sep, $reserved, $list, $maps): void {
|
||||
$encoded = rawurlencode($v);
|
||||
|
||||
// assoc? encode key too
|
||||
if (!$list) {
|
||||
$encoded = rawurlencode($k) . $assoc_sep . $encoded;
|
||||
}
|
||||
|
||||
// rawurlencode is compliant with 'unreserved' set
|
||||
if (!$reserved) {
|
||||
$v = $encoded;
|
||||
}
|
||||
|
||||
// decode chars in reserved set
|
||||
else {
|
||||
$v = str_replace(
|
||||
array_keys($maps),
|
||||
$maps,
|
||||
$encoded,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return implode($sep, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes variable.
|
||||
*
|
||||
* @return string decoded string
|
||||
*/
|
||||
public function decode(Parser $parser, Node\Variable $var, mixed $values)
|
||||
{
|
||||
$single = !is_array($values);
|
||||
$values = (array) $values;
|
||||
|
||||
array_walk($values, function (&$v, $k): void {
|
||||
$v = rawurldecode($v);
|
||||
});
|
||||
|
||||
return $single ? reset($values) : $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts value from variable.
|
||||
*/
|
||||
public function extract(Parser $parser, Node\Variable $var, string $data): array|string
|
||||
{
|
||||
$value = $data;
|
||||
$vals = array_filter(explode($this->sep, $data));
|
||||
$options = $var->options;
|
||||
|
||||
switch ($options['modifier']) {
|
||||
case '*':
|
||||
$value = [];
|
||||
foreach ($vals as $val) {
|
||||
if (str_contains($val, '=')) {
|
||||
[$k, $v] = explode('=', $val);
|
||||
$value[$k] = $v;
|
||||
} else {
|
||||
$value[] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ':':
|
||||
break;
|
||||
|
||||
default:
|
||||
$value = str_contains($value, (string) $this->sep) ? $vals : $value;
|
||||
}
|
||||
|
||||
return $this->decode($parser, $var, $value);
|
||||
}
|
||||
|
||||
public static function createById($id)
|
||||
{
|
||||
if (!isset(static::$types[$id])) {
|
||||
throw new \InvalidArgumentException("Invalid operator [{$id}]");
|
||||
}
|
||||
|
||||
if (isset(static::$loaded[$id])) {
|
||||
return static::$loaded[$id];
|
||||
}
|
||||
|
||||
$op = static::$types[$id];
|
||||
$class = __NAMESPACE__ . '\\' . ($op['named'] ? 'Named' : 'UnNamed');
|
||||
|
||||
return static::$loaded[$id] = new $class($id, $op['named'], $op['sep'], $op['empty'], $op['reserved'], $op['start'], $op['first']);
|
||||
}
|
||||
|
||||
public static function isValid($id): bool
|
||||
{
|
||||
return isset(static::$types[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correct regex given the variable location in the URI.
|
||||
*/
|
||||
protected function getRegex(): string
|
||||
{
|
||||
return match ($this->id) {
|
||||
'?', '&', '#' => self::$queryRegex,
|
||||
default => self::$pathRegex,
|
||||
};
|
||||
}
|
||||
}
|
||||
202
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/Named.php
vendored
Normal file
202
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/Named.php
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Operator;
|
||||
|
||||
use Rize\UriTemplate\Node;
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
/**
|
||||
* | 1 | {?list} ?list=red,green,blue | {name}=(?:\w+(?:,\w+?)*)*
|
||||
* | 2 | {?list*} ?list=red&list=green&list=blue | {name}+=(?:{$value}+(?:{sep}{name}+={$value}*))*
|
||||
* | 3 | {?keys} ?keys=semi,%3B,dot,.,comma,%2C | (same as 1)
|
||||
* | 4 | {?keys*} ?semi=%3B&dot=.&comma=%2C | (same as 2)
|
||||
* | 5 | {?list*} ?list[]=red&list[]=green&list[]=blue | {name[]}+=(?:{$value}+(?:{sep}{name[]}+={$value}*))*.
|
||||
*/
|
||||
class Named extends Abstraction
|
||||
{
|
||||
public function toRegex(Parser $parser, Node\Variable $var): string
|
||||
{
|
||||
$name = $var->name;
|
||||
$value = $this->getRegex();
|
||||
$options = $var->options;
|
||||
|
||||
if ($options['modifier']) {
|
||||
switch ($options['modifier']) {
|
||||
case '*':
|
||||
// 2 | 4
|
||||
$regex = "{$name}+=(?:{$value}+(?:{$this->sep}{$name}+={$value}*)*)"
|
||||
. "|{$value}+=(?:{$value}+(?:{$this->sep}{$value}+={$value}*)*)";
|
||||
|
||||
break;
|
||||
|
||||
case ':':
|
||||
$regex = "{$value}\\{0,{$options['value']}\\}";
|
||||
|
||||
break;
|
||||
|
||||
case '%':
|
||||
// 5
|
||||
$name .= '+(?:%5B|\[)[^=]*=';
|
||||
$regex = "{$name}(?:{$value}+(?:{$this->sep}{$name}{$value}*)*)";
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException("Unknown modifier `{$options['modifier']}`");
|
||||
}
|
||||
} else {
|
||||
// 1, 3
|
||||
$regex = "{$name}=(?:{$value}+(?:,{$value}+)*)*";
|
||||
}
|
||||
|
||||
return '(?:&)?' . $regex;
|
||||
}
|
||||
|
||||
public function expandString(Parser $parser, Node\Variable $var, $val): string
|
||||
{
|
||||
$val = (string) $val;
|
||||
$options = $var->options;
|
||||
$result = $this->encode($parser, $var, $var->name);
|
||||
|
||||
// handle empty value
|
||||
if ($val === '') {
|
||||
return $result . $this->empty;
|
||||
}
|
||||
|
||||
$result .= '=';
|
||||
|
||||
if ($options['modifier'] === ':') {
|
||||
$val = mb_substr($val, 0, (int) $options['value']);
|
||||
}
|
||||
|
||||
return $result . $this->encode($parser, $var, $val);
|
||||
}
|
||||
|
||||
public function expandNonExplode(Parser $parser, Node\Variable $var, array $val): ?string
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = $this->encode($parser, $var, $var->name);
|
||||
|
||||
$result .= '=';
|
||||
|
||||
return $result . $this->encode($parser, $var, $val);
|
||||
}
|
||||
|
||||
public function expandExplode(Parser $parser, Node\Variable $var, array $val): ?string
|
||||
{
|
||||
if (empty($val)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$list = isset($val[0]);
|
||||
$data = [];
|
||||
foreach ($val as $k => $v) {
|
||||
// if value is a list, use `varname` as keyname, otherwise use `key` name
|
||||
$key = $list ? $var->name : $k;
|
||||
if ($list) {
|
||||
$data[$key][] = $v;
|
||||
} else {
|
||||
$data[$key] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's array modifier, we have to use variable name as index
|
||||
// e.g. if variable name is 'query' and value is ['limit' => 1]
|
||||
// then we convert it to ['query' => ['limit' => 1]]
|
||||
if (!$list && $var->options['modifier'] === '%') {
|
||||
$data = [$var->name => $data];
|
||||
}
|
||||
|
||||
return $this->encodeExplodeVars($var, $data);
|
||||
}
|
||||
|
||||
public function extract(Parser $parser, Node\Variable $var, $data): array|string
|
||||
{
|
||||
// get rid of optional `&` at the beginning
|
||||
if ($data[0] === '&') {
|
||||
$data = substr($data, 1);
|
||||
}
|
||||
|
||||
$value = $data;
|
||||
$vals = explode($this->sep, $data);
|
||||
$options = $var->options;
|
||||
|
||||
switch ($options['modifier']) {
|
||||
case '%':
|
||||
parse_str($value, $query);
|
||||
|
||||
return $query[$var->name];
|
||||
|
||||
case '*':
|
||||
$value = [];
|
||||
|
||||
foreach ($vals as $val) {
|
||||
[$k, $v] = explode('=', $val);
|
||||
|
||||
// 2
|
||||
if ($k === $var->getToken()) {
|
||||
$value[] = $v;
|
||||
}
|
||||
|
||||
// 4
|
||||
else {
|
||||
$value[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ':':
|
||||
break;
|
||||
|
||||
default:
|
||||
// 1, 3
|
||||
// remove key from value e.g. 'lang=en,th' becomes 'en,th'
|
||||
$value = str_replace($var->getToken() . '=', '', $value);
|
||||
$value = explode(',', $value);
|
||||
|
||||
if (count($value) === 1) {
|
||||
$value = current($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->decode($parser, $var, $value);
|
||||
}
|
||||
|
||||
public function encodeExplodeVars(Node\Variable $var, $data): null|array|string
|
||||
{
|
||||
// http_build_query uses PHP_QUERY_RFC1738 encoding by default
|
||||
// i.e. spaces are encoded as '+' (plus signs) we need to convert
|
||||
// it to %20 RFC3986
|
||||
$query = http_build_query($data, '', $this->sep);
|
||||
$query = str_replace('+', '%20', $query);
|
||||
|
||||
// `%` array modifier
|
||||
if ($var->options['modifier'] === '%') {
|
||||
|
||||
// it also uses numeric based-index by default e.g. list[] becomes list[0]
|
||||
$query = preg_replace('#%5B\d+%5D#', '%5B%5D', $query);
|
||||
}
|
||||
|
||||
// `:`, `*` modifiers
|
||||
else {
|
||||
// by default, http_build_query will convert array values to `a[]=1&a[]=2`
|
||||
// which is different from the spec. It should be `a=1&a=2`
|
||||
$query = preg_replace('#%5B\d+%5D#', '', $query);
|
||||
}
|
||||
|
||||
// handle reserved charset
|
||||
if ($this->reserved) {
|
||||
$query = str_replace(
|
||||
array_keys(static::$reserved_chars),
|
||||
static::$reserved_chars,
|
||||
$query,
|
||||
);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
47
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/UnNamed.php
vendored
Normal file
47
vendor/rize/uri-template/src/Rize/UriTemplate/Operator/UnNamed.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate\Operator;
|
||||
|
||||
use Rize\UriTemplate\Node;
|
||||
use Rize\UriTemplate\Parser;
|
||||
|
||||
/**
|
||||
* | 1 | {/list} /red,green,blue | {$value}*(?:,{$value}+)*
|
||||
* | 2 | {/list*} /red/green/blue | {$value}+(?:{$sep}{$value}+)*
|
||||
* | 3 | {/keys} /semi,%3B,dot,.,comma,%2C | /(\w+,?)+
|
||||
* | 4 | {/keys*} /semi=%3B/dot=./comma=%2C | /(?:\w+=\w+/?)*.
|
||||
*/
|
||||
class UnNamed extends Abstraction
|
||||
{
|
||||
public function toRegex(Parser $parser, Node\Variable $var): string
|
||||
{
|
||||
$value = $this->getRegex();
|
||||
$options = $var->options;
|
||||
|
||||
if ($options['modifier']) {
|
||||
switch ($options['modifier']) {
|
||||
case '*':
|
||||
// 2 | 4
|
||||
$regex = "{$value}+(?:{$this->sep}{$value}+)*";
|
||||
|
||||
break;
|
||||
|
||||
case ':':
|
||||
$regex = $value . '{0,' . $options['value'] . '}';
|
||||
|
||||
break;
|
||||
|
||||
case '%':
|
||||
throw new \InvalidArgumentException('% (array) modifier only works with Named type operators e.g. ;,?,&');
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException("Unknown modifier `{$options['modifier']}`");
|
||||
}
|
||||
} else {
|
||||
// 1, 3
|
||||
$regex = "{$value}*(?:,{$value}+)*";
|
||||
}
|
||||
|
||||
return $regex;
|
||||
}
|
||||
}
|
||||
149
vendor/rize/uri-template/src/Rize/UriTemplate/Parser.php
vendored
Normal file
149
vendor/rize/uri-template/src/Rize/UriTemplate/Parser.php
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate;
|
||||
|
||||
use Rize\UriTemplate\Node\Abstraction;
|
||||
use Rize\UriTemplate\Node\Expression;
|
||||
use Rize\UriTemplate\Node\Variable;
|
||||
use Rize\UriTemplate\Operator\UnNamed;
|
||||
|
||||
class Parser
|
||||
{
|
||||
private const REGEX_VARNAME = '[A-z0-9.]|%[0-9a-fA-F]{2}';
|
||||
|
||||
/**
|
||||
* Parses URI Template and returns nodes.
|
||||
*
|
||||
* @return Node\Abstraction[]
|
||||
*/
|
||||
public function parse(string $template): array
|
||||
{
|
||||
$parts = preg_split('#(\{[^}]+})#', $template, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
|
||||
$nodes = [];
|
||||
|
||||
foreach ($parts as $part) {
|
||||
$node = $this->createNode($part);
|
||||
|
||||
// if current node has dot separator that requires a forward lookup
|
||||
// for the previous node iff previous node's operator is UnNamed
|
||||
if ($node instanceof Expression && $node->getOperator()->id === '.') {
|
||||
if (count($nodes) > 0) {
|
||||
$previousNode = $nodes[count($nodes) - 1];
|
||||
if ($previousNode instanceof Expression && $previousNode->getOperator() instanceof UnNamed) {
|
||||
$previousNode->setForwardLookupSeparator($node->getOperator()->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$nodes[] = $node;
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
protected function createNode(string $token): Abstraction
|
||||
{
|
||||
// literal string
|
||||
if ($token[0] !== '{') {
|
||||
$node = $this->createLiteralNode($token);
|
||||
} else {
|
||||
// remove `{}` from expression and parse it
|
||||
$node = $this->parseExpression(substr($token, 1, -1));
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
protected function parseExpression(string $expression): Expression
|
||||
{
|
||||
$token = $expression;
|
||||
$prefix = $token[0];
|
||||
|
||||
// not a valid operator?
|
||||
if (!Operator\Abstraction::isValid($prefix)) {
|
||||
// not valid chars?
|
||||
if (!preg_match('#' . self::REGEX_VARNAME . '#', $token)) {
|
||||
throw new \InvalidArgumentException("Invalid operator [{$prefix}] found at {$token}");
|
||||
}
|
||||
|
||||
// default operator
|
||||
//
|
||||
// PHP 8.5: using null as array offset is deprecated and we no longer rely on auto-casting null to ''.
|
||||
$prefix = '';
|
||||
}
|
||||
|
||||
// remove operator prefix if exists e.g. '?'
|
||||
if ($prefix) {
|
||||
$token = substr($token, 1);
|
||||
}
|
||||
|
||||
// parse variables
|
||||
$vars = [];
|
||||
foreach (explode(',', $token) as $var) {
|
||||
$vars[] = $this->parseVariable($var);
|
||||
}
|
||||
|
||||
return $this->createExpressionNode(
|
||||
$token,
|
||||
$this->createOperatorNode($prefix),
|
||||
$vars,
|
||||
);
|
||||
}
|
||||
|
||||
protected function parseVariable(string $var): Variable
|
||||
{
|
||||
$var = trim($var);
|
||||
$val = null;
|
||||
$modifier = null;
|
||||
|
||||
// check for prefix (:) / explode (*) / array (%) modifier
|
||||
if (str_contains($var, ':')) {
|
||||
$modifier = ':';
|
||||
[$varname, $val] = explode(':', $var);
|
||||
|
||||
// error checking
|
||||
if (!is_numeric($val)) {
|
||||
throw new \InvalidArgumentException("Value for `:` modifier must be numeric value [{$varname}:{$val}]");
|
||||
}
|
||||
}
|
||||
|
||||
switch ($last = substr($var, -1)) {
|
||||
case '*':
|
||||
case '%':
|
||||
// there can be only 1 modifier per var
|
||||
if ($modifier) {
|
||||
throw new \InvalidArgumentException("Multiple modifiers per variable are not allowed [{$var}]");
|
||||
}
|
||||
|
||||
$modifier = $last;
|
||||
$var = substr($var, 0, -1);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->createVariableNode(
|
||||
$var,
|
||||
['modifier' => $modifier, 'value' => $val],
|
||||
);
|
||||
}
|
||||
|
||||
protected function createVariableNode($token, $options = []): Variable
|
||||
{
|
||||
return new Variable($token, $options);
|
||||
}
|
||||
|
||||
protected function createExpressionNode($token, ?Operator\Abstraction $operator = null, array $vars = []): Expression
|
||||
{
|
||||
return new Expression($token, $operator, $vars);
|
||||
}
|
||||
|
||||
protected function createLiteralNode(string $token): Node\Literal
|
||||
{
|
||||
return new Node\Literal($token);
|
||||
}
|
||||
|
||||
protected function createOperatorNode($token): Operator\Abstraction
|
||||
{
|
||||
return Operator\Abstraction::createById($token);
|
||||
}
|
||||
}
|
||||
10
vendor/rize/uri-template/src/Rize/UriTemplate/UriTemplate.php
vendored
Normal file
10
vendor/rize/uri-template/src/Rize/UriTemplate/UriTemplate.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Rize\UriTemplate;
|
||||
|
||||
use Rize\UriTemplate as Template;
|
||||
|
||||
/**
|
||||
* Future compatibility.
|
||||
*/
|
||||
class UriTemplate extends Template {}
|
||||
93
vendor/rize/uri-template/tests/Rize/Uri/Node/ParserTest.php
vendored
Normal file
93
vendor/rize/uri-template/tests/Rize/Uri/Node/ParserTest.php
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\Attributes\Depends;
|
||||
use Rize\UriTemplate;
|
||||
use Rize\UriTemplate\Node;
|
||||
use Rize\UriTemplate\Operator;
|
||||
use Rize\UriTemplate\Parser;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ParserTest extends TestCase
|
||||
{
|
||||
protected function service()
|
||||
{
|
||||
return new Parser();
|
||||
}
|
||||
|
||||
public function testParseTemplate()
|
||||
{
|
||||
$input = 'http://www.example.com/{term:1}/{term}/{test*}/foo{?query,number}';
|
||||
$expected = [new Node\Literal('http://www.example.com/'), new Node\Expression(
|
||||
'term:1',
|
||||
Operator\Abstraction::createById(''),
|
||||
[new Node\Variable(
|
||||
'term:1',
|
||||
['modifier' => ':', 'value' => 1],
|
||||
)],
|
||||
), new Node\Literal('/'), new Node\Expression(
|
||||
'term',
|
||||
Operator\Abstraction::createById(''),
|
||||
[new Node\Variable(
|
||||
'term',
|
||||
['modifier' => null, 'value' => null],
|
||||
)],
|
||||
), new Node\Literal('/'), new Node\Expression(
|
||||
'test*',
|
||||
Operator\Abstraction::createById(''),
|
||||
[new Node\Variable(
|
||||
'test',
|
||||
['modifier' => '*', 'value' => null],
|
||||
)],
|
||||
), new Node\Literal('/foo'), new Node\Expression(
|
||||
'query,number',
|
||||
Operator\Abstraction::createById('?'),
|
||||
[new Node\Variable(
|
||||
'query',
|
||||
['modifier' => null, 'value' => null],
|
||||
), new Node\Variable(
|
||||
'number',
|
||||
['modifier' => null, 'value' => null],
|
||||
)],
|
||||
)];
|
||||
|
||||
$service = $this->service();
|
||||
$actual = $service->parse($input);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
public function testParseTemplateWithLiteral()
|
||||
{
|
||||
// will pass
|
||||
$uri = new UriTemplate('http://www.example.com/v1/company/', []);
|
||||
$params = $uri->extract('/{countryCode}/{registrationNumber}/test{.format}', '/gb/0123456/test.json');
|
||||
static::assertEquals(['countryCode' => 'gb', 'registrationNumber' => '0123456', 'format' => 'json'], $params);
|
||||
}
|
||||
|
||||
#[Depends('testParseTemplateWithLiteral')]
|
||||
public function testParseTemplateWithTwoVariablesAndDotBetween()
|
||||
{
|
||||
// will fail
|
||||
$uri = new UriTemplate('http://www.example.com/v1/company/', []);
|
||||
$params = $uri->extract('/{countryCode}/{registrationNumber}{.format}', '/gb/0123456.json');
|
||||
static::assertEquals(['countryCode' => 'gb', 'registrationNumber' => '0123456', 'format' => 'json'], $params);
|
||||
}
|
||||
|
||||
#[Depends('testParseTemplateWithLiteral')]
|
||||
public function testParseTemplateWithTwoVariablesAndDotBetweenStrict()
|
||||
{
|
||||
// will fail
|
||||
$uri = new UriTemplate('http://www.example.com/v1/company/', []);
|
||||
$params = $uri->extract('/{countryCode}/{registrationNumber}{.format}', '/gb/0123456.json', true);
|
||||
static::assertEquals(['countryCode' => 'gb', 'registrationNumber' => '0123456', 'format' => 'json'], $params);
|
||||
}
|
||||
|
||||
#[Depends('testParseTemplateWithLiteral')]
|
||||
public function testParseTemplateWithThreeVariablesAndDotBetweenStrict()
|
||||
{
|
||||
// will fail
|
||||
$uri = new UriTemplate('http://www.example.com/v1/company/', []);
|
||||
$params = $uri->extract('/{countryCode}/{registrationNumber}{.namespace}{.format}', '/gb/0123456.company.json');
|
||||
static::assertEquals(['countryCode' => 'gb', 'registrationNumber' => '0123456', 'namespace' => 'company', 'format' => 'json'], $params);
|
||||
}
|
||||
}
|
||||
253
vendor/rize/uri-template/tests/Rize/UriTemplateTest.php
vendored
Normal file
253
vendor/rize/uri-template/tests/Rize/UriTemplateTest.php
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Metadata\Covers;
|
||||
use Rize\UriTemplate\UriTemplate;
|
||||
|
||||
/**
|
||||
* URI Template
|
||||
*
|
||||
* http://tools.ietf.org/html/rfc6570
|
||||
*/
|
||||
class UriTemplateTest extends TestCase
|
||||
{
|
||||
public function service($uri = '', $params = [])
|
||||
{
|
||||
return new UriTemplate($uri, $params);
|
||||
}
|
||||
|
||||
public static function dataExpansion()
|
||||
{
|
||||
$params = ['count' => ["one", "two", "three"], 'dom' => ["example", "com"], 'dub' => "me/too", 'hello' => "Hello World!", 'half' => "50%", 'var' => "value", 'who' => "fred", 'base' => "http://example.com/home/", 'path' => "/foo/bar", 'list' => ["red", "green", "blue"], 'keys' => ["semi" => ";", "dot" => ".", "comma" => ","], 'list_with_empty' => [''], 'keys_with_empty' => ['john' => ''], 'v' => "6", 'x' => "1024", 'y' => "768", 'empty' => "", 'empty_keys' => [], 'undef' => null];
|
||||
|
||||
return [
|
||||
['http://example.com/~john', ['uri' => 'http://example.com/~{username}', 'params' => ['username' => 'john']]],
|
||||
['http://example.com/dictionary/d/dog', ['uri' => 'http://example.com/dictionary/{term:1}/{term}', 'params' => ['term' => 'dog'], 'extract' => ['term:1' => 'd', 'term' => 'dog']]],
|
||||
# Form-style parameters expression
|
||||
['http://example.com/j/john/search?q=mycelium&q=3&lang=th,jp,en', ['uri' => 'http://example.com/{term:1}/{term}/search{?q*,lang}', 'params' => ['q' => ['mycelium', 3], 'lang' => ['th', 'jp', 'en'], 'term' => 'john']]],
|
||||
['http://www.example.com/john', ['uri' => 'http://www.example.com/{username}', 'params' => ['username' => 'john']]],
|
||||
['http://www.example.com/foo?query=mycelium&number=100', ['uri' => 'http://www.example.com/foo{?query,number}', 'params' => ['query' => 'mycelium', 'number' => 100]]],
|
||||
# 'query' is undefined
|
||||
['http://www.example.com/foo?number=100', [
|
||||
'uri' => 'http://www.example.com/foo{?query,number}',
|
||||
'params' => ['number' => 100],
|
||||
# we can't extract undefined values
|
||||
'extract' => false,
|
||||
]],
|
||||
# undefined variables
|
||||
['http://www.example.com/foo', ['uri' => 'http://www.example.com/foo{?query,number}', 'params' => [], 'extract' => ['query' => null, 'number' => null]]],
|
||||
['http://www.example.com/foo', ['uri' => 'http://www.example.com/foo{?number}', 'params' => [], 'extract' => ['number' => null]]],
|
||||
['one,two,three|one,two,three|/one,two,three|/one/two/three|;count=one,two,three|;count=one;count=two;count=three|?count=one,two,three|?count=one&count=two&count=three|&count=one&count=two&count=three', ['uri' => '{count}|{count*}|{/count}|{/count*}|{;count}|{;count*}|{?count}|{?count*}|{&count*}', 'params' => ['count' => ['one', 'two', 'three']]]],
|
||||
['http://www.host.com/path/to/a/file.x.y', ['uri' => 'http://{host}{/segments*}/{file}{.extensions*}', 'params' => ['host' => 'www.host.com', 'segments' => ['path', 'to', 'a'], 'file' => 'file', 'extensions' => ['x', 'y']], 'extract' => ['host' => 'www.host.com', 'segments' => ['path', 'to', 'a'], 'file' => 'file.x.y', 'extensions' => null]]],
|
||||
# level 1 - Simple String Expansion: {var}
|
||||
['value|Hello%20World%21|50%25|OX|OX|1024,768|1024,Hello%20World%21,768|?1024,|?1024|?768|val|value|red,green,blue|semi,%3B,dot,.,comma,%2C|semi=%3B,dot=.,comma=%2C', ['uri' => '{var}|{hello}|{half}|O{empty}X|O{undef}X|{x,y}|{x,hello,y}|?{x,empty}|?{x,undef}|?{undef,y}|{var:3}|{var:30}|{list}|{keys}|{keys*}', 'params' => $params]],
|
||||
# level 2 - Reserved Expansion: {+var}
|
||||
['value|Hello%20World!|50%25|http%3A%2F%2Fexample.com%2Fhome%2Findex|http://example.com/home/index|OX|OX|/foo/bar/here|here?ref=/foo/bar|up/foo/barvalue/here|1024,Hello%20World!,768|/foo/bar,1024/here|/foo/b/here|red,green,blue|red,green,blue|semi,;,dot,.,comma,,|semi=;,dot=.,comma=,', ['uri' => '{+var}|{+hello}|{+half}|{base}index|{+base}index|O{+empty}X|O{+undef}X|{+path}/here|here?ref={+path}|up{+path}{var}/here|{+x,hello,y}|{+path,x}/here|{+path:6}/here|{+list}|{+list*}|{+keys}|{+keys*}', 'params' => $params]],
|
||||
# level 2 - Fragment Expansion: {#var}
|
||||
['#value|#Hello%20World!|#50%25|foo#|foo|#1024,Hello%20World!,768|#/foo/bar,1024/here|#/foo/b/here|#red,green,blue|#red,green,blue|#semi,;,dot,.,comma,,|#semi=;,dot=.,comma=,', ['uri' => '{#var}|{#hello}|{#half}|foo{#empty}|foo{#undef}|{#x,hello,y}|{#path,x}/here|{#path:6}/here|{#list}|{#list*}|{#keys}|{#keys*}', 'params' => $params]],
|
||||
# Label Expansion with Dot-Prefix: {.var}
|
||||
['.fred|.fred.fred|.50%25.fred|www.example.com|X.value|X.|X|X.val|X.red,green,blue|X.red.green.blue|X.semi,%3B,dot,.,comma,%2C|X.semi=%3B.dot=..comma=%2C|X|X', ['uri' => '{.who}|{.who,who}|{.half,who}|www{.dom*}|X{.var}|X{.empty}|X{.undef}|X{.var:3}|X{.list}|X{.list*}|X{.keys}|X{.keys*}|X{.empty_keys}|X{.empty_keys*}', 'params' => $params]],
|
||||
# Path Segment Expansion: {/var}
|
||||
['/fred|/fred/fred|/50%25/fred|/fred/me%2Ftoo|/value|/value/|/value|/value/1024/here|/v/value|/red,green,blue|/red/green/blue|/red/green/blue/%2Ffoo|/semi,%3B,dot,.,comma,%2C|/semi=%3B/dot=./comma=%2C', ['uri' => '{/who}|{/who,who}|{/half,who}|{/who,dub}|{/var}|{/var,empty}|{/var,undef}|{/var,x}/here|{/var:1,var}|{/list}|{/list*}|{/list*,path:4}|{/keys}|{/keys*}', 'params' => $params]],
|
||||
# Path-Style Parameter Expansion: {;var}
|
||||
[';who=fred|;half=50%25|;empty|;v=6;empty;who=fred|;v=6;who=fred|;x=1024;y=768|;x=1024;y=768;empty|;x=1024;y=768|;hello=Hello|;list=red,green,blue|;list=red;list=green;list=blue|;keys=semi,%3B,dot,.,comma,%2C|;semi=%3B;dot=.;comma=%2C', ['uri' => '{;who}|{;half}|{;empty}|{;v,empty,who}|{;v,bar,who}|{;x,y}|{;x,y,empty}|{;x,y,undef}|{;hello:5}|{;list}|{;list*}|{;keys}|{;keys*}', 'params' => $params]],
|
||||
# Form-Style Query Expansion: {?var}
|
||||
['?who=fred|?half=50%25|?x=1024&y=768|?x=1024&y=768&empty=|?x=1024&y=768|?var=val|?list=red,green,blue|?list=red&list=green&list=blue|?keys=semi,%3B,dot,.,comma,%2C|?semi=%3B&dot=.&comma=%2C|?list_with_empty=|?john=', ['uri' => '{?who}|{?half}|{?x,y}|{?x,y,empty}|{?x,y,undef}|{?var:3}|{?list}|{?list*}|{?keys}|{?keys*}|{?list_with_empty*}|{?keys_with_empty*}', 'params' => $params]],
|
||||
# Form-Style Query Continuation: {&var}
|
||||
['&who=fred|&half=50%25|?fixed=yes&x=1024|&x=1024&y=768&empty=|&x=1024&y=768|&var=val|&list=red,green,blue|&list=red&list=green&list=blue|&keys=semi,%3B,dot,.,comma,%2C|&semi=%3B&dot=.&comma=%2C', ['uri' => '{&who}|{&half}|?fixed=yes{&x}|{&x,y,empty}|{&x,y,undef}|{&var:3}|{&list}|{&list*}|{&keys}|{&keys*}', 'params' => $params]],
|
||||
# Test empty values
|
||||
['|||', ['uri' => '{empty}|{empty*}|{?empty}|{?empty*}', 'params' => ['empty' => []]]],
|
||||
];
|
||||
}
|
||||
|
||||
public static function dataExpandWithArrayModifier()
|
||||
{
|
||||
return [
|
||||
# List
|
||||
[
|
||||
# '?choices[]=a&choices[]=b&choices[]=c',
|
||||
'?choices%5B%5D=a&choices%5B%5D=b&choices%5B%5D=c',
|
||||
['uri' => '{?choices%}', 'params' => ['choices' => ['a', 'b', 'c']]],
|
||||
],
|
||||
# Keys
|
||||
[
|
||||
# '?choices[a]=1&choices[b]=2&choices[c][test]=3',
|
||||
'?choices%5Ba%5D=1&choices%5Bb%5D=2&choices%5Bc%5D%5Btest%5D=3',
|
||||
['uri' => '{?choices%}', 'params' => ['choices' => ['a' => 1, 'b' => 2, 'c' => ['test' => 3]]]],
|
||||
],
|
||||
# Mixed
|
||||
[
|
||||
# '?list[]=a&list[]=b&keys[a]=1&keys[b]=2',
|
||||
'?list%5B%5D=a&list%5B%5D=b&keys%5Ba%5D=1&keys%5Bb%5D=2',
|
||||
['uri' => '{?list%,keys%}', 'params' => ['list' => ['a', 'b'], 'keys' => ['a' => 1, 'b' => 2]]],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public static function dataBaseTemplate()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'http://google.com/api/1/users/1',
|
||||
# base uri
|
||||
['uri' => '{+host}/api/{v}', 'params' => ['host' => 'http://google.com', 'v' => 1]],
|
||||
# other uri
|
||||
['uri' => '/{resource}/{id}', 'params' => ['resource' => 'users', 'id' => 1]],
|
||||
],
|
||||
# test override base params
|
||||
[
|
||||
'http://github.com/api/1/users/1',
|
||||
# base uri
|
||||
['uri' => '{+host}/api/{v}', 'params' => ['host' => 'http://google.com', 'v' => 1]],
|
||||
# other uri
|
||||
['uri' => '/{resource}/{id}', 'params' => ['host' => 'http://github.com', 'resource' => 'users', 'id' => 1]],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public static function dataExtraction()
|
||||
{
|
||||
return [['/no/{term:1}/random/foo{?query,list%,keys%}', '/no/j/random/foo?query=1,2,3&list%5B%5D=a&list%5B%5D=b&keys%5Ba%5D=1&keys%5Bb%5D=2&keys%5Bc%5D%5Btest%5D%5Btest%5D=1', ['term:1' => 'j', 'query' => [1, 2, 3], 'list' => ['a', 'b'], 'keys' => ['a' => 1, 'b' => 2, 'c' => ['test' => ['test' => 1]]]]], ['/no/{term:1}/random/{term}/{test*}/foo{?query,number}', '/no/j/random/john/a,b,c/foo?query=1,2,3&number=10', ['term:1' => 'j', 'term' => 'john', 'test' => ['a', 'b', 'c'], 'query' => [1, 2, 3], 'number' => 10]], ['/search/{term:1}/{term}/{?q*,limit}', '/search/j/john/?a=1&b=2&limit=10', ['term:1' => 'j', 'term' => 'john', 'q' => ['a' => 1, 'b' => 2], 'limit' => 10]], ['http://www.example.com/foo{?query,number}', 'http://www.example.com/foo?query=5', ['query' => 5, 'number' => null]], ['{count}|{count*}|{/count}|{/count*}|{;count}|{;count*}|{?count}|{?count*}|{&count*}', 'one,two,three|one,two,three|/one,two,three|/one/two/three|;count=one,two,three|;count=one;count=two;count=three|?count=one,two,three|?count=one&count=two&count=three|&count=one&count=two&count=three', ['count' => ['one', 'two', 'three']]], ['http://example.com/{term:1}/{term}/search{?q*,lang}', 'http://example.com/j/john/search?q=Hello%20World%21&q=3&lang=th,jp,en', ['q' => ['Hello World!', 3], 'lang' => ['th', 'jp', 'en'], 'term' => 'john', 'term:1' => 'j']], ['/foo/bar/{number}', '/foo/bar/0', ['number' => 0]], ['/some/{path}{?ref}', '/some/foo', ['path' => 'foo', 'ref' => null]]];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataExpansion
|
||||
*/
|
||||
public function testExpansion($expected, $input)
|
||||
{
|
||||
$service = $this->service();
|
||||
$result = $service->expand($input['uri'], $input['params']);
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataExpandWithArrayModifier
|
||||
*/
|
||||
public function testExpandWithArrayModifier($expected, $input)
|
||||
{
|
||||
$service = $this->service();
|
||||
$result = $service->expand($input['uri'], $input['params']);
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataBaseTemplate
|
||||
*/
|
||||
public function testBaseTemplate($expected, $base, $other)
|
||||
{
|
||||
$service = $this->service($base['uri'], $base['params']);
|
||||
$result = $service->expand($other['uri'], $other['params']);
|
||||
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataExtraction
|
||||
*/
|
||||
public function testExtract($template, $uri, $expected)
|
||||
{
|
||||
$service = $this->service();
|
||||
$actual = $service->extract($template, $uri);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
public function testExpandFromFixture()
|
||||
{
|
||||
$dir = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR;
|
||||
$files = ['spec-examples.json', 'spec-examples-by-section.json', 'extended-tests.json'];
|
||||
$service = $this->service();
|
||||
|
||||
foreach ($files as $file) {
|
||||
$content = json_decode(file_get_contents($dir . $file), $array = true);
|
||||
|
||||
# iterate through each fixture
|
||||
foreach ($content as $fixture) {
|
||||
$vars = $fixture['variables'];
|
||||
|
||||
# assert each test cases
|
||||
foreach ($fixture['testcases'] as $case) {
|
||||
[$uri, $expected] = $case;
|
||||
|
||||
$actual = $service->expand($uri, $vars);
|
||||
|
||||
if (is_array($expected)) {
|
||||
$expected = current(array_filter($expected, fn($input) => $actual === $input));
|
||||
}
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function dataExtractStrictMode()
|
||||
{
|
||||
$dataTest = [['/search/{term:1}/{term}/{?q*,limit}', '/search/j/john/?a=1&b=2&limit=10', ['term:1' => 'j', 'term' => 'john', 'limit' => '10', 'q' => ['a' => '1', 'b' => '2']]], ['http://example.com/{term:1}/{term}/search{?q*,lang}', 'http://example.com/j/john/search?q=Hello%20World%21&q=3&lang=th,jp,en', ['term:1' => 'j', 'term' => 'john', 'lang' => ['th', 'jp', 'en'], 'q' => ['Hello World!', '3']]], ['/foo/bar/{number}', '/foo/bar/0', ['number' => 0]], ['/', '/', []]];
|
||||
|
||||
$rfc3986AllowedPathCharacters = ['-', '.', '_', '~', '!', '$', '&', "'", '(', ')', '*', '+', ',', ';', '=', ':', '@'];
|
||||
|
||||
foreach ($rfc3986AllowedPathCharacters as $char) {
|
||||
$title = "RFC3986 path character ($char)";
|
||||
$title = str_replace("'", 'single quote', $title); // PhpStorm workaround
|
||||
if ($char === ',') { // , means array on RFC6570
|
||||
$params = ['term' => ['foo', 'baz']];
|
||||
} else {
|
||||
$params = ['term' => "foo{$char}baz"];
|
||||
}
|
||||
|
||||
$data = ['/search/{term}', "/search/foo{$char}baz", $params];
|
||||
|
||||
$dataTest[$title] = $data;
|
||||
$data = ['/search/{;term}', "/search/;term=foo{$char}baz", $params];
|
||||
$dataTest['Named ' . $title] = $data;
|
||||
}
|
||||
|
||||
$rfc3986AllowedQueryCharacters = $rfc3986AllowedPathCharacters;
|
||||
$rfc3986AllowedQueryCharacters[] = '/';
|
||||
$rfc3986AllowedQueryCharacters[] = '?';
|
||||
unset($rfc3986AllowedQueryCharacters[array_search('&', $rfc3986AllowedQueryCharacters, true)]);
|
||||
|
||||
foreach ($rfc3986AllowedQueryCharacters as $char) {
|
||||
$title = "RFC3986 query character ($char)";
|
||||
$title = str_replace("'", 'single quote', $title); // PhpStorm workaround
|
||||
if ($char === ',') { // , means array on RFC6570
|
||||
$params = ['term' => ['foo', 'baz']];
|
||||
} else {
|
||||
$params = ['term' => "foo{$char}baz"];
|
||||
}
|
||||
|
||||
$data = ['/search/{?term}', "/search/?term=foo{$char}baz", $params];
|
||||
$dataTest['Named ' . $title] = $data;
|
||||
}
|
||||
|
||||
return $dataTest;
|
||||
}
|
||||
|
||||
public static function extractStrictModeNotMatchProvider()
|
||||
{
|
||||
return [['/', '/a'], ['/{test}', '/a/'], ['/search/{term:1}/{term}/{?q*,limit}', '/search/j/?a=1&b=2&limit=10'], ['http://www.example.com/foo{?query,number}', 'http://www.example.com/foo?query=5'], ['http://www.example.com/foo{?query,number}', 'http://www.example.com/foo'], ['http://example.com/{term:1}/{term}/search{?q*,lang}', 'http://example.com/j/john/search?q=']];
|
||||
}
|
||||
|
||||
#[DataProvider('dataExtractStrictMode')]
|
||||
public function testExtractStrictMode(string $template, string $uri, array $expectedParams)
|
||||
{
|
||||
$service = $this->service();
|
||||
$params = $service->extract($template, $uri, true);
|
||||
|
||||
$this->assertTrue(isset($params));
|
||||
$this->assertEquals($expectedParams, $params);
|
||||
}
|
||||
|
||||
#[DataProvider('extractStrictModeNotMatchProvider')]
|
||||
public function testExtractStrictModeNotMatch(string $template, string $uri)
|
||||
{
|
||||
$service = $this->service();
|
||||
$actual = $service->extract($template, $uri, true);
|
||||
|
||||
$this->assertFalse(isset($actual));
|
||||
}
|
||||
}
|
||||
90
vendor/rize/uri-template/tests/fixtures/README.md
vendored
Normal file
90
vendor/rize/uri-template/tests/fixtures/README.md
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
URI Template Tests
|
||||
==================
|
||||
|
||||
This is a set of tests for implementations of
|
||||
[RFC6570](http://tools.ietf.org/html/rfc6570) - URI Template. It is designed
|
||||
to be reused by any implementation, to improve interoperability and
|
||||
implementation quality.
|
||||
|
||||
If your project uses Git for version control, you can make uritemplate-tests into a [submodule](http://help.github.com/submodules/).
|
||||
|
||||
Test Format
|
||||
-----------
|
||||
|
||||
Each test file is a [JSON](http://tools.ietf.org/html/RFC6627) document
|
||||
containing an object whose properties are groups of related tests.
|
||||
Alternatively, all tests are available in XML as well, with the XML files
|
||||
being generated by transform-json-tests.xslt which uses json2xml.xslt as a
|
||||
general-purpose JSON-to-XML parsing library.
|
||||
|
||||
Each group, in turn, is an object with three children:
|
||||
|
||||
* level - the level of the tests covered, as per the RFC (optional; if absent,
|
||||
assume level 4).
|
||||
* variables - an object representing the variables that are available to the
|
||||
tests in the suite
|
||||
* testcases - a list of testcases, where each case is a two-member list, the
|
||||
first being the template, the second being the result of expanding the
|
||||
template with the provided variables.
|
||||
|
||||
Note that the result string can be a few different things:
|
||||
|
||||
* string - if the second member is a string, the result of expansion is
|
||||
expected to match it, character-for-character.
|
||||
* list - if the second member is a list of strings, the result of expansion
|
||||
is expected to match one of them; this allows for templates that can
|
||||
expand into different, equally-acceptable URIs.
|
||||
* false - if the second member is boolean false, expansion is expected to
|
||||
fail (i.e., the template was invalid).
|
||||
|
||||
For example:
|
||||
|
||||
{
|
||||
"Level 1 Examples" :
|
||||
{
|
||||
"level": 1,
|
||||
"variables": {
|
||||
"var" : "value",
|
||||
"hello" : "Hello World!"
|
||||
},
|
||||
"testcases" : [
|
||||
["{var}", "value"],
|
||||
["{hello}", "Hello%20World%21"]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Tests Included
|
||||
--------------
|
||||
|
||||
The following test files are included:
|
||||
|
||||
* spec-examples.json - The complete set of example templates from the RFC
|
||||
* spec-examples-by-section.json - The examples, section by section
|
||||
* extended-tests.json - more complex test cases
|
||||
* negative-tests.json - invalid templates
|
||||
|
||||
For all these test files, XML versions with the names *.xml can be
|
||||
generated with the transform-json-tests.xslt XSLT stylesheet. The XSLT
|
||||
contains the names of the above test files as a parameter, and can be
|
||||
started with any XML as input (i.e., the XML input is ignored).
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright 2011-2012 The Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
118
vendor/rize/uri-template/tests/fixtures/extended-tests.json
vendored
Normal file
118
vendor/rize/uri-template/tests/fixtures/extended-tests.json
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"Additional Examples 1":{
|
||||
"level":4,
|
||||
"variables":{
|
||||
"id" : "person",
|
||||
"token" : "12345",
|
||||
"fields" : ["id", "name", "picture"],
|
||||
"format" : "json",
|
||||
"q" : "URI Templates",
|
||||
"page" : "5",
|
||||
"lang" : "en",
|
||||
"geocode" : ["37.76","-122.427"],
|
||||
"first_name" : "John",
|
||||
"last.name" : "Doe",
|
||||
"Some%20Thing" : "foo",
|
||||
"number" : 6,
|
||||
"long" : 37.76,
|
||||
"lat" : -122.427,
|
||||
"group_id" : "12345",
|
||||
"query" : "PREFIX dc: <http://purl.org/dc/elements/1.1/> SELECT ?book ?who WHERE { ?book dc:creator ?who }",
|
||||
"uri" : "http://example.org/?uri=http%3A%2F%2Fexample.org%2F",
|
||||
"word" : "drücken",
|
||||
"Stra%C3%9Fe" : "Grüner Weg",
|
||||
"random" : "šö䟜ñꀣ¥‡ÑÒÓÔÕÖרÙÚàáâãäåæçÿ",
|
||||
"assoc_special_chars" :
|
||||
{ "šö䟜ñꀣ¥‡ÑÒÓÔÕ" : "ÖרÙÚàáâãäåæçÿ" }
|
||||
},
|
||||
"testcases":[
|
||||
|
||||
[ "{/id*}" , "/person" ],
|
||||
[ "{/id*}{?fields,first_name,last.name,token}" , [
|
||||
"/person?fields=id,name,picture&first_name=John&last.name=Doe&token=12345",
|
||||
"/person?fields=id,picture,name&first_name=John&last.name=Doe&token=12345",
|
||||
"/person?fields=picture,name,id&first_name=John&last.name=Doe&token=12345",
|
||||
"/person?fields=picture,id,name&first_name=John&last.name=Doe&token=12345",
|
||||
"/person?fields=name,picture,id&first_name=John&last.name=Doe&token=12345",
|
||||
"/person?fields=name,id,picture&first_name=John&last.name=Doe&token=12345"]
|
||||
],
|
||||
["/search.{format}{?q,geocode,lang,locale,page,result_type}",
|
||||
[ "/search.json?q=URI%20Templates&geocode=37.76,-122.427&lang=en&page=5",
|
||||
"/search.json?q=URI%20Templates&geocode=-122.427,37.76&lang=en&page=5"]
|
||||
],
|
||||
["/test{/Some%20Thing}", "/test/foo" ],
|
||||
["/set{?number}", "/set?number=6"],
|
||||
["/loc{?long,lat}" , "/loc?long=37.76&lat=-122.427"],
|
||||
["/base{/group_id,first_name}/pages{/page,lang}{?format,q}","/base/12345/John/pages/5/en?format=json&q=URI%20Templates"],
|
||||
["/sparql{?query}", "/sparql?query=PREFIX%20dc%3A%20%3Chttp%3A%2F%2Fpurl.org%2Fdc%2Felements%2F1.1%2F%3E%20SELECT%20%3Fbook%20%3Fwho%20WHERE%20%7B%20%3Fbook%20dc%3Acreator%20%3Fwho%20%7D"],
|
||||
["/go{?uri}", "/go?uri=http%3A%2F%2Fexample.org%2F%3Furi%3Dhttp%253A%252F%252Fexample.org%252F"],
|
||||
["/service{?word}", "/service?word=dr%C3%BCcken"],
|
||||
["/lookup{?Stra%C3%9Fe}", "/lookup?Stra%25C3%259Fe=Gr%C3%BCner%20Weg"],
|
||||
["{random}" , "%C5%A1%C3%B6%C3%A4%C5%B8%C5%93%C3%B1%C3%AA%E2%82%AC%C2%A3%C2%A5%E2%80%A1%C3%91%C3%92%C3%93%C3%94%C3%95%C3%96%C3%97%C3%98%C3%99%C3%9A%C3%A0%C3%A1%C3%A2%C3%A3%C3%A4%C3%A5%C3%A6%C3%A7%C3%BF"],
|
||||
["{?assoc_special_chars*}", "?%C5%A1%C3%B6%C3%A4%C5%B8%C5%93%C3%B1%C3%AA%E2%82%AC%C2%A3%C2%A5%E2%80%A1%C3%91%C3%92%C3%93%C3%94%C3%95=%C3%96%C3%97%C3%98%C3%99%C3%9A%C3%A0%C3%A1%C3%A2%C3%A3%C3%A4%C3%A5%C3%A6%C3%A7%C3%BF"]
|
||||
]
|
||||
},
|
||||
"Additional Examples 2":{
|
||||
"level":4,
|
||||
"variables":{
|
||||
"id" : ["person","albums"],
|
||||
"token" : "12345",
|
||||
"fields" : ["id", "name", "picture"],
|
||||
"format" : "atom",
|
||||
"q" : "URI Templates",
|
||||
"page" : "10",
|
||||
"start" : "5",
|
||||
"lang" : "en",
|
||||
"geocode" : ["37.76","-122.427"]
|
||||
},
|
||||
"testcases":[
|
||||
|
||||
[ "{/id*}" , ["/person/albums","/albums/person"] ],
|
||||
[ "{/id*}{?fields,token}" , [
|
||||
"/person/albums?fields=id,name,picture&token=12345",
|
||||
"/person/albums?fields=id,picture,name&token=12345",
|
||||
"/person/albums?fields=picture,name,id&token=12345",
|
||||
"/person/albums?fields=picture,id,name&token=12345",
|
||||
"/person/albums?fields=name,picture,id&token=12345",
|
||||
"/person/albums?fields=name,id,picture&token=12345",
|
||||
"/albums/person?fields=id,name,picture&token=12345",
|
||||
"/albums/person?fields=id,picture,name&token=12345",
|
||||
"/albums/person?fields=picture,name,id&token=12345",
|
||||
"/albums/person?fields=picture,id,name&token=12345",
|
||||
"/albums/person?fields=name,picture,id&token=12345",
|
||||
"/albums/person?fields=name,id,picture&token=12345"]
|
||||
]
|
||||
]
|
||||
},
|
||||
"Additional Examples 3: Empty Variables":{
|
||||
"variables" : {
|
||||
"empty_list" : [],
|
||||
"empty_assoc" : {}
|
||||
},
|
||||
"testcases":[
|
||||
[ "{/empty_list}", [ "" ] ],
|
||||
[ "{/empty_list*}", [ "" ] ],
|
||||
[ "{?empty_list}", [ ""] ],
|
||||
[ "{?empty_list*}", [ "" ] ],
|
||||
[ "{?empty_assoc}", [ "" ] ],
|
||||
[ "{?empty_assoc*}", [ "" ] ]
|
||||
]
|
||||
},
|
||||
"Additional Examples 4: Numeric Keys":{
|
||||
"variables" : {
|
||||
"42" : "The Answer to the Ultimate Question of Life, the Universe, and Everything",
|
||||
"1337" : ["leet", "as","it", "can","be"],
|
||||
"german" : {
|
||||
"11": "elf",
|
||||
"12": "zwölf"
|
||||
}
|
||||
},
|
||||
"testcases":[
|
||||
[ "{42}", "The%20Answer%20to%20the%20Ultimate%20Question%20of%20Life%2C%20the%20Universe%2C%20and%20Everything"],
|
||||
[ "{?42}", "?42=The%20Answer%20to%20the%20Ultimate%20Question%20of%20Life%2C%20the%20Universe%2C%20and%20Everything"],
|
||||
[ "{1337}", "leet,as,it,can,be"],
|
||||
[ "{?1337*}", "?1337=leet&1337=as&1337=it&1337=can&1337=be"],
|
||||
[ "{?german*}", [ "?11=elf&12=zw%C3%B6lf", "?12=zw%C3%B6lf&11=elf"] ]
|
||||
]
|
||||
}
|
||||
}
|
||||
201
vendor/rize/uri-template/tests/fixtures/json2xml.xslt
vendored
Normal file
201
vendor/rize/uri-template/tests/fixtures/json2xml.xslt
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Downloaded on 12/6/2012 from http://www.gerixsoft.com/blog/xslt/json2xml -->
|
||||
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
|
||||
<xsl:template match="json">
|
||||
<xsl:copy>
|
||||
<xsl:copy-of select="@*"/>
|
||||
<xsl:call-template name="json2xml">
|
||||
<xsl:with-param name="text" select="."/>
|
||||
</xsl:call-template>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="json2xml">
|
||||
<xsl:param name="text"/>
|
||||
<xsl:variable name="mode0">
|
||||
<xsl:variable name="regexps" select="'//(.*?)\n', '/\*(.*?)\*/', '(''|")(([^\\]|\\[\\"''/btnvfr])*?)\3', '(-?\d+(\.\d+([eE][+-]?\d+)?|[eE][+-]?\d+))', '(-?[1-9]\d*)', '(-?0[0-7]+)', '(-?0x[0-9a-fA-F]+)', '([:,\{\}\[\]])', '(true|false)', '(null)'"/>
|
||||
<xsl:analyze-string select="$text" regex="{string-join($regexps,'|')}" flags="s">
|
||||
<xsl:matching-substring>
|
||||
<xsl:choose>
|
||||
<!-- single line comment -->
|
||||
<xsl:when test="regex-group(1)">
|
||||
<xsl:comment>
|
||||
<xsl:value-of select="regex-group(1)"/>
|
||||
</xsl:comment>
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:when>
|
||||
<!-- multi line comment -->
|
||||
<xsl:when test="regex-group(2)">
|
||||
<xsl:comment>
|
||||
<xsl:value-of select="regex-group(2)"/>
|
||||
</xsl:comment>
|
||||
</xsl:when>
|
||||
<!-- string -->
|
||||
<xsl:when test="regex-group(3)">
|
||||
<string>
|
||||
<xsl:analyze-string select="regex-group(4)" regex="\\([\\"'/btnvfr])" flags="s">
|
||||
<xsl:matching-substring>
|
||||
<xsl:variable name="s" select="regex-group(1)"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$s=('\', '"', '''', '/')">
|
||||
<xsl:value-of select="regex-group(1)"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="$s='b'">
|
||||
<!--xsl:text></xsl:text-->
|
||||
<xsl:message select="'escape sequense \b is not supported by XML'"/>
|
||||
<xsl:text>\b</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$s='t'">
|
||||
<xsl:text>	</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$s='n'">
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$s='v'">
|
||||
<!--xsl:text></xsl:text-->
|
||||
<xsl:message select="'escape sequence \v is not supported by XML'"/>
|
||||
<xsl:text>\v</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$s='f'">
|
||||
<!--xsl:text></xsl:text-->
|
||||
<xsl:message select="'escape sequence \f is not supported by XML'"/>
|
||||
<xsl:text>\f</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="$s='r'">
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:message terminate="yes" select="'internal error'"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:matching-substring>
|
||||
<xsl:non-matching-substring>
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:non-matching-substring>
|
||||
</xsl:analyze-string>
|
||||
</string>
|
||||
</xsl:when>
|
||||
<!-- double -->
|
||||
<xsl:when test="regex-group(6)">
|
||||
<double>
|
||||
<xsl:value-of select="regex-group(6)"/>
|
||||
</double>
|
||||
</xsl:when>
|
||||
<!-- integer -->
|
||||
<xsl:when test="regex-group(9)">
|
||||
<integer>
|
||||
<xsl:value-of select="regex-group(9)"/>
|
||||
</integer>
|
||||
</xsl:when>
|
||||
<!-- octal -->
|
||||
<xsl:when test="regex-group(10)">
|
||||
<integer>
|
||||
<xsl:value-of xmlns:Integer="java:java.lang.Integer" select="Integer:parseInt(regex-group(10), 8)"/>
|
||||
</integer>
|
||||
</xsl:when>
|
||||
<!-- hex -->
|
||||
<xsl:when test="regex-group(11)">
|
||||
<integer>
|
||||
<xsl:value-of xmlns:Integer="java:java.lang.Integer" select="Integer:parseInt(replace(regex-group(11), '0x', ''), 16)"/>
|
||||
</integer>
|
||||
</xsl:when>
|
||||
<!-- symbol -->
|
||||
<xsl:when test="regex-group(12)">
|
||||
<symbol>
|
||||
<xsl:value-of select="regex-group(12)"/>
|
||||
</symbol>
|
||||
</xsl:when>
|
||||
<!-- boolean -->
|
||||
<xsl:when test="regex-group(13)">
|
||||
<boolean>
|
||||
<xsl:value-of select="regex-group(13)"/>
|
||||
</boolean>
|
||||
</xsl:when>
|
||||
<!-- null -->
|
||||
<xsl:when test="regex-group(14)">
|
||||
<null />
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:message terminate="yes" select="'internal error'"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:matching-substring>
|
||||
<xsl:non-matching-substring>
|
||||
<xsl:if test="normalize-space()!=''">
|
||||
<xsl:message select="concat('unknown token: ', .)"/>
|
||||
<xsl:value-of select="."/>
|
||||
</xsl:if>
|
||||
</xsl:non-matching-substring>
|
||||
</xsl:analyze-string>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="mode1">
|
||||
<xsl:apply-templates mode="json2xml1" select="$mode0/node()[1]"/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="mode2">
|
||||
<xsl:apply-templates mode="json2xml2" select="$mode1"/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="mode3">
|
||||
<xsl:apply-templates mode="json2xml3" select="$mode2"/>
|
||||
</xsl:variable>
|
||||
<xsl:copy-of select="$mode3"/> <!-- change $mode3 to $mode[0-2] for easy debug -->
|
||||
</xsl:template>
|
||||
|
||||
<!-- json2xml1 mode: group content between {} and [] into object and array elements -->
|
||||
|
||||
<xsl:template mode="json2xml1" match="node()" priority="-9">
|
||||
<xsl:copy-of select="."/>
|
||||
<xsl:apply-templates mode="json2xml1" select="following-sibling::node()[1]"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template mode="json2xml1" match="symbol[.=('}',']')]"/>
|
||||
|
||||
<xsl:template mode="json2xml1" match="symbol[.=('{','[')]">
|
||||
<xsl:element name="{if (.='{') then 'object' else 'array'}">
|
||||
<xsl:apply-templates mode="json2xml1" select="following-sibling::node()[1]"/>
|
||||
</xsl:element>
|
||||
<xsl:variable name="level" select="count(preceding-sibling::symbol[.=('{','[')])-count(preceding-sibling::symbol[.=('}',']')])+1"/>
|
||||
<xsl:variable name="ender"
|
||||
select="following-sibling::symbol[.=('}',']') and count(preceding-sibling::symbol[.=('{','[')])-count(preceding-sibling::symbol[.=('}',']')])=$level][1]"/>
|
||||
<xsl:apply-templates mode="json2xml1" select="$ender/following-sibling::node()[1]"/>
|
||||
</xsl:template>
|
||||
|
||||
<!-- json2xml2 mode: group <string>:<string|integer|double|object|array> into field element -->
|
||||
|
||||
<xsl:template priority="-9" mode="json2xml2" match="@*|node()">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates mode="json2xml2" select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template mode="json2xml2"
|
||||
match="string[following-sibling::*[1]/self::symbol[.=':'] and following-sibling::*[2]/(self::string|self::integer|self::double|self::boolean|self::object|self::array|self::null)]"/>
|
||||
|
||||
<xsl:template mode="json2xml2"
|
||||
match="symbol[.=':'][preceding-sibling::*[1]/self::string and following-sibling::*[1]/(self::string|self::integer|self::double|self::boolean|self::object|self::array|self::null)]">
|
||||
<field name="{preceding-sibling::*[1]}">
|
||||
<xsl:for-each select="following-sibling::*[1]">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates mode="json2xml2" select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
</xsl:for-each>
|
||||
</field>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template mode="json2xml2"
|
||||
match="*[self::string|self::integer|self::double|self::boolean|self::object|self::array|self::null][preceding-sibling::*[2]/self::string and preceding-sibling::*[1]/self::symbol[.=':']]"/>
|
||||
|
||||
<!-- json2xml3 mode: drop comma between consecutive field and object elements -->
|
||||
|
||||
<xsl:template priority="-9" mode="json2xml3" match="@*|node()">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates mode="json2xml3" select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template mode="json2xml3" match="object/symbol[.=','][preceding-sibling::*[1]/self::field and following-sibling::*[1]/self::field]"/>
|
||||
|
||||
<xsl:template mode="json2xml3" match="array/symbol[.=','][preceding-sibling::*[1]/(self::string|self::integer|self::double|self::boolean|self::object|self::array|self::null) and following-sibling::*[1]/(self::string|self::integer|self::double|self::boolean|self::object|self::array|self::null)]"/>
|
||||
|
||||
</xsl:stylesheet>
|
||||
57
vendor/rize/uri-template/tests/fixtures/negative-tests.json
vendored
Normal file
57
vendor/rize/uri-template/tests/fixtures/negative-tests.json
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"Failure Tests":{
|
||||
"level":4,
|
||||
"variables":{
|
||||
"id" : "thing",
|
||||
"var" : "value",
|
||||
"hello" : "Hello World!",
|
||||
"with space" : "fail",
|
||||
" leading_space" : "Hi!",
|
||||
"trailing_space " : "Bye!",
|
||||
"empty" : "",
|
||||
"path" : "/foo/bar",
|
||||
"x" : "1024",
|
||||
"y" : "768",
|
||||
"list" : ["red", "green", "blue"],
|
||||
"keys" : { "semi" : ";", "dot" : ".", "comma" : ","},
|
||||
"example" : "red",
|
||||
"searchTerms" : "uri templates",
|
||||
"~thing" : "some-user",
|
||||
"default-graph-uri" : ["http://www.example/book/","http://www.example/papers/"],
|
||||
"query" : "PREFIX dc: <http://purl.org/dc/elements/1.1/> SELECT ?book ?who WHERE { ?book dc:creator ?who }"
|
||||
|
||||
},
|
||||
"testcases":[
|
||||
[ "{/id*", false ],
|
||||
[ "/id*}", false ],
|
||||
[ "{/?id}", false ],
|
||||
[ "{var:prefix}", false ],
|
||||
[ "{hello:2*}", false ] ,
|
||||
[ "{??hello}", false ] ,
|
||||
[ "{!hello}", false ] ,
|
||||
[ "{with space}", false],
|
||||
[ "{ leading_space}", false],
|
||||
[ "{trailing_space }", false],
|
||||
[ "{=path}", false ] ,
|
||||
[ "{$var}", false ],
|
||||
[ "{|var*}", false ],
|
||||
[ "{*keys?}", false ],
|
||||
[ "{?empty=default,var}", false ],
|
||||
[ "{var}{-prefix|/-/|var}" , false ],
|
||||
[ "?q={searchTerms}&c={example:color?}" , false ],
|
||||
[ "x{?empty|foo=none}" , false ],
|
||||
[ "/h{#hello+}" , false ],
|
||||
[ "/h#{hello+}" , false ],
|
||||
[ "{keys:1}", false ],
|
||||
[ "{+keys:1}", false ],
|
||||
[ "{;keys:1*}", false ],
|
||||
[ "?{-join|&|var,list}" , false ],
|
||||
[ "/people/{~thing}", false],
|
||||
[ "/{default-graph-uri}", false ],
|
||||
[ "/sparql{?query,default-graph-uri}", false ],
|
||||
[ "/sparql{?query){&default-graph-uri*}", false ],
|
||||
[ "/resolution{?x, y}" , false ]
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
439
vendor/rize/uri-template/tests/fixtures/spec-examples-by-section.json
vendored
Normal file
439
vendor/rize/uri-template/tests/fixtures/spec-examples-by-section.json
vendored
Normal file
@@ -0,0 +1,439 @@
|
||||
{
|
||||
"3.2.1 Variable Expansion" :
|
||||
{
|
||||
"variables": {
|
||||
"count" : ["one", "two", "three"],
|
||||
"dom" : ["example", "com"],
|
||||
"dub" : "me/too",
|
||||
"hello" : "Hello World!",
|
||||
"half" : "50%",
|
||||
"var" : "value",
|
||||
"who" : "fred",
|
||||
"base" : "http://example.com/home/",
|
||||
"path" : "/foo/bar",
|
||||
"list" : ["red", "green", "blue"],
|
||||
"keys" : { "semi" : ";", "dot" : ".", "comma" : ","},
|
||||
"v" : "6",
|
||||
"x" : "1024",
|
||||
"y" : "768",
|
||||
"empty" : "",
|
||||
"empty_keys" : [],
|
||||
"undef" : null
|
||||
},
|
||||
"testcases" : [
|
||||
["{count}", "one,two,three"],
|
||||
["{count*}", "one,two,three"],
|
||||
["{/count}", "/one,two,three"],
|
||||
["{/count*}", "/one/two/three"],
|
||||
["{;count}", ";count=one,two,three"],
|
||||
["{;count*}", ";count=one;count=two;count=three"],
|
||||
["{?count}", "?count=one,two,three"],
|
||||
["{?count*}", "?count=one&count=two&count=three"],
|
||||
["{&count*}", "&count=one&count=two&count=three"]
|
||||
]
|
||||
},
|
||||
"3.2.2 Simple String Expansion" :
|
||||
{
|
||||
"variables": {
|
||||
"count" : ["one", "two", "three"],
|
||||
"dom" : ["example", "com"],
|
||||
"dub" : "me/too",
|
||||
"hello" : "Hello World!",
|
||||
"half" : "50%",
|
||||
"var" : "value",
|
||||
"who" : "fred",
|
||||
"base" : "http://example.com/home/",
|
||||
"path" : "/foo/bar",
|
||||
"list" : ["red", "green", "blue"],
|
||||
"keys" : { "semi" : ";", "dot" : ".", "comma" : ","},
|
||||
"v" : "6",
|
||||
"x" : "1024",
|
||||
"y" : "768",
|
||||
"empty" : "",
|
||||
"empty_keys" : [],
|
||||
"undef" : null
|
||||
},
|
||||
"testcases" : [
|
||||
["{var}", "value"],
|
||||
["{hello}", "Hello%20World%21"],
|
||||
["{half}", "50%25"],
|
||||
["O{empty}X", "OX"],
|
||||
["O{undef}X", "OX"],
|
||||
["{x,y}", "1024,768"],
|
||||
["{x,hello,y}", "1024,Hello%20World%21,768"],
|
||||
["?{x,empty}", "?1024,"],
|
||||
["?{x,undef}", "?1024"],
|
||||
["?{undef,y}", "?768"],
|
||||
["{var:3}", "val"],
|
||||
["{var:30}", "value"],
|
||||
["{list}", "red,green,blue"],
|
||||
["{list*}", "red,green,blue"],
|
||||
["{keys}", [
|
||||
"comma,%2C,dot,.,semi,%3B",
|
||||
"comma,%2C,semi,%3B,dot,.",
|
||||
"dot,.,comma,%2C,semi,%3B",
|
||||
"dot,.,semi,%3B,comma,%2C",
|
||||
"semi,%3B,comma,%2C,dot,.",
|
||||
"semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{keys*}", [
|
||||
"comma=%2C,dot=.,semi=%3B",
|
||||
"comma=%2C,semi=%3B,dot=.",
|
||||
"dot=.,comma=%2C,semi=%3B",
|
||||
"dot=.,semi=%3B,comma=%2C",
|
||||
"semi=%3B,comma=%2C,dot=.",
|
||||
"semi=%3B,dot=.,comma=%2C"
|
||||
]]
|
||||
]
|
||||
},
|
||||
"3.2.3 Reserved Expansion" :
|
||||
{
|
||||
"variables": {
|
||||
"count" : ["one", "two", "three"],
|
||||
"dom" : ["example", "com"],
|
||||
"dub" : "me/too",
|
||||
"hello" : "Hello World!",
|
||||
"half" : "50%",
|
||||
"var" : "value",
|
||||
"who" : "fred",
|
||||
"base" : "http://example.com/home/",
|
||||
"path" : "/foo/bar",
|
||||
"list" : ["red", "green", "blue"],
|
||||
"keys" : { "semi" : ";", "dot" : ".", "comma" : ","},
|
||||
"v" : "6",
|
||||
"x" : "1024",
|
||||
"y" : "768",
|
||||
"empty" : "",
|
||||
"empty_keys" : [],
|
||||
"undef" : null
|
||||
},
|
||||
"testcases" : [
|
||||
["{+var}", "value"],
|
||||
["{/var,empty}", "/value/"],
|
||||
["{/var,undef}", "/value"],
|
||||
["{+hello}", "Hello%20World!"],
|
||||
["{+half}", "50%25"],
|
||||
["{base}index", "http%3A%2F%2Fexample.com%2Fhome%2Findex"],
|
||||
["{+base}index", "http://example.com/home/index"],
|
||||
["O{+empty}X", "OX"],
|
||||
["O{+undef}X", "OX"],
|
||||
["{+path}/here", "/foo/bar/here"],
|
||||
["{+path:6}/here", "/foo/b/here"],
|
||||
["here?ref={+path}", "here?ref=/foo/bar"],
|
||||
["up{+path}{var}/here", "up/foo/barvalue/here"],
|
||||
["{+x,hello,y}", "1024,Hello%20World!,768"],
|
||||
["{+path,x}/here", "/foo/bar,1024/here"],
|
||||
["{+list}", "red,green,blue"],
|
||||
["{+list*}", "red,green,blue"],
|
||||
["{+keys}", [
|
||||
"comma,,,dot,.,semi,;",
|
||||
"comma,,,semi,;,dot,.",
|
||||
"dot,.,comma,,,semi,;",
|
||||
"dot,.,semi,;,comma,,",
|
||||
"semi,;,comma,,,dot,.",
|
||||
"semi,;,dot,.,comma,,"
|
||||
]],
|
||||
["{+keys*}", [
|
||||
"comma=,,dot=.,semi=;",
|
||||
"comma=,,semi=;,dot=.",
|
||||
"dot=.,comma=,,semi=;",
|
||||
"dot=.,semi=;,comma=,",
|
||||
"semi=;,comma=,,dot=.",
|
||||
"semi=;,dot=.,comma=,"
|
||||
]]
|
||||
]
|
||||
},
|
||||
"3.2.4 Fragment Expansion" :
|
||||
{
|
||||
"variables": {
|
||||
"count" : ["one", "two", "three"],
|
||||
"dom" : ["example", "com"],
|
||||
"dub" : "me/too",
|
||||
"hello" : "Hello World!",
|
||||
"half" : "50%",
|
||||
"var" : "value",
|
||||
"who" : "fred",
|
||||
"base" : "http://example.com/home/",
|
||||
"path" : "/foo/bar",
|
||||
"list" : ["red", "green", "blue"],
|
||||
"keys" : { "semi" : ";", "dot" : ".", "comma" : ","},
|
||||
"v" : "6",
|
||||
"x" : "1024",
|
||||
"y" : "768",
|
||||
"empty" : "",
|
||||
"empty_keys" : [],
|
||||
"undef" : null
|
||||
},
|
||||
"testcases" : [
|
||||
["{#var}", "#value"],
|
||||
["{#hello}", "#Hello%20World!"],
|
||||
["{#half}", "#50%25"],
|
||||
["foo{#empty}", "foo#"],
|
||||
["foo{#undef}", "foo"],
|
||||
["{#x,hello,y}", "#1024,Hello%20World!,768"],
|
||||
["{#path,x}/here", "#/foo/bar,1024/here"],
|
||||
["{#path:6}/here", "#/foo/b/here"],
|
||||
["{#list}", "#red,green,blue"],
|
||||
["{#list*}", "#red,green,blue"],
|
||||
["{#keys}", [
|
||||
"#comma,,,dot,.,semi,;",
|
||||
"#comma,,,semi,;,dot,.",
|
||||
"#dot,.,comma,,,semi,;",
|
||||
"#dot,.,semi,;,comma,,",
|
||||
"#semi,;,comma,,,dot,.",
|
||||
"#semi,;,dot,.,comma,,"
|
||||
]]
|
||||
]
|
||||
},
|
||||
"3.2.5 Label Expansion with Dot-Prefix" :
|
||||
{
|
||||
"variables": {
|
||||
"count" : ["one", "two", "three"],
|
||||
"dom" : ["example", "com"],
|
||||
"dub" : "me/too",
|
||||
"hello" : "Hello World!",
|
||||
"half" : "50%",
|
||||
"var" : "value",
|
||||
"who" : "fred",
|
||||
"base" : "http://example.com/home/",
|
||||
"path" : "/foo/bar",
|
||||
"list" : ["red", "green", "blue"],
|
||||
"keys" : { "semi" : ";", "dot" : ".", "comma" : ","},
|
||||
"v" : "6",
|
||||
"x" : "1024",
|
||||
"y" : "768",
|
||||
"empty" : "",
|
||||
"empty_keys" : [],
|
||||
"undef" : null
|
||||
},
|
||||
"testcases" : [
|
||||
["{.who}", ".fred"],
|
||||
["{.who,who}", ".fred.fred"],
|
||||
["{.half,who}", ".50%25.fred"],
|
||||
["www{.dom*}", "www.example.com"],
|
||||
["X{.var}", "X.value"],
|
||||
["X{.var:3}", "X.val"],
|
||||
["X{.empty}", "X."],
|
||||
["X{.undef}", "X"],
|
||||
["X{.list}", "X.red,green,blue"],
|
||||
["X{.list*}", "X.red.green.blue"],
|
||||
["{#keys}", [
|
||||
"#comma,,,dot,.,semi,;",
|
||||
"#comma,,,semi,;,dot,.",
|
||||
"#dot,.,comma,,,semi,;",
|
||||
"#dot,.,semi,;,comma,,",
|
||||
"#semi,;,comma,,,dot,.",
|
||||
"#semi,;,dot,.,comma,,"
|
||||
]],
|
||||
["{#keys*}", [
|
||||
"#comma=,,dot=.,semi=;",
|
||||
"#comma=,,semi=;,dot=.",
|
||||
"#dot=.,comma=,,semi=;",
|
||||
"#dot=.,semi=;,comma=,",
|
||||
"#semi=;,comma=,,dot=.",
|
||||
"#semi=;,dot=.,comma=,"
|
||||
]],
|
||||
["X{.empty_keys}", "X"],
|
||||
["X{.empty_keys*}", "X"]
|
||||
]
|
||||
},
|
||||
"3.2.6 Path Segment Expansion" :
|
||||
{
|
||||
"variables": {
|
||||
"count" : ["one", "two", "three"],
|
||||
"dom" : ["example", "com"],
|
||||
"dub" : "me/too",
|
||||
"hello" : "Hello World!",
|
||||
"half" : "50%",
|
||||
"var" : "value",
|
||||
"who" : "fred",
|
||||
"base" : "http://example.com/home/",
|
||||
"path" : "/foo/bar",
|
||||
"list" : ["red", "green", "blue"],
|
||||
"keys" : { "semi" : ";", "dot" : ".", "comma" : ","},
|
||||
"v" : "6",
|
||||
"x" : "1024",
|
||||
"y" : "768",
|
||||
"empty" : "",
|
||||
"empty_keys" : [],
|
||||
"undef" : null
|
||||
},
|
||||
"testcases" : [
|
||||
["{/who}", "/fred"],
|
||||
["{/who,who}", "/fred/fred"],
|
||||
["{/half,who}", "/50%25/fred"],
|
||||
["{/who,dub}", "/fred/me%2Ftoo"],
|
||||
["{/var}", "/value"],
|
||||
["{/var,empty}", "/value/"],
|
||||
["{/var,undef}", "/value"],
|
||||
["{/var,x}/here", "/value/1024/here"],
|
||||
["{/var:1,var}", "/v/value"],
|
||||
["{/list}", "/red,green,blue"],
|
||||
["{/list*}", "/red/green/blue"],
|
||||
["{/list*,path:4}", "/red/green/blue/%2Ffoo"],
|
||||
["{/keys}", [
|
||||
"/comma,%2C,dot,.,semi,%3B",
|
||||
"/comma,%2C,semi,%3B,dot,.",
|
||||
"/dot,.,comma,%2C,semi,%3B",
|
||||
"/dot,.,semi,%3B,comma,%2C",
|
||||
"/semi,%3B,comma,%2C,dot,.",
|
||||
"/semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{/keys*}", [
|
||||
"/comma=%2C/dot=./semi=%3B",
|
||||
"/comma=%2C/semi=%3B/dot=.",
|
||||
"/dot=./comma=%2C/semi=%3B",
|
||||
"/dot=./semi=%3B/comma=%2C",
|
||||
"/semi=%3B/comma=%2C/dot=.",
|
||||
"/semi=%3B/dot=./comma=%2C"
|
||||
]]
|
||||
]
|
||||
},
|
||||
"3.2.7 Path-Style Parameter Expansion" :
|
||||
{
|
||||
"variables": {
|
||||
"count" : ["one", "two", "three"],
|
||||
"dom" : ["example", "com"],
|
||||
"dub" : "me/too",
|
||||
"hello" : "Hello World!",
|
||||
"half" : "50%",
|
||||
"var" : "value",
|
||||
"who" : "fred",
|
||||
"base" : "http://example.com/home/",
|
||||
"path" : "/foo/bar",
|
||||
"list" : ["red", "green", "blue"],
|
||||
"keys" : { "semi" : ";", "dot" : ".", "comma" : ","},
|
||||
"v" : "6",
|
||||
"x" : "1024",
|
||||
"y" : "768",
|
||||
"empty" : "",
|
||||
"empty_keys" : [],
|
||||
"undef" : null
|
||||
},
|
||||
"testcases" : [
|
||||
["{;who}", ";who=fred"],
|
||||
["{;half}", ";half=50%25"],
|
||||
["{;empty}", ";empty"],
|
||||
["{;hello:5}", ";hello=Hello"],
|
||||
["{;v,empty,who}", ";v=6;empty;who=fred"],
|
||||
["{;v,bar,who}", ";v=6;who=fred"],
|
||||
["{;x,y}", ";x=1024;y=768"],
|
||||
["{;x,y,empty}", ";x=1024;y=768;empty"],
|
||||
["{;x,y,undef}", ";x=1024;y=768"],
|
||||
["{;list}", ";list=red,green,blue"],
|
||||
["{;list*}", ";list=red;list=green;list=blue"],
|
||||
["{;keys}", [
|
||||
";keys=comma,%2C,dot,.,semi,%3B",
|
||||
";keys=comma,%2C,semi,%3B,dot,.",
|
||||
";keys=dot,.,comma,%2C,semi,%3B",
|
||||
";keys=dot,.,semi,%3B,comma,%2C",
|
||||
";keys=semi,%3B,comma,%2C,dot,.",
|
||||
";keys=semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{;keys*}", [
|
||||
";comma=%2C;dot=.;semi=%3B",
|
||||
";comma=%2C;semi=%3B;dot=.",
|
||||
";dot=.;comma=%2C;semi=%3B",
|
||||
";dot=.;semi=%3B;comma=%2C",
|
||||
";semi=%3B;comma=%2C;dot=.",
|
||||
";semi=%3B;dot=.;comma=%2C"
|
||||
]]
|
||||
]
|
||||
},
|
||||
"3.2.8 Form-Style Query Expansion" :
|
||||
{
|
||||
"variables": {
|
||||
"count" : ["one", "two", "three"],
|
||||
"dom" : ["example", "com"],
|
||||
"dub" : "me/too",
|
||||
"hello" : "Hello World!",
|
||||
"half" : "50%",
|
||||
"var" : "value",
|
||||
"who" : "fred",
|
||||
"base" : "http://example.com/home/",
|
||||
"path" : "/foo/bar",
|
||||
"list" : ["red", "green", "blue"],
|
||||
"keys" : { "semi" : ";", "dot" : ".", "comma" : ","},
|
||||
"v" : "6",
|
||||
"x" : "1024",
|
||||
"y" : "768",
|
||||
"empty" : "",
|
||||
"empty_keys" : [],
|
||||
"undef" : null
|
||||
},
|
||||
"testcases" : [
|
||||
["{?who}", "?who=fred"],
|
||||
["{?half}", "?half=50%25"],
|
||||
["{?x,y}", "?x=1024&y=768"],
|
||||
["{?x,y,empty}", "?x=1024&y=768&empty="],
|
||||
["{?x,y,undef}", "?x=1024&y=768"],
|
||||
["{?var:3}", "?var=val"],
|
||||
["{?list}", "?list=red,green,blue"],
|
||||
["{?list*}", "?list=red&list=green&list=blue"],
|
||||
["{?keys}", [
|
||||
"?keys=comma,%2C,dot,.,semi,%3B",
|
||||
"?keys=comma,%2C,semi,%3B,dot,.",
|
||||
"?keys=dot,.,comma,%2C,semi,%3B",
|
||||
"?keys=dot,.,semi,%3B,comma,%2C",
|
||||
"?keys=semi,%3B,comma,%2C,dot,.",
|
||||
"?keys=semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{?keys*}", [
|
||||
"?comma=%2C&dot=.&semi=%3B",
|
||||
"?comma=%2C&semi=%3B&dot=.",
|
||||
"?dot=.&comma=%2C&semi=%3B",
|
||||
"?dot=.&semi=%3B&comma=%2C",
|
||||
"?semi=%3B&comma=%2C&dot=.",
|
||||
"?semi=%3B&dot=.&comma=%2C"
|
||||
]]
|
||||
]
|
||||
},
|
||||
"3.2.9 Form-Style Query Continuation" :
|
||||
{
|
||||
"variables": {
|
||||
"count" : ["one", "two", "three"],
|
||||
"dom" : ["example", "com"],
|
||||
"dub" : "me/too",
|
||||
"hello" : "Hello World!",
|
||||
"half" : "50%",
|
||||
"var" : "value",
|
||||
"who" : "fred",
|
||||
"base" : "http://example.com/home/",
|
||||
"path" : "/foo/bar",
|
||||
"list" : ["red", "green", "blue"],
|
||||
"keys" : { "semi" : ";", "dot" : ".", "comma" : ","},
|
||||
"v" : "6",
|
||||
"x" : "1024",
|
||||
"y" : "768",
|
||||
"empty" : "",
|
||||
"empty_keys" : [],
|
||||
"undef" : null
|
||||
},
|
||||
"testcases" : [
|
||||
["{&who}", "&who=fred"],
|
||||
["{&half}", "&half=50%25"],
|
||||
["?fixed=yes{&x}", "?fixed=yes&x=1024"],
|
||||
["{&var:3}", "&var=val"],
|
||||
["{&x,y,empty}", "&x=1024&y=768&empty="],
|
||||
["{&x,y,undef}", "&x=1024&y=768"],
|
||||
["{&list}", "&list=red,green,blue"],
|
||||
["{&list*}", "&list=red&list=green&list=blue"],
|
||||
["{&keys}", [
|
||||
"&keys=comma,%2C,dot,.,semi,%3B",
|
||||
"&keys=comma,%2C,semi,%3B,dot,.",
|
||||
"&keys=dot,.,comma,%2C,semi,%3B",
|
||||
"&keys=dot,.,semi,%3B,comma,%2C",
|
||||
"&keys=semi,%3B,comma,%2C,dot,.",
|
||||
"&keys=semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{&keys*}", [
|
||||
"&comma=%2C&dot=.&semi=%3B",
|
||||
"&comma=%2C&semi=%3B&dot=.",
|
||||
"&dot=.&comma=%2C&semi=%3B",
|
||||
"&dot=.&semi=%3B&comma=%2C",
|
||||
"&semi=%3B&comma=%2C&dot=.",
|
||||
"&semi=%3B&dot=.&comma=%2C"
|
||||
]]
|
||||
]
|
||||
}
|
||||
}
|
||||
218
vendor/rize/uri-template/tests/fixtures/spec-examples.json
vendored
Normal file
218
vendor/rize/uri-template/tests/fixtures/spec-examples.json
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
{
|
||||
"Level 1 Examples" :
|
||||
{
|
||||
"level": 1,
|
||||
"variables": {
|
||||
"var" : "value",
|
||||
"hello" : "Hello World!"
|
||||
},
|
||||
"testcases" : [
|
||||
["{var}", "value"],
|
||||
["{hello}", "Hello%20World%21"]
|
||||
]
|
||||
},
|
||||
"Level 2 Examples" :
|
||||
{
|
||||
"level": 2,
|
||||
"variables": {
|
||||
"var" : "value",
|
||||
"hello" : "Hello World!",
|
||||
"path" : "/foo/bar"
|
||||
},
|
||||
"testcases" : [
|
||||
["{+var}", "value"],
|
||||
["{+hello}", "Hello%20World!"],
|
||||
["{+path}/here", "/foo/bar/here"],
|
||||
["here?ref={+path}", "here?ref=/foo/bar"]
|
||||
]
|
||||
},
|
||||
"Level 3 Examples" :
|
||||
{
|
||||
"level": 3,
|
||||
"variables": {
|
||||
"var" : "value",
|
||||
"hello" : "Hello World!",
|
||||
"empty" : "",
|
||||
"path" : "/foo/bar",
|
||||
"x" : "1024",
|
||||
"y" : "768"
|
||||
},
|
||||
"testcases" : [
|
||||
["map?{x,y}", "map?1024,768"],
|
||||
["{x,hello,y}", "1024,Hello%20World%21,768"],
|
||||
["{+x,hello,y}", "1024,Hello%20World!,768"],
|
||||
["{+path,x}/here", "/foo/bar,1024/here"],
|
||||
["{#x,hello,y}", "#1024,Hello%20World!,768"],
|
||||
["{#path,x}/here", "#/foo/bar,1024/here"],
|
||||
["X{.var}", "X.value"],
|
||||
["X{.x,y}", "X.1024.768"],
|
||||
["{/var}", "/value"],
|
||||
["{/var,x}/here", "/value/1024/here"],
|
||||
["{;x,y}", ";x=1024;y=768"],
|
||||
["{;x,y,empty}", ";x=1024;y=768;empty"],
|
||||
["{?x,y}", "?x=1024&y=768"],
|
||||
["{?x,y,empty}", "?x=1024&y=768&empty="],
|
||||
["?fixed=yes{&x}", "?fixed=yes&x=1024"],
|
||||
["{&x,y,empty}", "&x=1024&y=768&empty="]
|
||||
]
|
||||
},
|
||||
"Level 4 Examples" :
|
||||
{
|
||||
"level": 4,
|
||||
"variables": {
|
||||
"var": "value",
|
||||
"hello": "Hello World!",
|
||||
"path": "/foo/bar",
|
||||
"list": ["red", "green", "blue"],
|
||||
"keys": {"semi": ";", "dot": ".", "comma":","}
|
||||
},
|
||||
"testcases": [
|
||||
["{var:3}", "val"],
|
||||
["{var:30}", "value"],
|
||||
["{list}", "red,green,blue"],
|
||||
["{list*}", "red,green,blue"],
|
||||
["{keys}", [
|
||||
"comma,%2C,dot,.,semi,%3B",
|
||||
"comma,%2C,semi,%3B,dot,.",
|
||||
"dot,.,comma,%2C,semi,%3B",
|
||||
"dot,.,semi,%3B,comma,%2C",
|
||||
"semi,%3B,comma,%2C,dot,.",
|
||||
"semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{keys*}", [
|
||||
"comma=%2C,dot=.,semi=%3B",
|
||||
"comma=%2C,semi=%3B,dot=.",
|
||||
"dot=.,comma=%2C,semi=%3B",
|
||||
"dot=.,semi=%3B,comma=%2C",
|
||||
"semi=%3B,comma=%2C,dot=.",
|
||||
"semi=%3B,dot=.,comma=%2C"
|
||||
]],
|
||||
["{+path:6}/here", "/foo/b/here"],
|
||||
["{+list}", "red,green,blue"],
|
||||
["{+list*}", "red,green,blue"],
|
||||
["{+keys}", [
|
||||
"comma,,,dot,.,semi,;",
|
||||
"comma,,,semi,;,dot,.",
|
||||
"dot,.,comma,,,semi,;",
|
||||
"dot,.,semi,;,comma,,",
|
||||
"semi,;,comma,,,dot,.",
|
||||
"semi,;,dot,.,comma,,"
|
||||
]],
|
||||
["{+keys*}", [
|
||||
"comma=,,dot=.,semi=;",
|
||||
"comma=,,semi=;,dot=.",
|
||||
"dot=.,comma=,,semi=;",
|
||||
"dot=.,semi=;,comma=,",
|
||||
"semi=;,comma=,,dot=.",
|
||||
"semi=;,dot=.,comma=,"
|
||||
]],
|
||||
["{#path:6}/here", "#/foo/b/here"],
|
||||
["{#list}", "#red,green,blue"],
|
||||
["{#list*}", "#red,green,blue"],
|
||||
["{#keys}", [
|
||||
"#comma,,,dot,.,semi,;",
|
||||
"#comma,,,semi,;,dot,.",
|
||||
"#dot,.,comma,,,semi,;",
|
||||
"#dot,.,semi,;,comma,,",
|
||||
"#semi,;,comma,,,dot,.",
|
||||
"#semi,;,dot,.,comma,,"
|
||||
]],
|
||||
["{#keys*}", [
|
||||
"#comma=,,dot=.,semi=;",
|
||||
"#comma=,,semi=;,dot=.",
|
||||
"#dot=.,comma=,,semi=;",
|
||||
"#dot=.,semi=;,comma=,",
|
||||
"#semi=;,comma=,,dot=.",
|
||||
"#semi=;,dot=.,comma=,"
|
||||
]],
|
||||
["X{.var:3}", "X.val"],
|
||||
["X{.list}", "X.red,green,blue"],
|
||||
["X{.list*}", "X.red.green.blue"],
|
||||
["X{.keys}", [
|
||||
"X.comma,%2C,dot,.,semi,%3B",
|
||||
"X.comma,%2C,semi,%3B,dot,.",
|
||||
"X.dot,.,comma,%2C,semi,%3B",
|
||||
"X.dot,.,semi,%3B,comma,%2C",
|
||||
"X.semi,%3B,comma,%2C,dot,.",
|
||||
"X.semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{/var:1,var}", "/v/value"],
|
||||
["{/list}", "/red,green,blue"],
|
||||
["{/list*}", "/red/green/blue"],
|
||||
["{/list*,path:4}", "/red/green/blue/%2Ffoo"],
|
||||
["{/keys}", [
|
||||
"/comma,%2C,dot,.,semi,%3B",
|
||||
"/comma,%2C,semi,%3B,dot,.",
|
||||
"/dot,.,comma,%2C,semi,%3B",
|
||||
"/dot,.,semi,%3B,comma,%2C",
|
||||
"/semi,%3B,comma,%2C,dot,.",
|
||||
"/semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{/keys*}", [
|
||||
"/comma=%2C/dot=./semi=%3B",
|
||||
"/comma=%2C/semi=%3B/dot=.",
|
||||
"/dot=./comma=%2C/semi=%3B",
|
||||
"/dot=./semi=%3B/comma=%2C",
|
||||
"/semi=%3B/comma=%2C/dot=.",
|
||||
"/semi=%3B/dot=./comma=%2C"
|
||||
]],
|
||||
["{;hello:5}", ";hello=Hello"],
|
||||
["{;list}", ";list=red,green,blue"],
|
||||
["{;list*}", ";list=red;list=green;list=blue"],
|
||||
["{;keys}", [
|
||||
";keys=comma,%2C,dot,.,semi,%3B",
|
||||
";keys=comma,%2C,semi,%3B,dot,.",
|
||||
";keys=dot,.,comma,%2C,semi,%3B",
|
||||
";keys=dot,.,semi,%3B,comma,%2C",
|
||||
";keys=semi,%3B,comma,%2C,dot,.",
|
||||
";keys=semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{;keys*}", [
|
||||
";comma=%2C;dot=.;semi=%3B",
|
||||
";comma=%2C;semi=%3B;dot=.",
|
||||
";dot=.;comma=%2C;semi=%3B",
|
||||
";dot=.;semi=%3B;comma=%2C",
|
||||
";semi=%3B;comma=%2C;dot=.",
|
||||
";semi=%3B;dot=.;comma=%2C"
|
||||
]],
|
||||
["{?var:3}", "?var=val"],
|
||||
["{?list}", "?list=red,green,blue"],
|
||||
["{?list*}", "?list=red&list=green&list=blue"],
|
||||
["{?keys}", [
|
||||
"?keys=comma,%2C,dot,.,semi,%3B",
|
||||
"?keys=comma,%2C,semi,%3B,dot,.",
|
||||
"?keys=dot,.,comma,%2C,semi,%3B",
|
||||
"?keys=dot,.,semi,%3B,comma,%2C",
|
||||
"?keys=semi,%3B,comma,%2C,dot,.",
|
||||
"?keys=semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{?keys*}", [
|
||||
"?comma=%2C&dot=.&semi=%3B",
|
||||
"?comma=%2C&semi=%3B&dot=.",
|
||||
"?dot=.&comma=%2C&semi=%3B",
|
||||
"?dot=.&semi=%3B&comma=%2C",
|
||||
"?semi=%3B&comma=%2C&dot=.",
|
||||
"?semi=%3B&dot=.&comma=%2C"
|
||||
]],
|
||||
["{&var:3}", "&var=val"],
|
||||
["{&list}", "&list=red,green,blue"],
|
||||
["{&list*}", "&list=red&list=green&list=blue"],
|
||||
["{&keys}", [
|
||||
"&keys=comma,%2C,dot,.,semi,%3B",
|
||||
"&keys=comma,%2C,semi,%3B,dot,.",
|
||||
"&keys=dot,.,comma,%2C,semi,%3B",
|
||||
"&keys=dot,.,semi,%3B,comma,%2C",
|
||||
"&keys=semi,%3B,comma,%2C,dot,.",
|
||||
"&keys=semi,%3B,dot,.,comma,%2C"
|
||||
]],
|
||||
["{&keys*}", [
|
||||
"&comma=%2C&dot=.&semi=%3B",
|
||||
"&comma=%2C&semi=%3B&dot=.",
|
||||
"&dot=.&comma=%2C&semi=%3B",
|
||||
"&dot=.&semi=%3B&comma=%2C",
|
||||
"&semi=%3B&comma=%2C&dot=.",
|
||||
"&semi=%3B&dot=.&comma=%2C"
|
||||
]]
|
||||
]
|
||||
}
|
||||
}
|
||||
51
vendor/rize/uri-template/tests/fixtures/transform-json-tests.xslt
vendored
Normal file
51
vendor/rize/uri-template/tests/fixtures/transform-json-tests.xslt
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
|
||||
<xsl:include href="json2xml.xslt"/>
|
||||
|
||||
<!-- the input test files need to be supplied as a sequence of file names only (no extension) -->
|
||||
<xsl:param name="tests" select="('extended-tests', 'negative-tests', 'spec-examples-by-section', 'spec-examples')"/>
|
||||
<xsl:param name="json-ext" select="'json'"/>
|
||||
<xsl:param name="xml-ext" select="'xml'"/>
|
||||
|
||||
<!-- run this stylesheet with any input to generate the XML test files at output. -->
|
||||
<!-- (a popular way of doing this is to supply the XSLT to itself as the input file.) -->
|
||||
|
||||
<xsl:template match="/">
|
||||
<xsl:for-each select="$tests">
|
||||
<xsl:variable name="file" select="current()"/>
|
||||
<xsl:variable name="json">
|
||||
<json>
|
||||
<xsl:value-of select="unparsed-text(concat($file, '.', $json-ext))"/>
|
||||
</json>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="xml">
|
||||
<xsl:apply-templates select="$json/json"/>
|
||||
</xsl:variable>
|
||||
<xsl:result-document href="{$file}.{$xml-ext}" method="xml" indent="yes">
|
||||
<tests>
|
||||
<xsl:for-each select="$xml/json/object/field">
|
||||
<test name="{@name}">
|
||||
<xsl:if test="exists(object/field[1][@name eq 'level'])">
|
||||
<xsl:attribute name="level" select="object/field[1][@name eq 'level']/integer/text()"/>
|
||||
</xsl:if>
|
||||
<variables>
|
||||
<xsl:for-each select="object/field[@name eq 'variables']/object/field">
|
||||
<variable name="{@name}">
|
||||
<xsl:copy-of select="*"/>
|
||||
</variable>
|
||||
</xsl:for-each>
|
||||
</variables>
|
||||
<testcases>
|
||||
<xsl:for-each select="object/field[@name eq 'testcases']/array/array">
|
||||
<testcase template="{*[1]}" result="{*[2]}"/>
|
||||
</xsl:for-each> </testcases>
|
||||
</test>
|
||||
</xsl:for-each>
|
||||
</tests>
|
||||
</xsl:result-document>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
Reference in New Issue
Block a user