├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── docs.yml │ ├── phpstan.yml │ └── tests.yml ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── SECURITY.md ├── composer.json ├── config └── json-api.php ├── docs ├── .editorconfig ├── .vuepress │ ├── config.ts │ └── public │ │ └── images │ │ └── hero.jpg ├── README.md ├── comparison.md └── guide │ ├── README.md │ ├── implementations.md │ ├── testing.md │ └── usage.md ├── package.json ├── phpstan.neon ├── phpunit.coverage.dist.xml ├── phpunit.dist.xml ├── pint.json ├── src ├── Builder.php ├── Concerns │ └── HasConfig.php ├── Contracts │ └── JsonApiable.php ├── Http │ └── Resources │ │ ├── Authorizable.php │ │ ├── CollectsResources.php │ │ ├── CollectsWithIncludes.php │ │ ├── Json │ │ └── ResourceCollection.php │ │ ├── JsonApiCollection.php │ │ ├── JsonApiResource.php │ │ └── RelationshipsWithIncludes.php ├── JsonApiServiceProvider.php ├── Support │ ├── Facades │ │ └── JsonApi.php │ └── JsonApi.php └── Testing │ ├── Assert.php │ ├── Concerns │ ├── HasAttributes.php │ ├── HasCollections.php │ ├── HasIdentifications.php │ └── HasRelationships.php │ └── TestResponseMacros.php ├── tests ├── Fixtures │ ├── Post.php │ ├── Tag.php │ └── User.php ├── JsonApiAuthorisationTest.php ├── JsonApiCollectionTest.php ├── JsonApiPaginationTest.php ├── JsonApiRelationshipsTest.php ├── JsonApiResourceTest.php ├── TestCase.php └── database │ └── migrations │ ├── 0000_00_00_000000_create_users_table.php │ ├── 0000_00_00_000001_create_posts_table.php │ └── 0000_00_00_000002_create_tags_table.php └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = true 13 | 14 | [*.yml] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | *.js linguist-vendored 5 | CHANGELOG.md export-ignore 6 | *.lock -diff 7 | *.min.js -diff 8 | *.min.css -diff 9 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Publish docs 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths: 7 | - 'docs/**' 8 | # trigger deployment manually 9 | workflow_dispatch: 10 | 11 | jobs: 12 | docs: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | with: 18 | # fetch all commits to get last updated time or other git log info 19 | fetch-depth: 0 20 | 21 | - name: Setup Node.js 22 | uses: actions/setup-node@v1 23 | with: 24 | # choose node.js version to use 25 | node-version: '14' 26 | 27 | # cache node_modules 28 | - name: Cache dependencies 29 | uses: actions/cache@v2 30 | id: yarn-cache 31 | with: 32 | path: | 33 | **/node_modules 34 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 35 | restore-keys: | 36 | ${{ runner.os }}-yarn- 37 | 38 | - name: Install dependencies 39 | if: steps.yarn-cache.outputs.cache-hit != 'true' 40 | run: yarn --frozen-lockfile 41 | 42 | - name: Build VuePress site 43 | run: yarn docs:build 44 | 45 | - name: Deploy to GitHub Pages 46 | uses: crazy-max/ghaction-github-pages@v2 47 | with: 48 | target_branch: gh-pages 49 | build_dir: docs/.vuepress/dist 50 | env: 51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 52 | -------------------------------------------------------------------------------- /.github/workflows/phpstan.yml: -------------------------------------------------------------------------------- 1 | name: phpstan 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | analyze: 7 | runs-on: ubuntu-latest 8 | 9 | name: PHPStan 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: Setup PHP 15 | uses: shivammathur/setup-php@v2 16 | with: 17 | php-version: 8.1 18 | extensions: dom, curl, mbstring, zip, pcntl, bcmath, intl, exif 19 | 20 | - name: Get composer cache directory 21 | id: composer-cache 22 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 23 | 24 | - name: Cache dependencies 25 | uses: actions/cache@v2 26 | with: 27 | path: ${{ steps.composer-cache.outputs.dir }} 28 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} 29 | restore-keys: ${{ runner.os }}-composer-prefer-stable- 30 | 31 | - name: Install dependencies 32 | run: | 33 | composer update --prefer-stable --prefer-dist --no-interaction --no-suggest 34 | 35 | - name: Run analysis 36 | run: ./vendor/bin/phpstan analyse 37 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | test: 7 | runs-on: ${{ matrix.os }} 8 | 9 | strategy: 10 | fail-fast: true 11 | matrix: 12 | os: [ ubuntu-latest ] 13 | php: [ 7.4, 8.0, 8.1 ] 14 | laravel: [ 6.*, 8.*, 9.* ] 15 | dependency-version: [ prefer-stable ] 16 | exclude: 17 | # PHP 8.1 is not compatible with Laravel 6! 18 | - laravel: 6.* 19 | php: 8.1 20 | # PHP 7 is not compatible with Laravel 9 and future releases! 21 | - laravel: 9.* 22 | php: 7.4 23 | include: 24 | - laravel: 6.* 25 | testbench: 4.* 26 | 27 | - laravel: 8.* 28 | testbench: 6.* 29 | 30 | - laravel: 9.* 31 | testbench: 7.* 32 | 33 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} 34 | 35 | steps: 36 | - name: Checkout code 37 | uses: actions/checkout@v2 38 | 39 | - name: Setup PHP 40 | uses: shivammathur/setup-php@v2 41 | with: 42 | php-version: ${{ matrix.php }} 43 | extensions: dom, curl, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, intl, exif 44 | coverage: pcov 45 | 46 | - name: Get composer cache directory 47 | id: composer-cache 48 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 49 | 50 | - name: Cache dependencies 51 | uses: actions/cache@v2 52 | with: 53 | path: ${{ steps.composer-cache.outputs.dir }} 54 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} 55 | restore-keys: ${{ runner.os }}-composer-${{ matrix.dependency-version }}- 56 | 57 | - name: Install dependencies 58 | run: | 59 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update 60 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction 61 | 62 | - name: Execute tests 63 | run: | 64 | cp phpunit.coverage.dist.xml phpunit.xml || true 65 | vendor/bin/phpunit 66 | 67 | - name: Deploy coverage to codacy 68 | uses: codacy/codacy-coverage-reporter-action@v1 69 | with: 70 | # project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} 71 | api-token: ${{ secrets.CODACY_API_TOKEN }} 72 | coverage-reports: clover.xml 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | composer.lock 3 | .phpunit.result.cache 4 | phpunit.xml 5 | node_modules 6 | .cache 7 | .temp 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "laravel-pint.enable": true, 3 | "editor.formatOnSave": true 4 | } 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ruben Robles 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![json-api-logo](https://raw.githubusercontent.com/skore/laravel-json-api/master/docs/.vuepress/public/images/hero.jpg) 2 | 3 | **THIS PACKAGE IS GONNA BE DEPRECATED IN FAVOUR OF THIS ONE**: https://github.com/open-southeners/laravel-apiable 4 | 5 |

Laravel JSON:API

6 | 7 | [![latest tag](https://img.shields.io/github/v/tag/skore/laravel-json-api?label=latest&sort=semver)](https://github.com/skore/laravel-json-api/releases/latest) [![packagist version](https://img.shields.io/packagist/v/skore-labs/laravel-json-api)](https://packagist.org/packages/skore-labs/laravel-json-api) [![run-tests](https://github.com/skore/laravel-json-api/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/skore/laravel-json-api/actions/workflows/tests.yml) [![phpstan](https://github.com/skore/laravel-json-api/actions/workflows/phpstan.yml/badge.svg)](https://github.com/skore/laravel-json-api/actions/workflows/phpstan.yml) [![StyleCI](https://github.styleci.io/repos/198988581/shield?style=flat&branch=master)](https://github.styleci.io/repos/198988581) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/032829b3392846c1864b912ba9d0aa90)](https://www.codacy.com/gh/skore/laravel-json-api/dashboard?utm_source=github.com&utm_medium=referral&utm_content=skore/laravel-json-api&utm_campaign=Badge_Grade) [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/032829b3392846c1864b912ba9d0aa90)](https://www.codacy.com/gh/skore/laravel-json-api/dashboard?utm_source=github.com&utm_medium=referral&utm_content=skore/laravel-json-api&utm_campaign=Badge_Coverage) [![Scc Count Badge](https://sloc.xyz/github/skore/laravel-json-api?category=code)](https://github.com/skore/laravel-json-api) [![Scc Count Badge](https://sloc.xyz/github/skore/laravel-json-api?category=comments)](https://github.com/skore/laravel-json-api) [![Take a peek on VSCode online](https://img.shields.io/badge/vscode-Take%20a%20peek-blue?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAACJklEQVQoFYVSS2hTURCdue8l7cv3NT8bYrMqCtYitRZEKKIrwW6kGy0obtzpoqCIC/GBoEUptKDQLgRBKIo7FUW6EHFTN1XxW900IAZFbEiwecn9jPNSGkWwDgz3ztxzzswwF+E/Nujdj8Ri0dPRTGHUyeSnmwT3arF4BTfiDU7MF22CC4LoeDxXENFcEYjgtQG6+U/i0JUn3dRUM4g0wmgrni1AdFOR6wQUXLV3XHu5hSg8LBU8fD++rQxAOODN56Uv5/i+t9URGaUIpTLgBDEBRbBv+u0zvu3h8Kk2NCFWSnVEaxIQhwIQ669y1dls70DWdqJjBCACqq2MniHC7Qi4j/vvJzsiofGzG4QVsD4LglNuyn1MHZHzynCtQI3NXip8uN1b2trJiSlCkYFIhgVZ1K9+stA6unT54PMAOHynGhxtE33vwGp8K2m5Ulaq6QPPAcpJgUz2VPxkTwd4gQrngvwfLr7XwscUwaRs1F3540tdKvVVcksKxC5lzFy+89VYi8gtMY6d39htxpzRRscR4Y0gdQIFaq3hBoDp5yELYOBW5uKLnX6jEbND4XarNhl9xADuN026W7k+WgpeUpcWD5PGqyx8oDUwmZO1atWPd6W57bXVt7YJnofsPMFvc7yFzRaEpwjwEBglXNeFRCq3DjBr9PXwrzN2bjErQzQLWo8wMZRI5yTvdxk3+nJtDW8hEdbW2USya3fCTT8wWj9aLqc//gJwC/Y8vXqalgAAAABJRU5ErkJggg==)](https://vscode.dev/github/skore/laravel-json-api) 8 | 9 | Integrate JSON:API resources on Laravel. 10 | 11 | ## Features 12 | 13 | - Compatible and tested with all the Laravel LTS supported versions ([see them here](https://laravel.com/docs/master/releases#support-policy)) 14 | - Full formatting using pure built-in model methods and properties. 15 | - Relationships and nested working with [eager loading](https://laravel.com/docs/master/eloquent-relationships#eager-loading). 16 | - Permissions "out-of-the-box" authorising each resource view or list of resources. 17 | - Auto-hide not allowed attributes from responses like `user_id` or `post_id`. 18 | - Own testing utilities built-in Laravel's ones to make integration tests easier. 19 | 20 | ## Documentation 21 | 22 | [Official documentation](https://skorelabs.github.io/laravel-json-api) 23 | 24 | ## Credits 25 | 26 | - Ruben Robles ([@d8vjork](https://github.com/d8vjork)) 27 | - Skore ([https://www.getskore.com/](https://www.getskore.com/)) 28 | - [And all the contributors](https://github.com/skore-labs/laravel-json-api/graphs/contributors) 29 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | We're also following the [Laravel's default support policy](https://laravel.com/docs/master/releases#support-policy) on our semantic versioning. 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 3.x | :white_check_mark: | 10 | | < 3.0 | :x: | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | Send us an email at developers@getskore.com 15 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "skore-labs/laravel-json-api", 3 | "description": "Integrate JSON:API resources on Laravel", 4 | "license": "MIT", 5 | "keywords": [ 6 | "skore-labs", 7 | "laravel-json-api", 8 | "json-api" 9 | ], 10 | "authors": [ 11 | { 12 | "name": "Ruben Robles", 13 | "email": "d8vjork@outlook.com" 14 | } 15 | ], 16 | "require": { 17 | "php": "^7.2|^8.0|^8.1", 18 | "illuminate/http": "^6.0|^8.0|^9.0", 19 | "illuminate/support": "^6.0|^8.0|^9.0" 20 | }, 21 | "require-dev": { 22 | "ext-json": "*", 23 | "nunomaduro/larastan": "^1.0", 24 | "orchestra/testbench": "^4.0|^6.0|^7.0", 25 | "phpstan/phpstan": "^1.0", 26 | "phpunit/phpunit": "^7.0|^9.0" 27 | }, 28 | "suggest": { 29 | "hammerstone/fast-paginate": "Improves jsonPaginate method performance (SQL database query pagination)", 30 | "skorelabs/laravel-query-builder": "Allows to include data on your API responses following the JSON:API" 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "SkoreLabs\\JsonApi\\": "src" 35 | } 36 | }, 37 | "autoload-dev": { 38 | "psr-4": { 39 | "SkoreLabs\\JsonApi\\Tests\\": "tests" 40 | } 41 | }, 42 | "config": { 43 | "sort-packages": true 44 | }, 45 | "extra": { 46 | "laravel": { 47 | "providers": [ 48 | "SkoreLabs\\JsonApi\\JsonApiServiceProvider" 49 | ] 50 | } 51 | }, 52 | "minimum-stability": "dev" 53 | } 54 | -------------------------------------------------------------------------------- /config/json-api.php: -------------------------------------------------------------------------------- 1 | [ 6 | /* 7 | * The default number of results that will be returned 8 | * when using the JSON API paginator. 9 | */ 10 | 'default_size' => 50, 11 | ], 12 | 13 | 'included' => 'included', 14 | 15 | /** 16 | * Bypass package built-in authorisation 17 | * with true it won't check policies (view & viewAny). 18 | */ 19 | 'authorisable' => [ 20 | 'viewAny' => false, 21 | 'view' => false, 22 | ], 23 | 24 | /** 25 | * This transforms all under the relationships 26 | * like the following example:. 27 | * 28 | * myRelation => my_relation 29 | */ 30 | 'normalize_relations' => false, 31 | 32 | ]; 33 | -------------------------------------------------------------------------------- /docs/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false -------------------------------------------------------------------------------- /docs/.vuepress/config.ts: -------------------------------------------------------------------------------- 1 | import { defineUserConfig } from 'vuepress' 2 | import type { DefaultThemeOptions } from 'vuepress' 3 | 4 | export default defineUserConfig({ 5 | base: '/laravel-json-api/', 6 | lang: 'en-US', 7 | title: 'Laravel JSON:API', 8 | description: 'Integrate JSON:API resources on Laravel', 9 | 10 | plugins: [ 11 | [ 12 | '@vuepress/search', { 13 | searchMaxSuggestions: 10 14 | } 15 | ] 16 | ], 17 | 18 | theme: '@vuepress/theme-default', 19 | themeConfig: { 20 | logo: 'https://skore-public-assets.s3.eu-west-2.amazonaws.com/skore-logo-2x.png', 21 | 22 | repo: 'skore/laravel-json-api', 23 | 24 | navbar: [ 25 | { 26 | text: 'Home', 27 | link: '/README.md', 28 | }, 29 | { 30 | text: 'Guide', 31 | children: [ 32 | { 33 | text: 'Installation', 34 | link: '/guide/README.md' 35 | }, 36 | '/guide/usage.md', 37 | '/guide/testing.md', 38 | '/guide/implementations.md', 39 | ], 40 | }, 41 | { 42 | text: 'Comparison', 43 | link: '/comparison.md', 44 | } 45 | ], 46 | 47 | sidebar: { 48 | '/guide/': [ 49 | { 50 | text: 'Introduction', 51 | children: [ 52 | { 53 | text: 'Installation', 54 | link: '/guide/README.md' 55 | }, 56 | { 57 | text: 'Usage', 58 | link: '/guide/usage.md' 59 | }, 60 | { 61 | text: 'Testing', 62 | link: '/guide/testing.md' 63 | }, 64 | { 65 | text: 'Implementations', 66 | link: '/guide/implementations.md' 67 | }, 68 | ] 69 | }, 70 | // { 71 | // text: 'Upgrading', 72 | // link: '/guide/upgrading.md' 73 | // }, 74 | ], 75 | }, 76 | }, 77 | }) 78 | -------------------------------------------------------------------------------- /docs/.vuepress/public/images/hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skore/laravel-json-api/e75f7c874c1c287b71536f2c2fd9c9bf7a4f4b0c/docs/.vuepress/public/images/hero.jpg -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | title: Home 4 | heroImage: /images/hero.jpg 5 | actions: 6 | - text: Get Started 7 | link: /guide/README.md 8 | type: primary 9 | - text: Comparison 10 | link: /comparison.md 11 | type: secondary 12 | features: 13 | - title: Long Term Support 14 | details: Compatible and tested with all the Laravel LTS supported versions. 15 | - title: Brainless implementation 16 | details: Write no code to achieve a basic JSON:API parsing of your models. 17 | - title: Built-in policies 18 | details: Permissions "out-of-the-box" authorising each resource view or list of resources. 19 | footer: MIT Licensed | Copyright © 2022 Open Southeners 20 | --- -------------------------------------------------------------------------------- /docs/comparison.md: -------------------------------------------------------------------------------- 1 | ::: danger 2 | **This package won't be receiving any feature updates.** If you didn't see, you should check [our next version of this package clicking here](https://github.com/open-southeners/laravel-apiable). 3 | ::: 4 | 5 | # Comparison 6 | 7 | Of course there are lot more libraries out there for Laravel and even more generic (for PHP) that we can also use instead of this one. 8 | 9 | So here we'll explain the differences between them and this one. 10 | 11 | ## laravel-json-api 12 | 13 | - Repository here: [https://github.com/laravel-json-api/laravel](https://github.com/laravel-json-api/laravel) 14 | 15 | This is much more complex as it adds another layer of complexity on our application called `Schemas` so it doesn't only provide JSON:API parsing of the Eloquent models but also validation and comes with more extra stuff but with a much bigger sacrifice (**need to write much more code, while our solution is almost code-less**). 16 | 17 | Also it comes licensed as Apache 2.0, while our is following the same Laravel's license: MIT. 18 | 19 | ## Fractal 20 | 21 | - Repository here: [https://github.com/thephpleague/fractal](https://github.com/thephpleague/fractal) 22 | 23 | Much simpler than the one above, but still adds a new layer (as **it is not a Laravel package**). 24 | 25 | So it's much of the same, doesn't take advantage of the tools that the framework itself already provides like the API resources. Still a very good option thought as its one of the official _The PHP League_ packages, so you'll expect a very good support. -------------------------------------------------------------------------------- /docs/guide/README.md: -------------------------------------------------------------------------------- 1 | ::: danger 2 | **This package won't be receiving any feature updates.** If you didn't see, you should check [our next version of this package clicking here](https://github.com/open-southeners/laravel-apiable). 3 | ::: 4 | 5 | # Introduction 6 | 7 | Install with the following command: 8 | 9 | ```sh 10 | composer require skorelabs/laravel-json-api 11 | ``` 12 | 13 | ## Getting started 14 | 15 | First publish the config file once installed like this: 16 | 17 | ```sh 18 | php artisan vendor:publish --provider="SkoreLabs\JsonApi\JsonApiServiceProvider" 19 | ``` 20 | 21 | And use as simple as importing the class `SkoreLabs\JsonApi\Http\Resources\JsonApiCollection` for collections or `SkoreLabs\JsonApi\Http\Resources\JsonApiResource` for resources. 22 | 23 | ```php 24 | getJson('/posts'); 15 | 16 | $response->assertJsonApi(); 17 | ``` 18 | 19 | [[toc]] 20 | 21 | ### at 22 | 23 | Assert the resource at position of the collection starting by 0. 24 | 25 | ```php 26 | use SkoreLabs\JsonApi\Testing\Assert; 27 | 28 | $response = $this->getJson('/posts'); 29 | 30 | $response->assertJsonApi(function (Assert $jsonApi) { 31 | $json->at(0)->hasAttribute('title', 'Hello world'); 32 | }); 33 | ``` 34 | 35 | ### atRelation 36 | 37 | Assert the related model. 38 | 39 | ```php 40 | use SkoreLabs\JsonApi\Testing\Assert; 41 | 42 | $response = $this->getJson('/posts'); 43 | 44 | $relatedComment = Comment::find(4); 45 | 46 | $response->assertJsonApi(function (Assert $jsonApi) use ($relatedComment) { 47 | $json->at(0)->atRelation($relatedComment)->hasAttribute('content', 'Foo bar'); 48 | }); 49 | ``` 50 | 51 | ### hasAttribute 52 | 53 | Assert the resource has the specified attribute key and value. 54 | 55 | ```php 56 | use SkoreLabs\JsonApi\Testing\Assert; 57 | 58 | $response = $this->getJson('/posts/1'); 59 | 60 | $response->assertJsonApi(function (Assert $jsonApi) { 61 | $json->hasAttribute('title', 'Hello world'); 62 | }); 63 | ``` 64 | 65 | ### hasAttributes 66 | 67 | Assert the resource has the specified attributes keys and values. 68 | 69 | ```php 70 | use SkoreLabs\JsonApi\Testing\Assert; 71 | 72 | $response = $this->getJson('/posts/1'); 73 | 74 | $response->assertJsonApi(function (Assert $jsonApi) { 75 | $json->hasAttributes([ 76 | 'title' => 'Hello world' 77 | 'slug' => 'hello-world' 78 | ]); 79 | }); 80 | ``` 81 | 82 | ### hasId 83 | 84 | Assert the resource has the specified ID (or model key). 85 | 86 | ```php 87 | use SkoreLabs\JsonApi\Testing\Assert; 88 | 89 | $response = $this->getJson('/posts/1'); 90 | 91 | $response->assertJsonApi(function (Assert $jsonApi) { 92 | $json->hasId(1); 93 | }); 94 | ``` 95 | 96 | ### hasType 97 | 98 | Assert the resource has the specified type. 99 | 100 | ```php 101 | use SkoreLabs\JsonApi\Testing\Assert; 102 | 103 | $response = $this->getJson('/posts/1'); 104 | 105 | $response->assertJsonApi(function (Assert $jsonApi) { 106 | $json->hasType('post'); 107 | }); 108 | ``` 109 | 110 | ### hasAttributes 111 | 112 | Assert the resource has the specified attributes keys and values. 113 | 114 | ```php 115 | use SkoreLabs\JsonApi\Testing\Assert; 116 | 117 | $response = $this->getJson('/posts/1'); 118 | 119 | $response->assertJsonApi(function (Assert $jsonApi) { 120 | $json->hasAttributes([ 121 | 'title' => 'Hello world' 122 | 'slug' => 'hello-world' 123 | ]); 124 | }); 125 | ``` 126 | 127 | ### hasAnyRelationships 128 | 129 | Assert that the resource **has any** relationships with the specified **resource type**. 130 | 131 | Second parameter is for assert that the response **includes** the relationship data at the `included`. 132 | 133 | ```php 134 | use SkoreLabs\JsonApi\Testing\Assert; 135 | 136 | $response = $this->getJson('/posts/1'); 137 | 138 | $response->assertJsonApi(function (Assert $jsonApi) { 139 | $json->hasAnyRelationships('comment', true); 140 | }); 141 | ``` 142 | 143 | ### hasNotAnyRelationships 144 | 145 | Assert that the resource **doesn't have any** relationships with the specified **resource type**. 146 | 147 | Second parameter is for assert that the response **doesn't includes** the relationship data at the `included`. 148 | 149 | ```php 150 | use SkoreLabs\JsonApi\Testing\Assert; 151 | 152 | $response = $this->getJson('/posts/2'); 153 | 154 | $response->assertJsonApi(function (Assert $jsonApi) { 155 | $json->hasNotAnyRelationships('comment', true); 156 | }); 157 | ``` 158 | 159 | ### hasRelationshipWith 160 | 161 | Assert that the specific model resource **is a** relationship with the parent resource. 162 | 163 | Second parameter is for assert that the response **includes** the relationship data at the `included`. 164 | 165 | ```php 166 | use SkoreLabs\JsonApi\Testing\Assert; 167 | 168 | $response = $this->getJson('/posts/1'); 169 | 170 | $relatedComment = Comment::find(4); 171 | 172 | $response->assertJsonApi(function (Assert $jsonApi) use ($relatedComment) { 173 | $json->hasRelationshipWith($relatedComment, true); 174 | }); 175 | ``` 176 | 177 | ### hasNotRelationshipWith 178 | 179 | Assert that the specific model resource **is not** a relationship with the parent resource. 180 | 181 | Second parameter is for assert that the response **doesn't includes** the relationship data at the `included`. 182 | 183 | ```php 184 | use SkoreLabs\JsonApi\Testing\Assert; 185 | 186 | $response = $this->getJson('/posts/1'); 187 | 188 | $relatedComment = Comment::find(4); 189 | 190 | $response->assertJsonApi(function (Assert $jsonApi) use ($relatedComment) { 191 | $json->hasRelationshipWith($relatedComment, true); 192 | }); 193 | ``` 194 | -------------------------------------------------------------------------------- /docs/guide/usage.md: -------------------------------------------------------------------------------- 1 | ::: danger 2 | **This package won't be receiving any feature updates.** If you didn't see, you should check [our next version of this package clicking here](https://github.com/open-southeners/laravel-apiable). 3 | ::: 4 | 5 | # Usage 6 | 7 | How to use this on your Laravel website. 8 | 9 | ## Custom resource type 10 | 11 | To customise the resource type of a model you should: 12 | 13 | 1. Add `SkoreLabs\JsonApi\Contracts\JsonApiable` contract to the model class. 14 | 2. And add `resourceType` method to the model returning the type as a string. 15 | 16 | ```php 17 | resource) { 101 | $this->resource->loadMissing('author'); 102 | } 103 | 104 | parent::withRelationships(); 105 | } 106 | 107 | /** 108 | * Attach additional attributes data. 109 | * 110 | * @return array 111 | */ 112 | protected function withAttributes() 113 | { 114 | return [ 115 | 'is_first_visit' => $this->last_accessed_at === null, 116 | $this->mergeWhen(Auth::user() instanceof User && $this->author->id === Auth::id(), [ 117 | 'is_author' => true, 118 | ]), 119 | ]; 120 | } 121 | } 122 | ``` 123 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-json-api", 3 | "private": true, 4 | "repository": "https://d8vjork@github.com/skore/laravel-json-api.git", 5 | "license": "MIT", 6 | "scripts": { 7 | "docs:build": "vuepress build docs", 8 | "docs:clean-dev": "vuepress dev docs --clean-cache", 9 | "docs:dev": "vuepress dev docs" 10 | }, 11 | "devDependencies": { 12 | "@vuepress/plugin-search": "^2.0.0-beta.36", 13 | "vuepress": "^2.0.0-beta.36" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | includes: 2 | - ./vendor/nunomaduro/larastan/extension.neon 3 | 4 | parameters: 5 | 6 | paths: 7 | - src 8 | 9 | # The level 8 is the highest level 10 | level: 5 11 | 12 | ignoreErrors: 13 | - '#Unsafe usage of new static#' 14 | 15 | checkMissingIterableValueType: false 16 | -------------------------------------------------------------------------------- /phpunit.coverage.dist.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 17 | ./src 18 | 19 | 20 | src/Support/Facades 21 | src/Contracts 22 | src/JsonApiServiceProvider.php 23 | src/Testing/TestResponseMacros.php 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | tests 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /phpunit.dist.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 17 | src/ 18 | 19 | 20 | 21 | 22 | tests 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "laravel" 3 | } 4 | -------------------------------------------------------------------------------- /src/Builder.php: -------------------------------------------------------------------------------- 1 | model->getPerPage(); 23 | $clientPerPage = (int) request('page.size', config('json-api.pagination.default_size')); 24 | 25 | if (! $perPage || $perPage < $clientPerPage) { 26 | $perPage = $clientPerPage; 27 | } 28 | 29 | if (class_exists('Hammerstone\FastPaginate\FastPaginate')) { 30 | return $this->fastPaginate($perPage, $columns, $pageNumberKey, $pageNumber); 31 | } 32 | 33 | return $this->paginate($perPage, $columns, $pageNumberKey, $pageNumber); 34 | }; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Concerns/HasConfig.php: -------------------------------------------------------------------------------- 1 | authorise = $this->authorise 26 | ?: $this->getAuthorisableConfig('view') 27 | ?: ! $resource instanceof Model 28 | ?: Gate::check('view', $resource); 29 | 30 | return $this->authorise; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Http/Resources/CollectsResources.php: -------------------------------------------------------------------------------- 1 | collects(); 28 | 29 | $this->collection = $collects && ! $resource->first() instanceof $collects 30 | ? $this->getFiltered($resource, $collects) 31 | : $resource->toBase(); 32 | 33 | return $resource instanceof AbstractPaginator 34 | ? $resource->setCollection($this->collection) 35 | : $this->collection; 36 | } 37 | 38 | /** 39 | * Get resource collection filtered by authorisation. 40 | * 41 | * @param mixed $resource 42 | * @param mixed $collects 43 | * @return \Illuminate\Support\Collection 44 | */ 45 | protected function getFiltered($resource, $collects) 46 | { 47 | if ($resource instanceof AbstractPaginator) { 48 | $resource = $resource->getCollection(); 49 | } 50 | 51 | $collection = $resource->map(function ($item) use ($collects) { 52 | $authoriseKey = 'viewAny'; 53 | $authorise = $this->authorise; 54 | 55 | if (! $this->getAuthorisableConfig($authoriseKey) && gettype($this->authorise) !== 'boolean') { 56 | $authorise = Gate::check($authoriseKey, class_basename($item)); 57 | } 58 | 59 | return new $collects($item, $authorise); 60 | }); 61 | 62 | return $collection->filter(function (JsonApiResource $item) { 63 | return ! $item->resource instanceof MissingValue; 64 | }); 65 | } 66 | 67 | /** 68 | * Get the resource that this resource collects. 69 | * 70 | * @return string|null 71 | */ 72 | protected function collects() 73 | { 74 | if ($this->collects) { 75 | return $this->collects; 76 | } 77 | 78 | if (Str::endsWith(class_basename($this), 'Collection') && 79 | class_exists($class = Str::replaceLast('Collection', '', get_class($this)))) { 80 | return $class; 81 | } 82 | } 83 | 84 | /** 85 | * Get an iterator for the resource collection. 86 | * 87 | * @return \ArrayIterator 88 | */ 89 | public function getIterator() 90 | { 91 | return $this->collection->getIterator(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Http/Resources/CollectsWithIncludes.php: -------------------------------------------------------------------------------- 1 | getIncludedConfig(); 21 | $collectionIncludes = Collection::make( 22 | $this->with[$includedKey] ?? [] 23 | ); 24 | 25 | /** @var \SkoreLabs\JsonApi\Http\Resources\JsonApiResource $jsonResource */ 26 | foreach ($this->collection->toArray() as $jsonResource) { 27 | /** @var \SkoreLabs\JsonApi\Http\Resources\JsonApiResource $resource */ 28 | foreach ($jsonResource->getIncluded() as $resource) { 29 | $collectionIncludes->push($resource); 30 | } 31 | } 32 | 33 | $includesArr = $this->checkUniqueness( 34 | $collectionIncludes 35 | )->values()->all(); 36 | 37 | if (! empty($includesArr)) { 38 | Arr::set($this->with, $includedKey, $includesArr); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Http/Resources/Json/ResourceCollection.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | public $collects; 23 | 24 | /** 25 | * The mapped collection instance. 26 | * 27 | * @var \Illuminate\Support\Collection 28 | */ 29 | public $collection; 30 | 31 | /** 32 | * Indicates if all existing request query parameters should be added to pagination links. 33 | * 34 | * @var bool 35 | */ 36 | protected $preserveQueryParameters = false; 37 | 38 | /** 39 | * The query parameters that should be added to the pagination links. 40 | * 41 | * @var array|null 42 | */ 43 | protected $queryParameters; 44 | 45 | /** 46 | * Create a new resource instance. 47 | * 48 | * @param mixed $resource 49 | * @return void 50 | */ 51 | public function __construct($resource) 52 | { 53 | $this->resource = $this->collectResource($resource); 54 | } 55 | 56 | /** 57 | * Indicate that all current query parameters should be appended to pagination links. 58 | * 59 | * @return $this 60 | */ 61 | public function preserveQuery() 62 | { 63 | $this->preserveQueryParameters = true; 64 | 65 | return $this; 66 | } 67 | 68 | /** 69 | * Specify the query string parameters that should be present on pagination links. 70 | * 71 | * @param array $query 72 | * @return $this 73 | */ 74 | public function withQuery(array $query) 75 | { 76 | $this->preserveQueryParameters = false; 77 | 78 | $this->queryParameters = $query; 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * Return the count of items in the resource collection. 85 | * 86 | * @return int 87 | */ 88 | public function count(): int 89 | { 90 | return $this->collection->count(); 91 | } 92 | 93 | /** 94 | * Transform the resource into a JSON array. 95 | * 96 | * @param \Illuminate\Http\Request $request 97 | * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable 98 | */ 99 | public function toArray($request) 100 | { 101 | return $this->collection->map->toArray($request)->all(); 102 | } 103 | 104 | /** 105 | * Create an HTTP response that represents the object. 106 | * 107 | * @param \Illuminate\Http\Request $request 108 | * @return \Illuminate\Http\JsonResponse 109 | */ 110 | public function toResponse($request) 111 | { 112 | if ($this->resource instanceof AbstractPaginator || $this->resource instanceof AbstractCursorPaginator) { 113 | return $this->preparePaginatedResponse($request); 114 | } 115 | 116 | return parent::toResponse($request); 117 | } 118 | 119 | /** 120 | * Create a paginate-aware HTTP response. 121 | * 122 | * @param \Illuminate\Http\Request $request 123 | * @return \Illuminate\Http\JsonResponse 124 | */ 125 | protected function preparePaginatedResponse($request) 126 | { 127 | if ($this->preserveQueryParameters) { 128 | $this->resource->appends($request->query()); 129 | } elseif ($this->queryParameters !== null) { 130 | $this->resource->appends($this->queryParameters); 131 | } 132 | 133 | return (new PaginatedResourceResponse($this))->toResponse($request); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/Http/Resources/JsonApiCollection.php: -------------------------------------------------------------------------------- 1 | |null $collects 19 | * @return void 20 | */ 21 | public function __construct($resource, $authorise = null, $collects = null) 22 | { 23 | $this->collects = $collects ?: JsonApiResource::class; 24 | $this->authorise = $authorise; 25 | 26 | parent::__construct($resource); 27 | 28 | $this->withIncludes(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Http/Resources/JsonApiResource.php: -------------------------------------------------------------------------------- 1 | authorise = $authorise; 34 | 35 | if ($this->authorize($resource)) { 36 | $this->resource = $resource; 37 | $this->withRelationships(); 38 | } else { 39 | $this->resource = new MissingValue(); 40 | } 41 | } 42 | 43 | /** 44 | * Transform the resource into an array. 45 | * 46 | * @param \Illuminate\Http\Request $request 47 | * @return array 48 | */ 49 | public function toArray($request) 50 | { 51 | if ($this->evaluateResponse()) { 52 | return [ 53 | $this->merge($this->getResourceIdentifier()), 54 | 'attributes' => $this->getAttributes(), 55 | 'relationships' => $this->when($this->relationships, $this->relationships), 56 | ]; 57 | } 58 | 59 | return $this->resource; 60 | } 61 | 62 | /** 63 | * Test response if valid for formatting. 64 | * 65 | * @return bool 66 | */ 67 | protected function evaluateResponse() 68 | { 69 | return ! is_array($this->resource) 70 | && $this->resource !== null 71 | && ! $this->resource instanceof MissingValue; 72 | } 73 | 74 | /** 75 | * Get object identifier "id" and "type". 76 | * 77 | * @return array 78 | */ 79 | public function getResourceIdentifier() 80 | { 81 | return [ 82 | $this->resource->getKeyName() => (string) $this->resource->getKey(), 83 | 'type' => JsonApi::getResourceType($this->resource), 84 | ]; 85 | } 86 | 87 | /** 88 | * Get filtered attributes excluding all the ids. 89 | * 90 | * @return array 91 | */ 92 | protected function getAttributes() 93 | { 94 | return array_filter( 95 | array_merge($this->resource->attributesToArray(), $this->withAttributes()), 96 | function ($value, $key) { 97 | return ! Str::endsWith($key, '_id') && $key !== $this->resource->getKeyName() && $value !== null; 98 | }, 99 | ARRAY_FILTER_USE_BOTH 100 | ); 101 | } 102 | 103 | /** 104 | * Attach additional attributes data. 105 | * 106 | * @return array 107 | */ 108 | protected function withAttributes() 109 | { 110 | return []; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Http/Resources/RelationshipsWithIncludes.php: -------------------------------------------------------------------------------- 1 | resource instanceof Model) { 33 | $this->attachRelations($this->resource); 34 | } 35 | } 36 | 37 | /** 38 | * Attach relationships to the resource. 39 | * 40 | * @param \Illuminate\Database\Eloquent\Model $model 41 | * @return void 42 | */ 43 | protected function attachRelations(Model $model) 44 | { 45 | $relations = array_filter($model->getRelations(), static function ($value, $key) { 46 | return $key !== 'pivot' ?: (bool) $value === false; 47 | }, ARRAY_FILTER_USE_BOTH); 48 | 49 | foreach ($relations as $relation => $relationObj) { 50 | if (config('json-api.normalize_relations', false)) { 51 | $relation = Str::snake($relation); 52 | } 53 | 54 | if ($relationObj instanceof DatabaseCollection) { 55 | /** @var \Illuminate\Database\Eloquent\Model $relationModel */ 56 | foreach ($relationObj->all() as $relationModel) { 57 | $this->relationships[$relation]['data'][] = $this->processModelRelation( 58 | $relationModel 59 | ); 60 | } 61 | } 62 | 63 | if ($relationObj instanceof Model) { 64 | $this->relationships[$relation]['data'] = $this->processModelRelation( 65 | $relationObj 66 | ); 67 | } 68 | } 69 | } 70 | 71 | /** 72 | * Process a model relation attaching to its model additional attributes. 73 | * 74 | * @param \Illuminate\Database\Eloquent\Model $model 75 | * @return array 76 | */ 77 | protected function processModelRelation(Model $model) 78 | { 79 | $modelResourceClass = $this->getModelResource($model); 80 | /** @var \SkoreLabs\JsonApi\Http\Resources\JsonApiResource $modelResource */ 81 | $modelResource = new $modelResourceClass($model, $this->authorise); 82 | $modelIdentifier = $modelResource->getResourceIdentifier(); 83 | 84 | if (! empty(Arr::get($modelIdentifier, $model->getKeyName(), null))) { 85 | $this->addIncluded($modelResource); 86 | 87 | return $modelIdentifier; 88 | } 89 | 90 | return []; 91 | } 92 | 93 | /** 94 | * Set included data to resource's with. 95 | * 96 | * @param $resource 97 | * @return void 98 | */ 99 | protected function addIncluded(JsonApiResource $resource) 100 | { 101 | $includesCol = Collection::make([ 102 | $resource, 103 | array_values($this->getIncluded()), 104 | array_values($resource->getIncluded()), 105 | ])->flatten(); 106 | 107 | $includesArr = $this->checkUniqueness( 108 | $includesCol 109 | )->values()->all(); 110 | 111 | if (! empty($includesArr)) { 112 | Arr::set($this->with, $this->getIncludedConfig(), $includesArr); 113 | } 114 | } 115 | 116 | /** 117 | * Get resource included relationships. 118 | * 119 | * @return array 120 | */ 121 | public function getIncluded() 122 | { 123 | return $this->with[$this->getIncludedConfig()] ?? []; 124 | } 125 | 126 | /** 127 | * Check and return unique resources on a collection. 128 | * 129 | * @param \Illuminate\Support\Collection 130 | * @return \Illuminate\Support\Collection 131 | */ 132 | protected function checkUniqueness(Collection $collection) 133 | { 134 | return $collection->unique(static function ($resource) { 135 | return implode('', $resource->getResourceIdentifier()); 136 | }); 137 | } 138 | 139 | /** 140 | * Get API resource from model. 141 | * 142 | * @param \Illuminate\Database\Eloquent\Model $model 143 | * @return string 144 | */ 145 | protected function getModelResource(Model $model) 146 | { 147 | return defined(get_class($model).'::JSON_SERIALIZER') 148 | ? $model::JSON_SERIALIZER 149 | : JsonApiResource::class; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/JsonApiServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->runningInConsole()) { 23 | $this->publishes([ 24 | __DIR__.'/../config/json-api.php' => config_path('json-api.php'), 25 | ], 'config'); 26 | } 27 | } 28 | 29 | /** 30 | * Register any application services. 31 | * 32 | * @return void 33 | */ 34 | public function register() 35 | { 36 | Builder::mixin(new JsonApiBuilder()); 37 | 38 | $this->mergeConfigFrom(__DIR__.'/../config/json-api.php', 'json-api'); 39 | 40 | $this->app->singleton('json-api', function () { 41 | return new JsonApi(); 42 | }); 43 | 44 | $this->registerTestingMacros(); 45 | } 46 | 47 | protected function registerTestingMacros() 48 | { 49 | if (class_exists(TestResponse::class)) { 50 | TestResponse::mixin(new TestResponseMacros()); 51 | 52 | return; 53 | } 54 | 55 | // Laravel <= 6.0 56 | if (class_exists(LegacyTestResponse::class)) { 57 | LegacyTestResponse::mixin(new TestResponseMacros()); 58 | 59 | return; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Support/Facades/JsonApi.php: -------------------------------------------------------------------------------- 1 | resourceType(); 39 | } 40 | 41 | return Str::snake(class_basename(is_string($model) ? $model : get_class($model))); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Testing/Assert.php: -------------------------------------------------------------------------------- 1 | id = $id; 30 | $this->type = $type; 31 | 32 | $this->attributes = $attributes; 33 | $this->relationships = $relationships; 34 | $this->includeds = $includeds; 35 | 36 | $this->collection = $collection; 37 | } 38 | 39 | public static function fromTestResponse($response) 40 | { 41 | try { 42 | $content = json_decode($response->getContent(), true); 43 | PHPUnit::assertArrayHasKey('data', $content); 44 | $data = $content['data']; 45 | $collection = []; 46 | 47 | if (static::isCollection($data)) { 48 | $collection = $data; 49 | $data = head($data); 50 | } 51 | 52 | PHPUnit::assertIsArray($data); 53 | PHPUnit::assertArrayHasKey('id', $data); 54 | PHPUnit::assertArrayHasKey('type', $data); 55 | PHPUnit::assertArrayHasKey('attributes', $data); 56 | PHPUnit::assertIsArray($data['attributes']); 57 | } catch (AssertionFailedError $e) { 58 | PHPUnit::fail('Not a valid JSON:API response or response data is empty.'); 59 | } 60 | 61 | return new self($data['id'], $data['type'], $data['attributes'], $data['relationships'] ?? [], $content['included'] ?? [], $collection); 62 | } 63 | 64 | /** 65 | * Get the instance as an array. 66 | * 67 | * @return array 68 | */ 69 | public function toArray(): array 70 | { 71 | return $this->attributes; 72 | } 73 | 74 | /** 75 | * Check if data contains a collection of resources. 76 | * 77 | * @param array $data 78 | * @return bool 79 | */ 80 | public static function isCollection(array $data = []) 81 | { 82 | return ! array_key_exists('attributes', $data); 83 | } 84 | 85 | /** 86 | * Get the identifier in a pretty printable message by id and type. 87 | * 88 | * @param mixed $id 89 | * @param string $type 90 | * @return string 91 | */ 92 | protected function getIdentifierMessageFor($id = null, string $type = null) 93 | { 94 | $messagePrefix = '{ id: %s, type: "%s" }'; 95 | 96 | if (! $id && ! $type) { 97 | return sprintf($messagePrefix.' at position %d', (string) $this->id, $this->type, $this->atPosition); 98 | } 99 | 100 | return sprintf($messagePrefix, (string) $id, $type); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Testing/Concerns/HasAttributes.php: -------------------------------------------------------------------------------- 1 | |string $value 22 | * @return $this 23 | */ 24 | public function hasAttribute($name, $value = null) 25 | { 26 | PHPUnit::assertArrayHasKey($name, $this->attributes, sprintf('JSON:API response does not have an attribute named "%s"', $name)); 27 | 28 | if ($value) { 29 | PHPUnit::assertContains($value, $this->attributes, sprintf('JSON:API response does not have an attribute named "%s" with value "%s"', $name, json_encode($value))); 30 | } 31 | 32 | return $this; 33 | } 34 | 35 | /** 36 | * Assert that a resource has an array of attributes with names and values (optional). 37 | * 38 | * @param mixed $attributes 39 | * @return $this 40 | */ 41 | public function hasAttributes($attributes) 42 | { 43 | foreach ($attributes as $name => $value) { 44 | $this->hasAttribute($name, $value); 45 | } 46 | 47 | return $this; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Testing/Concerns/HasCollections.php: -------------------------------------------------------------------------------- 1 | collection)) { 26 | PHPUnit::fail(sprintf('There is no item at position "%d" on the collection response.', $position)); 27 | } 28 | 29 | $data = $this->collection[$position]; 30 | 31 | $this->atPosition = $position; 32 | 33 | return new self($data['id'], $data['type'], $data['attributes'], $data['relationships'] ?? [], $this->includeds, $this->collection); 34 | } 35 | 36 | /** 37 | * Assert the number of resources that are at the collection. 38 | * 39 | * @param int $value 40 | * @return $this 41 | */ 42 | public function count(int $value) 43 | { 44 | PHPUnit::assertCount($value, $this->collection, sprintf('The collection size is not same as "%d"', $value)); 45 | 46 | return $this; 47 | } 48 | 49 | /** 50 | * Assert the number of resources that are at the collection (alias of count). 51 | * 52 | * @param int $value 53 | * @return $this 54 | */ 55 | public function hasSize(int $value) 56 | { 57 | return $this->count($value); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Testing/Concerns/HasIdentifications.php: -------------------------------------------------------------------------------- 1 | id === $value, sprintf('JSON:API response does not have id "%s"', $value)); 33 | 34 | return $this; 35 | } 36 | 37 | /** 38 | * Check that a resource has the specified type. 39 | * 40 | * @param mixed $value 41 | * @return $this 42 | */ 43 | public function hasType($value) 44 | { 45 | PHPUnit::assertSame($this->type, $value, sprintf('JSON:API response does not have type "%s"', $value)); 46 | 47 | return $this; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Testing/Concerns/HasRelationships.php: -------------------------------------------------------------------------------- 1 | includeds, function ($included) use ($model) { 33 | return $included['type'] === JsonApi::getResourceType($model) && $included['id'] == $model->getKey(); 34 | })); 35 | 36 | return new self($item['id'], $item['type'], $item['attributes'], $item['relationships'] ?? [], $this->includeds); 37 | } 38 | 39 | /** 40 | * Assert that a resource has any relationship and included (optional) by type. 41 | * 42 | * @param mixed $name 43 | * @param bool $withIncluded 44 | * @return $this 45 | */ 46 | public function hasAnyRelationships($name, $withIncluded = false) 47 | { 48 | $type = JsonApi::getResourceType($name); 49 | 50 | PHPUnit::assertTrue( 51 | count($this->filterResources($this->relationships, $type)) > 0, 52 | sprintf('There is not any relationship with type "%s"', $type) 53 | ); 54 | 55 | if ($withIncluded) { 56 | PHPUnit::assertTrue( 57 | count($this->filterResources($this->includeds, $type)) > 0, 58 | sprintf('There is not any relationship with type "%s"', $type) 59 | ); 60 | } 61 | 62 | return $this; 63 | } 64 | 65 | /** 66 | * Assert that a resource does not have any relationship and included (optional) by type. 67 | * 68 | * @param mixed $name 69 | * @param bool $withIncluded 70 | * @return $this 71 | */ 72 | public function hasNotAnyRelationships($name, $withIncluded = false) 73 | { 74 | $type = JsonApi::getResourceType($name); 75 | 76 | PHPUnit::assertFalse( 77 | count($this->filterResources($this->relationships, $type)) > 0, 78 | sprintf('There is a relationship with type "%s" for resource "%s"', $type, $this->getIdentifierMessageFor()) 79 | ); 80 | 81 | if ($withIncluded) { 82 | PHPUnit::assertFalse( 83 | count($this->filterResources($this->includeds, $type)) > 0, 84 | sprintf('There is a included relationship with type "%s"', $type) 85 | ); 86 | } 87 | 88 | return $this; 89 | } 90 | 91 | /** 92 | * Assert that a resource has any relationship and included (optional) by model instance. 93 | * 94 | * @param \Illuminate\Database\Eloquent\Model $model 95 | * @param bool $withIncluded 96 | * @return $this 97 | */ 98 | public function hasRelationshipWith(Model $model, $withIncluded = false) 99 | { 100 | $type = JsonApi::getResourceType($model); 101 | 102 | PHPUnit::assertTrue( 103 | count($this->filterResources($this->relationships, $type, $model->getKey())) > 0, 104 | sprintf('There is no relationship "%s" for resource "%s"', $this->getIdentifierMessageFor($model->getKey(), $type), $this->getIdentifierMessageFor()) 105 | ); 106 | 107 | if ($withIncluded) { 108 | PHPUnit::assertTrue( 109 | count($this->filterResources($this->includeds, $type, $model->getKey())) > 0, 110 | sprintf('There is no included relationship "%s"', $this->getIdentifierMessageFor($model->getKey(), $type)) 111 | ); 112 | } 113 | 114 | return $this; 115 | } 116 | 117 | /** 118 | * Assert that a resource does not have any relationship and included (optional) by model instance. 119 | * 120 | * @param \Illuminate\Database\Eloquent\Model $model 121 | * @param bool $withIncluded 122 | * @return $this 123 | */ 124 | public function hasNotRelationshipWith(Model $model, $withIncluded = false) 125 | { 126 | $type = JsonApi::getResourceType($model); 127 | 128 | PHPUnit::assertFalse( 129 | count($this->filterResources($this->relationships, $type, $model->getKey())) > 0, 130 | sprintf('There is a relationship "%s" for resource "%s"', $this->getIdentifierMessageFor($model->getKey(), $type), $this->getIdentifierMessageFor()) 131 | ); 132 | 133 | if ($withIncluded) { 134 | PHPUnit::assertFalse( 135 | count($this->filterResources($this->includeds, $type, $model->getKey())) > 0, 136 | sprintf('There is a included relationship "%s"', $this->getIdentifierMessageFor($model->getKey(), $type)) 137 | ); 138 | } 139 | 140 | return $this; 141 | } 142 | 143 | /** 144 | * Filter array of resources by a provided identifier. 145 | * 146 | * @param array $resources 147 | * @param string $type 148 | * @param mixed $id 149 | * @return array 150 | */ 151 | protected function filterResources(array $resources, string $type, $id = null) 152 | { 153 | return array_filter($resources, function ($resource) use ($type, $id) { 154 | return $this->filterResourceWithIdentifier($resource, $type, $id); 155 | }); 156 | } 157 | 158 | /** 159 | * Filter provided resource with given identifier. 160 | * 161 | * @param array $resource 162 | * @param string $type 163 | * @param mixed $id 164 | * @return bool 165 | */ 166 | protected function filterResourceWithIdentifier(array $resource, string $type, $id = null) 167 | { 168 | if (is_array($resource) && ! isset($resource['type'])) { 169 | return count($this->filterResources($resource, $type, $id)) > 0; 170 | } 171 | 172 | $condition = $resource['type'] === $type; 173 | 174 | if ($id) { 175 | $condition &= $resource['id'] == $id; 176 | } 177 | 178 | return (bool) $condition; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/Testing/TestResponseMacros.php: -------------------------------------------------------------------------------- 1 | belongsTo(self::class); 31 | } 32 | 33 | /** 34 | * Get its author user. 35 | * 36 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 37 | */ 38 | public function author() 39 | { 40 | return $this->belongsTo(User::class, 'user_id'); 41 | } 42 | 43 | /** 44 | * Get its tags. 45 | * 46 | * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 47 | */ 48 | public function tags() 49 | { 50 | return $this->belongsToMany(Tag::class); 51 | } 52 | 53 | /** 54 | * Return whether the post is published. 55 | * 56 | * @return bool 57 | */ 58 | public function getIsPublishedAttribute() 59 | { 60 | return true; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/Fixtures/Tag.php: -------------------------------------------------------------------------------- 1 | hasMany(Post::class); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/JsonApiAuthorisationTest.php: -------------------------------------------------------------------------------- 1 | loadMigrationsFrom(__DIR__.'/database/migrations'); 23 | } 24 | 25 | /** 26 | * Setup the test environment. 27 | * 28 | * @return void 29 | */ 30 | protected function setUp(): void 31 | { 32 | parent::setUp(); 33 | 34 | Gate::define('view', function (User $user, Post $post) { 35 | return $post->user_id === $user->id; 36 | }); 37 | 38 | Route::get('/', function () { 39 | return new JsonApiCollection(Post::with(['parent', 'author'])->whereNotNull('parent_id')->get(), true); 40 | }); 41 | 42 | Route::get('/restricted', function () { 43 | return new JsonApiCollection(Post::with(['parent', 'author'])->whereNotNull('parent_id')->get()); 44 | }); 45 | } 46 | 47 | public function test_resource_relationships_are_all_visible_when_bypassed() 48 | { 49 | $user = User::create([ 50 | 'name' => 'Ruben', 51 | 'email' => 'ruben@wonderland.com', 52 | 'password' => 'secret', 53 | ]); 54 | 55 | $firstPost = Post::create([ 56 | 'id' => 5, 57 | 'title' => 'Test Title', 58 | 'user_id' => User::create([ 59 | 'name' => 'Another', 60 | 'email' => 'another@wonderland.com', 61 | 'password' => 'secret', 62 | ])->id, 63 | ]); 64 | 65 | $secondPost = Post::create([ 66 | 'id' => 6, 67 | 'title' => 'Test Title 2', 68 | 'user_id' => $user->id, 69 | 'parent_id' => $firstPost->id, 70 | ]); 71 | 72 | $thirdAndMyPost = Post::create([ 73 | 'id' => 7, 74 | 'title' => 'Test Title 3', 75 | 'user_id' => $user->id, 76 | 'parent_id' => $secondPost->id, 77 | ]); 78 | 79 | $this->actingAs($user); 80 | 81 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) use ($firstPost, $secondPost) { 82 | $jsonApi->at(0)->hasRelationshipWith($firstPost, true); 83 | $jsonApi->at(1)->hasRelationshipWith($secondPost, true); 84 | }); 85 | } 86 | 87 | public function test_resource_relationships_are_normally_some_invisible() 88 | { 89 | $this->markTestSkipped('Not here yet, really need major release!'); 90 | 91 | $user = User::create([ 92 | 'name' => 'Ruben', 93 | 'email' => 'ruben@wonderland.com', 94 | 'password' => 'secret', 95 | ]); 96 | 97 | $firstPost = Post::create([ 98 | 'id' => 5, 99 | 'title' => 'Test Title', 100 | 'user_id' => User::create([ 101 | 'name' => 'Another', 102 | 'email' => 'another@wonderland.com', 103 | 'password' => 'secret', 104 | ])->id, 105 | ]); 106 | 107 | $secondPost = Post::create([ 108 | 'id' => 6, 109 | 'title' => 'Test Title 2', 110 | 'user_id' => $user->id, 111 | 'parent_id' => $firstPost->id, 112 | ]); 113 | 114 | $thirdAndMyPost = Post::create([ 115 | 'id' => 7, 116 | 'title' => 'Test Title 3', 117 | 'user_id' => $user->id, 118 | 'parent_id' => $secondPost->id, 119 | ]); 120 | 121 | $this->actingAs($user); 122 | 123 | $response = $this->get('/restricted', ['Accept' => 'application/json']); 124 | 125 | $response->assertJsonApi(function (Assert $jsonApi) use ($firstPost, $secondPost) { 126 | $jsonApi->count(2); 127 | 128 | $jsonApi->at(0)->hasNotRelationshipWith($firstPost, true); 129 | $jsonApi->at(1)->hasRelationshipWith($secondPost, true); 130 | }); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /tests/JsonApiCollectionTest.php: -------------------------------------------------------------------------------- 1 | bypassPolicies(); 23 | 24 | Route::get('/', function () { 25 | return JsonApi::format(collect([ 26 | new Post([ 27 | 'id' => 5, 28 | 'title' => 'Test Title', 29 | 'abstract' => 'Test abstract', 30 | ]), 31 | new Post([ 32 | 'id' => 6, 33 | 'title' => 'Test Title 2', 34 | ]), 35 | ])); 36 | }); 37 | } 38 | 39 | public function testCollectionsMayBeConvertedToJsonApi() 40 | { 41 | $response = $this->get('/', ['Accept' => 'application/json']); 42 | 43 | $response->assertStatus(200); 44 | 45 | $response->assertJson([ 46 | 'data' => [ 47 | [ 48 | 'id' => '5', 49 | 'type' => 'post', 50 | 'attributes' => [ 51 | 'title' => 'Test Title', 52 | 'abstract' => 'Test abstract', 53 | ], 54 | ], 55 | [ 56 | 'id' => '6', 57 | 'type' => 'post', 58 | 'attributes' => [ 59 | 'title' => 'Test Title 2', 60 | ], 61 | ], 62 | ], 63 | ], true); 64 | } 65 | 66 | public function testCollectionsAtHasAttribute() 67 | { 68 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) { 69 | $jsonApi->at(0)->hasAttribute('title', 'Test Title'); 70 | 71 | $jsonApi->at(1)->hasAttribute('title', 'Test Title 2'); 72 | }); 73 | } 74 | 75 | public function testCollectionsTakeByDefaultFirstItem() 76 | { 77 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) { 78 | $jsonApi->hasAttribute('title', 'Test Title'); 79 | }); 80 | } 81 | 82 | public function testCollectionsHasSize() 83 | { 84 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) { 85 | $jsonApi->hasSize(2); 86 | }); 87 | } 88 | 89 | public function testCollectionsAtUnreachablePosition() 90 | { 91 | $this->expectException(AssertionFailedError::class); 92 | 93 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) { 94 | $jsonApi->at(10); 95 | }); 96 | } 97 | 98 | public function testCollectionsToArrayReturnsArray() 99 | { 100 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) { 101 | $responseArray = $jsonApi->toArray(); 102 | 103 | $this->assertIsArray($responseArray); 104 | $this->assertFalse(empty($responseArray), 'toArray() should not be empty'); 105 | }); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /tests/JsonApiPaginationTest.php: -------------------------------------------------------------------------------- 1 | 'Test Title']); 29 | Post::create(['title' => 'Test Title 2']); 30 | Post::create(['title' => 'Test Title 3']); 31 | Post::create(['title' => 'Test Title 4']); 32 | 33 | return JsonApiCollection::make(Post::jsonPaginate(1), true); 34 | }); 35 | } 36 | 37 | protected function defineDatabaseMigrations() 38 | { 39 | $this->loadMigrationsFrom(__DIR__.'/database/migrations'); 40 | } 41 | 42 | public function testJsonApiPaginationWithPageSize() 43 | { 44 | $response = $this->getJson('/posts?page[size]=2'); 45 | 46 | $response->assertJsonApi(function (Assert $jsonApi) { 47 | $jsonApi->hasSize(2); 48 | }); 49 | 50 | $response->assertStatus(200); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/JsonApiRelationshipsTest.php: -------------------------------------------------------------------------------- 1 | bypassPolicies(); 44 | } 45 | 46 | public function testCollectionHasAnyClientAuthorRelationship() 47 | { 48 | Route::get('/', function () { 49 | $this->authoredPost = new Post([ 50 | 'id' => 5, 51 | 'title' => 'Test Title', 52 | 'abstract' => 'Test abstract', 53 | ]); 54 | 55 | $this->authoredPost->setRelation('author', new User([ 56 | 'id' => 1, 57 | 'name' => 'Myself', 58 | 'email' => 'me@internet.org', 59 | 'password' => '1234', 60 | ])); 61 | 62 | $this->lonelyPost = new Post([ 63 | 'id' => 6, 64 | 'title' => 'Test Title 2', 65 | ]); 66 | 67 | return JsonApi::format(collect([ 68 | $this->authoredPost, 69 | $this->lonelyPost, 70 | ])); 71 | }); 72 | 73 | $response = $this->get('/', ['Accept' => 'application/json']); 74 | 75 | $response->assertSuccessful(); 76 | 77 | $response->assertJsonApi(function (Assert $jsonApi) { 78 | $jsonApi->hasAnyRelationships('client', true) 79 | ->hasNotAnyRelationships('post', true); 80 | 81 | $jsonApi->at(0)->hasNotRelationshipWith($this->lonelyPost, true); 82 | }); 83 | } 84 | 85 | /** 86 | * @group requiresDatabase 87 | */ 88 | public function testResourceHasTagsRelationships() 89 | { 90 | // TODO: setRelation method doesn't work with hasMany relationships, so need migrations loaded 91 | $this->loadMigrationsFrom(__DIR__.'/database/migrations'); 92 | 93 | Route::get('/', function () { 94 | $this->authoredPost = Post::create([ 95 | 'title' => 'Test Title', 96 | ]); 97 | 98 | $this->lonelyTag = Tag::create([ 99 | 'name' => 'Lifestyle', 100 | 'slug' => 'lifestyle', 101 | ]); 102 | 103 | $this->postTag = Tag::create([ 104 | 'name' => 'News', 105 | 'slug' => 'news', 106 | ]); 107 | 108 | $anotherTag = Tag::create([ 109 | 'name' => 'International', 110 | 'slug' => 'international', 111 | ]); 112 | 113 | $this->authoredPost->tags()->attach([ 114 | $this->postTag->id, 115 | $anotherTag->id, 116 | ]); 117 | 118 | $this->authoredPost->author()->associate( 119 | User::create([ 120 | 'name' => 'Myself', 121 | 'email' => 'me@internet.org', 122 | 'password' => '1234', 123 | ])->id 124 | ); 125 | 126 | $this->authoredPost->save(); 127 | 128 | return JsonApi::format($this->authoredPost->refresh()->loadMissing('author', 'tags')); 129 | }); 130 | 131 | $response = $this->get('/', ['Accept' => 'application/json']); 132 | 133 | $response->assertSuccessful(); 134 | 135 | $response->assertJsonApi(function (Assert $jsonApi) { 136 | $jsonApi->hasRelationshipWith($this->postTag, true) 137 | ->hasNotRelationshipWith($this->lonelyTag, true); 138 | }); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /tests/JsonApiResourceTest.php: -------------------------------------------------------------------------------- 1 | bypassPolicies(); 17 | 18 | Route::get('/', function () { 19 | return JsonApi::format(new Post([ 20 | 'id' => 5, 21 | 'title' => 'Test Title', 22 | 'abstract' => 'Test abstract', 23 | ])); 24 | }); 25 | 26 | $response = $this->get('/', ['Accept' => 'application/json']); 27 | 28 | $response->assertStatus(200); 29 | 30 | $response->assertJson([ 31 | 'data' => [ 32 | 'id' => '5', 33 | 'type' => 'post', 34 | 'attributes' => [ 35 | 'title' => 'Test Title', 36 | 'abstract' => 'Test abstract', 37 | ], 38 | ], 39 | ], true); 40 | } 41 | 42 | public function testResourcesHasIdentifier() 43 | { 44 | $this->bypassPolicies(); 45 | 46 | Route::get('/', function () { 47 | return JsonApi::format(new Post([ 48 | 'id' => 5, 49 | 'title' => 'Test Title', 50 | 'abstract' => 'Test abstract', 51 | ])); 52 | }); 53 | 54 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) { 55 | $jsonApi->hasId(5)->hasType('post'); 56 | }); 57 | } 58 | 59 | public function testResourcesHasAttribute() 60 | { 61 | $this->bypassPolicies(); 62 | 63 | Route::get('/', function () { 64 | return JsonApi::format(new Post([ 65 | 'id' => 5, 66 | 'title' => 'Test Title', 67 | 'abstract' => 'Test abstract', 68 | ])); 69 | }); 70 | 71 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) { 72 | $jsonApi->hasAttribute('title', 'Test Title'); 73 | }); 74 | } 75 | 76 | public function testResourcesHasAttributes() 77 | { 78 | $this->bypassPolicies(); 79 | 80 | Route::get('/', function () { 81 | return JsonApi::format(new Post([ 82 | 'id' => 5, 83 | 'title' => 'Test Title', 84 | 'abstract' => 'Test abstract', 85 | ])); 86 | }); 87 | 88 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) { 89 | $jsonApi->hasAttributes([ 90 | 'title' => 'Test Title', 91 | 'abstract' => 'Test abstract', 92 | ]); 93 | }); 94 | } 95 | 96 | // FIXME: Not available in Laravel 6, wait to support removal 97 | // public function testResourcesMayBeConvertedToJsonApiWithToJsonMethod() 98 | // { 99 | // $resource = JsonApi::format(new Post([ 100 | // 'id' => 5, 101 | // 'title' => 'Test Title', 102 | // 'abstract' => 'Test abstract', 103 | // ]), true); 104 | 105 | // $this->assertSame('{"id":"5","type":"post","attributes":{"title":"Test Title","abstract":"Test abstract"}}', $resource->toJson()); 106 | // } 107 | 108 | public function testResourcesWithRelationshipsMayBeConvertedToJsonApi() 109 | { 110 | $this->bypassPolicies(); 111 | 112 | Route::get('/', function () { 113 | $post = new Post([ 114 | 'id' => 5, 115 | 'title' => 'Test Title', 116 | 'abstract' => 'Test abstract', 117 | ]); 118 | 119 | $post->setRelation('parent', new Post([ 120 | 'id' => 4, 121 | 'title' => 'Test Parent Title', 122 | ])); 123 | 124 | return JsonApi::format($post); 125 | }); 126 | 127 | $response = $this->get('/', ['Accept' => 'application/json']); 128 | 129 | $response->assertStatus(200); 130 | 131 | $response->assertJson([ 132 | 'data' => [ 133 | 'id' => '5', 134 | 'type' => 'post', 135 | 'attributes' => [ 136 | 'title' => 'Test Title', 137 | 'abstract' => 'Test abstract', 138 | ], 139 | 'relationships' => [ 140 | 'parent' => [ 141 | 'data' => [ 142 | 'id' => '4', 143 | 'type' => 'post', 144 | ], 145 | ], 146 | ], 147 | ], 148 | 'included' => [ 149 | [ 150 | 'id' => '4', 151 | 'type' => 'post', 152 | 'attributes' => [ 153 | 'title' => 'Test Parent Title', 154 | ], 155 | ], 156 | ], 157 | ], true); 158 | } 159 | 160 | public function testResourcesHasRelationshipWith() 161 | { 162 | $this->bypassPolicies(); 163 | 164 | Route::get('/', function () { 165 | $post = new Post([ 166 | 'id' => 5, 167 | 'title' => 'Test Title', 168 | 'abstract' => 'Test abstract', 169 | ]); 170 | 171 | $post->setRelation('parent', new Post([ 172 | 'id' => 4, 173 | 'title' => 'Test Parent Title', 174 | ])); 175 | 176 | return JsonApi::format($post); 177 | }); 178 | 179 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) { 180 | $jsonApi->hasRelationshipWith(new Post([ 181 | 'id' => 4, 182 | 'title' => 'Test Parent Title', 183 | ]), true); 184 | }); 185 | } 186 | 187 | public function testResourcesAtRelationHasAttribute() 188 | { 189 | $this->bypassPolicies(); 190 | 191 | Route::get('/', function () { 192 | $post = new Post([ 193 | 'id' => 5, 194 | 'title' => 'Test Title', 195 | 'abstract' => 'Test abstract', 196 | ]); 197 | 198 | $post->setRelation('parent', new Post([ 199 | 'id' => 4, 200 | 'title' => 'Test Parent Title', 201 | ])); 202 | 203 | return JsonApi::format($post); 204 | }); 205 | 206 | $this->get('/', ['Accept' => 'application/json'])->assertJsonApi(function (Assert $jsonApi) { 207 | $jsonApi->atRelation(new Post([ 208 | 'id' => 4, 209 | 'title' => 'Test Parent Title', 210 | ]))->hasAttribute('title', 'Test Parent Title'); 211 | }); 212 | } 213 | 214 | public function testResourcesMayNotBeConvertedToJsonApiWithoutPermissions() 215 | { 216 | Route::get('/', function () { 217 | return JsonApi::format(new Post([ 218 | 'id' => 5, 219 | 'title' => 'Test Title', 220 | ])); 221 | }); 222 | 223 | $response = $this->get('/', ['Accept' => 'application/json']); 224 | 225 | $response->assertStatus(200); 226 | 227 | $response->assertExactJson([ 228 | 'data' => [], 229 | ]); 230 | } 231 | 232 | public function testResourcesMayReturnEmptyDataWhenMissingIsGiven() 233 | { 234 | Route::get('/', function () { 235 | return JsonApi::format(new MissingValue()); 236 | }); 237 | 238 | $response = $this->get('/', ['Accept' => 'application/json']); 239 | 240 | $response->assertStatus(200); 241 | 242 | $response->assertExactJson([ 243 | 'data' => [], 244 | ]); 245 | 246 | $this->expectException(AssertionFailedError::class); 247 | 248 | $response->assertJsonApi(); 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'view' => true, 22 | 'viewAny' => true, 23 | ], 24 | ]); 25 | 26 | return $this; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/database/migrations/0000_00_00_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | bigInteger('id')->primary(); 18 | $table->string('name'); 19 | $table->string('email')->unique(); 20 | $table->string('password'); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('users'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/database/migrations/0000_00_00_000001_create_posts_table.php: -------------------------------------------------------------------------------- 1 | bigInteger('id')->primary(); 18 | $table->string('title'); 19 | $table->unsignedBigInteger('user_id')->nullable(); 20 | $table->unsignedBigInteger('parent_id')->nullable(); 21 | $table->timestamps(); 22 | 23 | $table->foreign('user_id')->references('id')->on('users'); 24 | $table->foreign('parent_id')->references('id')->on('posts'); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::dropIfExists('posts'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/database/migrations/0000_00_00_000002_create_tags_table.php: -------------------------------------------------------------------------------- 1 | bigInteger('id')->primary(); 18 | $table->string('name'); 19 | $table->string('slug')->unique(); 20 | $table->timestamps(); 21 | }); 22 | 23 | Schema::create('post_tag', static function (Blueprint $table) { 24 | $table->bigInteger('id')->primary(); 25 | $table->unsignedBigInteger('post_id')->nullable(); 26 | $table->unsignedBigInteger('tag_id')->nullable(); 27 | 28 | $table->foreign('post_id')->references('id')->on('posts'); 29 | $table->foreign('tag_id')->references('id')->on('tags'); 30 | }); 31 | } 32 | 33 | /** 34 | * Reverse the migrations. 35 | * 36 | * @return void 37 | */ 38 | public function down() 39 | { 40 | Schema::dropIfExists('post_tag'); 41 | Schema::dropIfExists('tags'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/parser@^7.16.4": 6 | version "7.17.8" 7 | resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" 8 | integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== 9 | 10 | "@nodelib/fs.scandir@2.1.5": 11 | version "2.1.5" 12 | resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" 13 | integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== 14 | dependencies: 15 | "@nodelib/fs.stat" "2.0.5" 16 | run-parallel "^1.1.9" 17 | 18 | "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": 19 | version "2.0.5" 20 | resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" 21 | integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 22 | 23 | "@nodelib/fs.walk@^1.2.3": 24 | version "1.2.8" 25 | resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" 26 | integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== 27 | dependencies: 28 | "@nodelib/fs.scandir" "2.1.5" 29 | fastq "^1.6.0" 30 | 31 | "@types/debug@^4.1.7": 32 | version "4.1.7" 33 | resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" 34 | integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== 35 | dependencies: 36 | "@types/ms" "*" 37 | 38 | "@types/fs-extra@^9.0.13": 39 | version "9.0.13" 40 | resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45" 41 | integrity sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA== 42 | dependencies: 43 | "@types/node" "*" 44 | 45 | "@types/hash-sum@^1.0.0": 46 | version "1.0.0" 47 | resolved "https://registry.yarnpkg.com/@types/hash-sum/-/hash-sum-1.0.0.tgz#838f4e8627887d42b162d05f3d96ca636c2bc504" 48 | integrity sha512-FdLBT93h3kcZ586Aee66HPCVJ6qvxVjBlDWNmxSGSbCZe9hTsjRKdSsl4y1T+3zfujxo9auykQMnFsfyHWD7wg== 49 | 50 | "@types/linkify-it@*": 51 | version "3.0.2" 52 | resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9" 53 | integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA== 54 | 55 | "@types/markdown-it@^12.2.3": 56 | version "12.2.3" 57 | resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" 58 | integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ== 59 | dependencies: 60 | "@types/linkify-it" "*" 61 | "@types/mdurl" "*" 62 | 63 | "@types/mdurl@*": 64 | version "1.0.2" 65 | resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" 66 | integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== 67 | 68 | "@types/ms@*": 69 | version "0.7.31" 70 | resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" 71 | integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== 72 | 73 | "@types/node@*": 74 | version "17.0.23" 75 | resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" 76 | integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== 77 | 78 | "@vitejs/plugin-vue@^2.1.0": 79 | version "2.2.4" 80 | resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-2.2.4.tgz#ab8b199ca82496b05d2654c5f34ffcf9b947243d" 81 | integrity sha512-ev9AOlp0ljCaDkFZF3JwC/pD2N4Hh+r5srl5JHM6BKg5+99jiiK0rE/XaRs3pVm1wzyKkjUy/StBSoXX5fFzcw== 82 | 83 | "@vue/compiler-core@3.2.31": 84 | version "3.2.31" 85 | resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.31.tgz#d38f06c2cf845742403b523ab4596a3fda152e89" 86 | integrity sha512-aKno00qoA4o+V/kR6i/pE+aP+esng5siNAVQ422TkBNM6qA4veXiZbSe8OTXHXquEi/f6Akc+nLfB4JGfe4/WQ== 87 | dependencies: 88 | "@babel/parser" "^7.16.4" 89 | "@vue/shared" "3.2.31" 90 | estree-walker "^2.0.2" 91 | source-map "^0.6.1" 92 | 93 | "@vue/compiler-dom@3.2.31": 94 | version "3.2.31" 95 | resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.31.tgz#b1b7dfad55c96c8cc2b919cd7eb5fd7e4ddbf00e" 96 | integrity sha512-60zIlFfzIDf3u91cqfqy9KhCKIJgPeqxgveH2L+87RcGU/alT6BRrk5JtUso0OibH3O7NXuNOQ0cDc9beT0wrg== 97 | dependencies: 98 | "@vue/compiler-core" "3.2.31" 99 | "@vue/shared" "3.2.31" 100 | 101 | "@vue/compiler-sfc@3.2.31", "@vue/compiler-sfc@^3.2.28": 102 | version "3.2.31" 103 | resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.31.tgz#d02b29c3fe34d599a52c5ae1c6937b4d69f11c2f" 104 | integrity sha512-748adc9msSPGzXgibHiO6T7RWgfnDcVQD+VVwYgSsyyY8Ans64tALHZANrKtOzvkwznV/F4H7OAod/jIlp/dkQ== 105 | dependencies: 106 | "@babel/parser" "^7.16.4" 107 | "@vue/compiler-core" "3.2.31" 108 | "@vue/compiler-dom" "3.2.31" 109 | "@vue/compiler-ssr" "3.2.31" 110 | "@vue/reactivity-transform" "3.2.31" 111 | "@vue/shared" "3.2.31" 112 | estree-walker "^2.0.2" 113 | magic-string "^0.25.7" 114 | postcss "^8.1.10" 115 | source-map "^0.6.1" 116 | 117 | "@vue/compiler-ssr@3.2.31": 118 | version "3.2.31" 119 | resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.31.tgz#4fa00f486c9c4580b40a4177871ebbd650ecb99c" 120 | integrity sha512-mjN0rqig+A8TVDnsGPYJM5dpbjlXeHUm2oZHZwGyMYiGT/F4fhJf/cXy8QpjnLQK4Y9Et4GWzHn9PS8AHUnSkw== 121 | dependencies: 122 | "@vue/compiler-dom" "3.2.31" 123 | "@vue/shared" "3.2.31" 124 | 125 | "@vue/devtools-api@^6.0.0", "@vue/devtools-api@^6.0.0-beta.21.1": 126 | version "6.1.3" 127 | resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.1.3.tgz#a44c52e8fa6d22f84db3abdcdd0be5135b7dd7cf" 128 | integrity sha512-79InfO2xHv+WHIrH1bHXQUiQD/wMls9qBk6WVwGCbdwP7/3zINtvqPNMtmSHXsIKjvUAHc8L0ouOj6ZQQRmcXg== 129 | 130 | "@vue/reactivity-transform@3.2.31": 131 | version "3.2.31" 132 | resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.31.tgz#0f5b25c24e70edab2b613d5305c465b50fc00911" 133 | integrity sha512-uS4l4z/W7wXdI+Va5pgVxBJ345wyGFKvpPYtdSgvfJfX/x2Ymm6ophQlXXB6acqGHtXuBqNyyO3zVp9b1r0MOA== 134 | dependencies: 135 | "@babel/parser" "^7.16.4" 136 | "@vue/compiler-core" "3.2.31" 137 | "@vue/shared" "3.2.31" 138 | estree-walker "^2.0.2" 139 | magic-string "^0.25.7" 140 | 141 | "@vue/reactivity@3.2.31": 142 | version "3.2.31" 143 | resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.31.tgz#fc90aa2cdf695418b79e534783aca90d63a46bbd" 144 | integrity sha512-HVr0l211gbhpEKYr2hYe7hRsV91uIVGFYNHj73njbARVGHQvIojkImKMaZNDdoDZOIkMsBc9a1sMqR+WZwfSCw== 145 | dependencies: 146 | "@vue/shared" "3.2.31" 147 | 148 | "@vue/runtime-core@3.2.31": 149 | version "3.2.31" 150 | resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.31.tgz#9d284c382f5f981b7a7b5971052a1dc4ef39ac7a" 151 | integrity sha512-Kcog5XmSY7VHFEMuk4+Gap8gUssYMZ2+w+cmGI6OpZWYOEIcbE0TPzzPHi+8XTzAgx1w/ZxDFcXhZeXN5eKWsA== 152 | dependencies: 153 | "@vue/reactivity" "3.2.31" 154 | "@vue/shared" "3.2.31" 155 | 156 | "@vue/runtime-dom@3.2.31": 157 | version "3.2.31" 158 | resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.31.tgz#79ce01817cb3caf2c9d923f669b738d2d7953eff" 159 | integrity sha512-N+o0sICVLScUjfLG7u9u5XCjvmsexAiPt17GNnaWHJUfsKed5e85/A3SWgKxzlxx2SW/Hw7RQxzxbXez9PtY3g== 160 | dependencies: 161 | "@vue/runtime-core" "3.2.31" 162 | "@vue/shared" "3.2.31" 163 | csstype "^2.6.8" 164 | 165 | "@vue/server-renderer@3.2.31", "@vue/server-renderer@^3.2.28": 166 | version "3.2.31" 167 | resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.31.tgz#201e9d6ce735847d5989403af81ef80960da7141" 168 | integrity sha512-8CN3Zj2HyR2LQQBHZ61HexF5NReqngLT3oahyiVRfSSvak+oAvVmu8iNLSu6XR77Ili2AOpnAt1y8ywjjqtmkg== 169 | dependencies: 170 | "@vue/compiler-ssr" "3.2.31" 171 | "@vue/shared" "3.2.31" 172 | 173 | "@vue/shared@3.2.31", "@vue/shared@^3.2.28": 174 | version "3.2.31" 175 | resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.31.tgz#c90de7126d833dcd3a4c7534d534be2fb41faa4e" 176 | integrity sha512-ymN2pj6zEjiKJZbrf98UM2pfDd6F2H7ksKw7NDt/ZZ1fh5Ei39X5tABugtT03ZRlWd9imccoK0hE8hpjpU7irQ== 177 | 178 | "@vuepress/bundler-vite@2.0.0-beta.36": 179 | version "2.0.0-beta.36" 180 | resolved "https://registry.yarnpkg.com/@vuepress/bundler-vite/-/bundler-vite-2.0.0-beta.36.tgz#2e0940ca8ac8911e7f8a407b417cf2723aab4ce9" 181 | integrity sha512-wIWbBhLtGotQ1zJGkCHFllKmmpqG2FhcIhoUPY8/VESOmKyUrE6Mbbsk5g8Un0kFbhiF3eFYP1eUxbZttbbpkA== 182 | dependencies: 183 | "@vitejs/plugin-vue" "^2.1.0" 184 | "@vue/compiler-sfc" "^3.2.28" 185 | "@vue/server-renderer" "^3.2.28" 186 | "@vuepress/client" "2.0.0-beta.35" 187 | "@vuepress/core" "2.0.0-beta.36" 188 | "@vuepress/shared" "2.0.0-beta.35" 189 | "@vuepress/utils" "2.0.0-beta.35" 190 | autoprefixer "^10.4.2" 191 | connect-history-api-fallback "^1.6.0" 192 | postcss "^8.4.5" 193 | postcss-csso "^6.0.0" 194 | rollup "^2.66.0" 195 | vite "^2.7.13" 196 | vue "^3.2.28" 197 | vue-router "^4.0.12" 198 | 199 | "@vuepress/cli@2.0.0-beta.36": 200 | version "2.0.0-beta.36" 201 | resolved "https://registry.yarnpkg.com/@vuepress/cli/-/cli-2.0.0-beta.36.tgz#bfd8ff08434e7249bdf28577ba9c21294f110b45" 202 | integrity sha512-tGhC4OgdgOOoXGw79HFAJz5y9t9YRNdSsgkMRJvCAv9f257X+M/Ex/Qh3hfcnge+OBuMj63JLDB0FDRQWeJFUA== 203 | dependencies: 204 | "@vuepress/core" "2.0.0-beta.36" 205 | "@vuepress/utils" "2.0.0-beta.35" 206 | cac "^6.7.12" 207 | chokidar "^3.5.3" 208 | envinfo "^7.8.1" 209 | esbuild "^0.13.12" 210 | 211 | "@vuepress/client@2.0.0-beta.35": 212 | version "2.0.0-beta.35" 213 | resolved "https://registry.yarnpkg.com/@vuepress/client/-/client-2.0.0-beta.35.tgz#943b3b84e882a1b0c5e50b46dc1f12df557e71a2" 214 | integrity sha512-oQj+fDvfDDJ+fPpcVVRJLeVX1QmnLCcpLBxPBVhqMD0WAFkj+sCBaeq0sQc5CwDaNysDcN71ACeuEpLDOEtCgQ== 215 | dependencies: 216 | "@vue/devtools-api" "^6.0.0-beta.21.1" 217 | "@vuepress/shared" "2.0.0-beta.35" 218 | vue "^3.2.28" 219 | vue-router "^4.0.12" 220 | 221 | "@vuepress/core@2.0.0-beta.36": 222 | version "2.0.0-beta.36" 223 | resolved "https://registry.yarnpkg.com/@vuepress/core/-/core-2.0.0-beta.36.tgz#934c9b40ed2fbc622d9a652a9bda63cbd48c02d0" 224 | integrity sha512-RBj2Tkgt2f7NMCfox1iKgd6V87X5qj8G/cpJm7R65IielaXkNGGKjgidOrLKRCA3X0c/COwmaBrdiFxJtOtIRw== 225 | dependencies: 226 | "@vuepress/client" "2.0.0-beta.35" 227 | "@vuepress/markdown" "2.0.0-beta.36" 228 | "@vuepress/shared" "2.0.0-beta.35" 229 | "@vuepress/utils" "2.0.0-beta.35" 230 | gray-matter "^4.0.3" 231 | toml "^3.0.0" 232 | 233 | "@vuepress/markdown@2.0.0-beta.36": 234 | version "2.0.0-beta.36" 235 | resolved "https://registry.yarnpkg.com/@vuepress/markdown/-/markdown-2.0.0-beta.36.tgz#cb2765c2736c5257dbefc425480d146330bd60c9" 236 | integrity sha512-Amvo7YuSbMZIfj24kwXDen81RsjliXTDvhv+R14aH4NbH9rpwKzTTtbmjWH6O/upqikDYIXhlozHjr1nEf1qHw== 237 | dependencies: 238 | "@types/markdown-it" "^12.2.3" 239 | "@vuepress/shared" "2.0.0-beta.35" 240 | "@vuepress/utils" "2.0.0-beta.35" 241 | markdown-it "^12.3.2" 242 | markdown-it-anchor "^8.4.1" 243 | markdown-it-emoji "^2.0.0" 244 | mdurl "^1.0.1" 245 | 246 | "@vuepress/plugin-active-header-links@2.0.0-beta.36": 247 | version "2.0.0-beta.36" 248 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-active-header-links/-/plugin-active-header-links-2.0.0-beta.36.tgz#6ec2953c27f6ce9dbbfdcdcef3f847f8b5ac927d" 249 | integrity sha512-jeH1sieF1M/2M33JoUXe5RuRcdlGvUqMIq2wGdnwfXZn7YzcZtM8bmmhgpZw5yTuW6mT59b5SwEINptkZDKtUw== 250 | dependencies: 251 | "@vuepress/client" "2.0.0-beta.35" 252 | "@vuepress/core" "2.0.0-beta.36" 253 | "@vuepress/utils" "2.0.0-beta.35" 254 | ts-debounce "^4.0.0" 255 | vue "^3.2.28" 256 | vue-router "^4.0.12" 257 | 258 | "@vuepress/plugin-back-to-top@2.0.0-beta.36": 259 | version "2.0.0-beta.36" 260 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-back-to-top/-/plugin-back-to-top-2.0.0-beta.36.tgz#33b310e0b73e281aa0afcb16e261c180f2761f0a" 261 | integrity sha512-BwWa/EeKvboG22m4HmnCEfs/RcPtQ5pL5uVss8+POLgDSICKDGhuHrQiH/DtgqbceXZCryNlJhLkNXQ6TxcR+A== 262 | dependencies: 263 | "@vuepress/core" "2.0.0-beta.36" 264 | "@vuepress/utils" "2.0.0-beta.35" 265 | ts-debounce "^4.0.0" 266 | vue "^3.2.28" 267 | 268 | "@vuepress/plugin-container@2.0.0-beta.36": 269 | version "2.0.0-beta.36" 270 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-container/-/plugin-container-2.0.0-beta.36.tgz#b5a553a8999500eb92f628329a69e5777ea90f53" 271 | integrity sha512-65DjPd2RHnbk8wvyPimalC7K+dHbb41fWH8bPdJL6EhFPBCdplXmDHjR8sLU/15HGrF8ms8PRJ0nKRv5WUEsrw== 272 | dependencies: 273 | "@types/markdown-it" "^12.2.3" 274 | "@vuepress/core" "2.0.0-beta.36" 275 | "@vuepress/markdown" "2.0.0-beta.36" 276 | "@vuepress/shared" "2.0.0-beta.35" 277 | "@vuepress/utils" "2.0.0-beta.35" 278 | markdown-it "^12.3.2" 279 | markdown-it-container "^3.0.0" 280 | 281 | "@vuepress/plugin-external-link-icon@2.0.0-beta.36": 282 | version "2.0.0-beta.36" 283 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-external-link-icon/-/plugin-external-link-icon-2.0.0-beta.36.tgz#5d37b58fdba3268ac56bb5848aef98ee48f2501e" 284 | integrity sha512-t8UHhvxT7Zwwv+bV+jKZ1fnTKxk6FHOQ9ydGnGWje7YTL097FppSrWFdMRFVTWBfqRKkrSOx5gB2LIz2pELWvA== 285 | dependencies: 286 | "@vuepress/client" "2.0.0-beta.35" 287 | "@vuepress/core" "2.0.0-beta.36" 288 | "@vuepress/markdown" "2.0.0-beta.36" 289 | "@vuepress/utils" "2.0.0-beta.35" 290 | vue "^3.2.28" 291 | 292 | "@vuepress/plugin-git@2.0.0-beta.36": 293 | version "2.0.0-beta.36" 294 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-git/-/plugin-git-2.0.0-beta.36.tgz#ac0d8e00916ed7049ffc47490d3a64213d84a519" 295 | integrity sha512-Q2fIaExIZTZHWcJzelRMSf41yvfLUto2vFB9sMmpgRZ+vqFpPwruyR7XGmBxHMiSIjBFPbjAPadgB3hpoDKyiQ== 296 | dependencies: 297 | "@vuepress/core" "2.0.0-beta.36" 298 | execa "^5.1.1" 299 | 300 | "@vuepress/plugin-medium-zoom@2.0.0-beta.36": 301 | version "2.0.0-beta.36" 302 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-medium-zoom/-/plugin-medium-zoom-2.0.0-beta.36.tgz#534760a5c794d9b60768b6d5ae5bcf190aad8889" 303 | integrity sha512-5qarMKNvypwYgo/ojOGSAKqug9mlmkzzaHGqX9w2rObYB0kCyV1CuqFOqd0Eg/3vif3B0fDOVgEIomjvgc8rQw== 304 | dependencies: 305 | "@vuepress/client" "2.0.0-beta.35" 306 | "@vuepress/core" "2.0.0-beta.36" 307 | "@vuepress/utils" "2.0.0-beta.35" 308 | medium-zoom "^1.0.6" 309 | vue "^3.2.28" 310 | 311 | "@vuepress/plugin-nprogress@2.0.0-beta.36": 312 | version "2.0.0-beta.36" 313 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-nprogress/-/plugin-nprogress-2.0.0-beta.36.tgz#fa7b1903f74ea48a27cb3b00cad605a4bab4930d" 314 | integrity sha512-PFDFdvWQvvkGCiYi2jiCiRggP984yAYyZtSuK9eX3A9itYi0Qp+ck10tc+7cGQc1B97zg3FHVyA0BJcXUJwiJQ== 315 | dependencies: 316 | "@vuepress/client" "2.0.0-beta.35" 317 | "@vuepress/core" "2.0.0-beta.36" 318 | "@vuepress/utils" "2.0.0-beta.35" 319 | nprogress "^0.2.0" 320 | vue "^3.2.28" 321 | vue-router "^4.0.12" 322 | 323 | "@vuepress/plugin-palette@2.0.0-beta.36": 324 | version "2.0.0-beta.36" 325 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-palette/-/plugin-palette-2.0.0-beta.36.tgz#72dfa8c79f987ca03e6705515fe2b48754125ca4" 326 | integrity sha512-37D1uwX1j91niSu6f//26azS18FSD3g93NJs8LM3HAim4XtzCRaFSnI90MNG2++4Aelx2SSx86M4OjVdb1oCKw== 327 | dependencies: 328 | "@vuepress/core" "2.0.0-beta.36" 329 | "@vuepress/utils" "2.0.0-beta.35" 330 | chokidar "^3.5.3" 331 | 332 | "@vuepress/plugin-prismjs@2.0.0-beta.36": 333 | version "2.0.0-beta.36" 334 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-prismjs/-/plugin-prismjs-2.0.0-beta.36.tgz#6344880364ba828919569519cb7312792546f8c9" 335 | integrity sha512-xQ+Qa8ODt3K5blEZa2THTmXFO5/RrBjAgkk0u1JmPdVB8FoQAjdSaxZIs9vTBwCMCIexd6c3cC+MaPT2OVrgdA== 336 | dependencies: 337 | "@vuepress/core" "2.0.0-beta.36" 338 | prismjs "^1.26.0" 339 | 340 | "@vuepress/plugin-search@^2.0.0-beta.36": 341 | version "2.0.0-beta.36" 342 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-search/-/plugin-search-2.0.0-beta.36.tgz#4b8219514ae704919cc31d227d571dc06eefa9fd" 343 | integrity sha512-UMtWH5h9wXiZgram2w5m/4Ni5R/8w+G/r22pBdBuqB1KMOUO473EmgOWgxqAsT3DLvOgevfmxQvp/OcEQv9Esw== 344 | dependencies: 345 | "@vuepress/client" "2.0.0-beta.35" 346 | "@vuepress/core" "2.0.0-beta.36" 347 | "@vuepress/shared" "2.0.0-beta.35" 348 | "@vuepress/utils" "2.0.0-beta.35" 349 | chokidar "^3.5.3" 350 | vue "^3.2.28" 351 | vue-router "^4.0.12" 352 | 353 | "@vuepress/plugin-theme-data@2.0.0-beta.36": 354 | version "2.0.0-beta.36" 355 | resolved "https://registry.yarnpkg.com/@vuepress/plugin-theme-data/-/plugin-theme-data-2.0.0-beta.36.tgz#298fd9b160de886d003705615dbeee8ca2712a2b" 356 | integrity sha512-1Fxj7F0rIARYa/gQmsUql3f7wPF3ML4Fs6kcPHXYll7ZNDLR1OBw9HIGJ7lW4qx37f6YfYs2RjefAuwkVFUn/A== 357 | dependencies: 358 | "@vue/devtools-api" "^6.0.0-beta.21.1" 359 | "@vuepress/client" "2.0.0-beta.35" 360 | "@vuepress/core" "2.0.0-beta.36" 361 | "@vuepress/shared" "2.0.0-beta.35" 362 | "@vuepress/utils" "2.0.0-beta.35" 363 | vue "^3.2.28" 364 | 365 | "@vuepress/shared@2.0.0-beta.35": 366 | version "2.0.0-beta.35" 367 | resolved "https://registry.yarnpkg.com/@vuepress/shared/-/shared-2.0.0-beta.35.tgz#3a717903f18a2c5cbf9e456ac93d904bb8ebd3bf" 368 | integrity sha512-sU+ekNDv22YG16B1XmZyMD+A94QbAUgTp5FTs+X2POU9UQCIZCuFhgTM9TfAnSgD/6lnbp2Aljwg5fJAidPQmw== 369 | dependencies: 370 | "@vue/shared" "^3.2.28" 371 | 372 | "@vuepress/theme-default@2.0.0-beta.36": 373 | version "2.0.0-beta.36" 374 | resolved "https://registry.yarnpkg.com/@vuepress/theme-default/-/theme-default-2.0.0-beta.36.tgz#4b792f10c784526747c447e30e0d71cf77b4a083" 375 | integrity sha512-3QqRL96MzKDamHo5bw9ldO2DHTxE+nwEHv1u2PsZusyMRoxyP1h2wPFHPhGaR+fhxFC9Ou9dOq4Ay2xiIU1piA== 376 | dependencies: 377 | "@vuepress/client" "2.0.0-beta.35" 378 | "@vuepress/core" "2.0.0-beta.36" 379 | "@vuepress/plugin-active-header-links" "2.0.0-beta.36" 380 | "@vuepress/plugin-back-to-top" "2.0.0-beta.36" 381 | "@vuepress/plugin-container" "2.0.0-beta.36" 382 | "@vuepress/plugin-external-link-icon" "2.0.0-beta.36" 383 | "@vuepress/plugin-git" "2.0.0-beta.36" 384 | "@vuepress/plugin-medium-zoom" "2.0.0-beta.36" 385 | "@vuepress/plugin-nprogress" "2.0.0-beta.36" 386 | "@vuepress/plugin-palette" "2.0.0-beta.36" 387 | "@vuepress/plugin-prismjs" "2.0.0-beta.36" 388 | "@vuepress/plugin-theme-data" "2.0.0-beta.36" 389 | "@vuepress/shared" "2.0.0-beta.35" 390 | "@vuepress/utils" "2.0.0-beta.35" 391 | "@vueuse/core" "^7.5.4" 392 | sass "^1.49.0" 393 | sass-loader "^12.4.0" 394 | vue "^3.2.28" 395 | vue-router "^4.0.12" 396 | 397 | "@vuepress/utils@2.0.0-beta.35": 398 | version "2.0.0-beta.35" 399 | resolved "https://registry.yarnpkg.com/@vuepress/utils/-/utils-2.0.0-beta.35.tgz#439000c65012b014736fd6bb7e787e22da840bd3" 400 | integrity sha512-359RVp8T5w+OB/rKy3DYBFqrH98IDWxiB2pf1Z9vgUA54p5xWBbvmh5GwIAfz1PDjpC5BOIk1b1/03VgcJSZFg== 401 | dependencies: 402 | "@types/debug" "^4.1.7" 403 | "@types/fs-extra" "^9.0.13" 404 | "@types/hash-sum" "^1.0.0" 405 | "@vuepress/shared" "2.0.0-beta.35" 406 | chalk "^4.1.2" 407 | debug "^4.3.3" 408 | fs-extra "^10.0.0" 409 | globby "^11.0.4" 410 | hash-sum "^2.0.0" 411 | ora "^5.4.1" 412 | upath "^2.0.1" 413 | 414 | "@vueuse/core@^7.5.4": 415 | version "7.7.1" 416 | resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-7.7.1.tgz#fc284f4103de73c7fb79bc06579d8066790db511" 417 | integrity sha512-PRRgbATMpoeUmkCEBtUeJgOwtew8s+4UsEd+Pm7MhkjL2ihCNrSqxNVtM6NFE4uP2sWnkGcZpCjPuNSxowJ1Ow== 418 | dependencies: 419 | "@vueuse/shared" "7.7.1" 420 | vue-demi "*" 421 | 422 | "@vueuse/shared@7.7.1": 423 | version "7.7.1" 424 | resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-7.7.1.tgz#77e312de7275380efce86b0079bd7938791a076b" 425 | integrity sha512-rN2qd22AUl7VdBxihagWyhUNHCyVk9IpvBTTfHoLH9G7rGE552X1f+zeCfehuno0zXif13jPw+icW/wn2a0rnQ== 426 | dependencies: 427 | vue-demi "*" 428 | 429 | ansi-regex@^5.0.1: 430 | version "5.0.1" 431 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 432 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 433 | 434 | ansi-styles@^4.1.0: 435 | version "4.3.0" 436 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 437 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 438 | dependencies: 439 | color-convert "^2.0.1" 440 | 441 | anymatch@~3.1.2: 442 | version "3.1.2" 443 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" 444 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== 445 | dependencies: 446 | normalize-path "^3.0.0" 447 | picomatch "^2.0.4" 448 | 449 | argparse@^1.0.7: 450 | version "1.0.10" 451 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 452 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 453 | dependencies: 454 | sprintf-js "~1.0.2" 455 | 456 | argparse@^2.0.1: 457 | version "2.0.1" 458 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 459 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 460 | 461 | array-union@^2.1.0: 462 | version "2.1.0" 463 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" 464 | integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== 465 | 466 | autoprefixer@^10.4.2: 467 | version "10.4.4" 468 | resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" 469 | integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== 470 | dependencies: 471 | browserslist "^4.20.2" 472 | caniuse-lite "^1.0.30001317" 473 | fraction.js "^4.2.0" 474 | normalize-range "^0.1.2" 475 | picocolors "^1.0.0" 476 | postcss-value-parser "^4.2.0" 477 | 478 | base64-js@^1.3.1: 479 | version "1.5.1" 480 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" 481 | integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== 482 | 483 | binary-extensions@^2.0.0: 484 | version "2.2.0" 485 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" 486 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== 487 | 488 | bl@^4.1.0: 489 | version "4.1.0" 490 | resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" 491 | integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== 492 | dependencies: 493 | buffer "^5.5.0" 494 | inherits "^2.0.4" 495 | readable-stream "^3.4.0" 496 | 497 | braces@^3.0.2, braces@~3.0.2: 498 | version "3.0.2" 499 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 500 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 501 | dependencies: 502 | fill-range "^7.0.1" 503 | 504 | browserslist@^4.20.2: 505 | version "4.20.2" 506 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" 507 | integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== 508 | dependencies: 509 | caniuse-lite "^1.0.30001317" 510 | electron-to-chromium "^1.4.84" 511 | escalade "^3.1.1" 512 | node-releases "^2.0.2" 513 | picocolors "^1.0.0" 514 | 515 | buffer@^5.5.0: 516 | version "5.7.1" 517 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" 518 | integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== 519 | dependencies: 520 | base64-js "^1.3.1" 521 | ieee754 "^1.1.13" 522 | 523 | cac@^6.7.12: 524 | version "6.7.12" 525 | resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.12.tgz#6fb5ea2ff50bd01490dbda497f4ae75a99415193" 526 | integrity sha512-rM7E2ygtMkJqD9c7WnFU6fruFcN3xe4FM5yUmgxhZzIKJk4uHl9U/fhwdajGFQbQuv43FAUo1Fe8gX/oIKDeSA== 527 | 528 | caniuse-lite@^1.0.30001317: 529 | version "1.0.30001320" 530 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" 531 | integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== 532 | 533 | chalk@^4.1.0, chalk@^4.1.2: 534 | version "4.1.2" 535 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 536 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 537 | dependencies: 538 | ansi-styles "^4.1.0" 539 | supports-color "^7.1.0" 540 | 541 | "chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3: 542 | version "3.5.3" 543 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" 544 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== 545 | dependencies: 546 | anymatch "~3.1.2" 547 | braces "~3.0.2" 548 | glob-parent "~5.1.2" 549 | is-binary-path "~2.1.0" 550 | is-glob "~4.0.1" 551 | normalize-path "~3.0.0" 552 | readdirp "~3.6.0" 553 | optionalDependencies: 554 | fsevents "~2.3.2" 555 | 556 | cli-cursor@^3.1.0: 557 | version "3.1.0" 558 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" 559 | integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== 560 | dependencies: 561 | restore-cursor "^3.1.0" 562 | 563 | cli-spinners@^2.5.0: 564 | version "2.6.1" 565 | resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" 566 | integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== 567 | 568 | clone@^1.0.2: 569 | version "1.0.4" 570 | resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" 571 | integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= 572 | 573 | color-convert@^2.0.1: 574 | version "2.0.1" 575 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 576 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 577 | dependencies: 578 | color-name "~1.1.4" 579 | 580 | color-name@~1.1.4: 581 | version "1.1.4" 582 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 583 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 584 | 585 | connect-history-api-fallback@^1.6.0: 586 | version "1.6.0" 587 | resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" 588 | integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== 589 | 590 | cross-spawn@^7.0.3: 591 | version "7.0.3" 592 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 593 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== 594 | dependencies: 595 | path-key "^3.1.0" 596 | shebang-command "^2.0.0" 597 | which "^2.0.1" 598 | 599 | css-tree@~2.0.4: 600 | version "2.0.4" 601 | resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.0.4.tgz#be44314f17e9ac85fe894a5888941782e1123c29" 602 | integrity sha512-b4IS9ZUMtGBiNjzYbcj9JhYbyei99R3ai2CSxlu8GQDnoPA/P+NU85hAm0eKDc/Zp660rpK6tFJQ2OSdacMHVg== 603 | dependencies: 604 | mdn-data "2.0.23" 605 | source-map-js "^1.0.1" 606 | 607 | csso@^5.0.1: 608 | version "5.0.3" 609 | resolved "https://registry.yarnpkg.com/csso/-/csso-5.0.3.tgz#10986ad2546e877b8b7bfbf930702239407af4d4" 610 | integrity sha512-93gBHTJ6EQlLNhIX5Ho8VAJD2t2T2wg1xHDjbIUm/oQ7iFiSUTo9jSojiQK0pEZ3lMhYDrQO7Rcd70M68+VrtA== 611 | dependencies: 612 | css-tree "~2.0.4" 613 | 614 | csstype@^2.6.8: 615 | version "2.6.20" 616 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.20.tgz#9229c65ea0b260cf4d3d997cb06288e36a8d6dda" 617 | integrity sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA== 618 | 619 | debug@^4.3.3: 620 | version "4.3.4" 621 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" 622 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 623 | dependencies: 624 | ms "2.1.2" 625 | 626 | defaults@^1.0.3: 627 | version "1.0.3" 628 | resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" 629 | integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= 630 | dependencies: 631 | clone "^1.0.2" 632 | 633 | dir-glob@^3.0.1: 634 | version "3.0.1" 635 | resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" 636 | integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== 637 | dependencies: 638 | path-type "^4.0.0" 639 | 640 | electron-to-chromium@^1.4.84: 641 | version "1.4.95" 642 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.95.tgz#49303dbe037c15e2e0cc851d71c4cb86119a9cd6" 643 | integrity sha512-h2VAMV/hPtmAeiDkwA8c5sjS+cWt6GlQL4ERdrOUWu7cRIG5IRk9uwR9f0utP+hPJ9ZZsADTq9HpbuT46eBYAg== 644 | 645 | entities@~2.1.0: 646 | version "2.1.0" 647 | resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" 648 | integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== 649 | 650 | envinfo@^7.8.1: 651 | version "7.8.1" 652 | resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" 653 | integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== 654 | 655 | esbuild-android-64@0.14.28: 656 | version "0.14.28" 657 | resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.28.tgz#69c7a8a4f4a888eb5584afb035524b0fda7affff" 658 | integrity sha512-A52C3zq+9tNwCqZ+4kVLBxnk/WnrYM8P2+QNvNE9B6d2OVPs214lp3g6UyO+dKDhUdefhfPCuwkP8j2A/+szNA== 659 | 660 | esbuild-android-arm64@0.13.15: 661 | version "0.13.15" 662 | resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz#3fc3ff0bab76fe35dd237476b5d2b32bb20a3d44" 663 | integrity sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg== 664 | 665 | esbuild-android-arm64@0.14.28: 666 | version "0.14.28" 667 | resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.28.tgz#110ff82019e75b866b53844c32f19f7933b4ce36" 668 | integrity sha512-sm0fDEGElZhMC3HLZeECI2juE4aG7uPfMBMqNUhy9CeX399Pz8rC6e78OXMXInGjSdEAwQmCOHmfsP7uv3Q8rA== 669 | 670 | esbuild-darwin-64@0.13.15: 671 | version "0.13.15" 672 | resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz#8e9169c16baf444eacec60d09b24d11b255a8e72" 673 | integrity sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ== 674 | 675 | esbuild-darwin-64@0.14.28: 676 | version "0.14.28" 677 | resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.28.tgz#d929ce16035da6047504fe8a71587d2ac9b756ed" 678 | integrity sha512-nzDd7mQ44FvsFHtOafZdBgn3Li5SMsnMnoz1J2MM37xJmR3wGNTFph88KypjHgWqwbxCI7MXS1U+sN4qDeeW6Q== 679 | 680 | esbuild-darwin-arm64@0.13.15: 681 | version "0.13.15" 682 | resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz#1b07f893b632114f805e188ddfca41b2b778229a" 683 | integrity sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ== 684 | 685 | esbuild-darwin-arm64@0.14.28: 686 | version "0.14.28" 687 | resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.28.tgz#75e1cb75c2230c541be1707c6751395fee9f6bbd" 688 | integrity sha512-XEq/bLR/glsUl+uGrBimQzOVs/CmwI833fXUhP9xrLI3IJ+rKyrZ5IA8u+1crOEf1LoTn8tV+hInmX6rGjbScw== 689 | 690 | esbuild-freebsd-64@0.13.15: 691 | version "0.13.15" 692 | resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz#0b8b7eca1690c8ec94c75680c38c07269c1f4a85" 693 | integrity sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA== 694 | 695 | esbuild-freebsd-64@0.14.28: 696 | version "0.14.28" 697 | resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.28.tgz#3579fd41f4c090d52e1a9134743e591c6aea49d7" 698 | integrity sha512-rTKLgUj/HEcPeE5XZ7IZwWpFx7IWMfprN7QRk/TUJE1s1Ipb58esboIesUpjirJz/BwrgHq+FDG9ChAI8dZAtQ== 699 | 700 | esbuild-freebsd-arm64@0.13.15: 701 | version "0.13.15" 702 | resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz#2e1a6c696bfdcd20a99578b76350b41db1934e52" 703 | integrity sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ== 704 | 705 | esbuild-freebsd-arm64@0.14.28: 706 | version "0.14.28" 707 | resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.28.tgz#de1c102a40005fa9da5160c0242b2de89ffd2d7b" 708 | integrity sha512-sBffxD1UMOsB7aWMoExmipycjcy3HJGwmqE4GQZUTZvdiH4GhjgUiVdtPyt7kSCdL40JqnWQJ4b1l8Y51oCF4Q== 709 | 710 | esbuild-linux-32@0.13.15: 711 | version "0.13.15" 712 | resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz#6fd39f36fc66dd45b6b5f515728c7bbebc342a69" 713 | integrity sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g== 714 | 715 | esbuild-linux-32@0.14.28: 716 | version "0.14.28" 717 | resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.28.tgz#cdb8ac2000df06044450bf33a93b9d63d61bb669" 718 | integrity sha512-+Wxidh3fBEQ9kHcCsD4etlBTMb1n6QY2uXv3rFhVn88CY/JP782MhA57/ipLMY4kOLeSKEuFGN4rtjHuhmRMig== 719 | 720 | esbuild-linux-64@0.13.15: 721 | version "0.13.15" 722 | resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz#9cb8e4bcd7574e67946e4ee5f1f1e12386bb6dd3" 723 | integrity sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA== 724 | 725 | esbuild-linux-64@0.14.28: 726 | version "0.14.28" 727 | resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.28.tgz#b1e961d42af89dab8c3c0ce86420a7657765f0ae" 728 | integrity sha512-7+xgsC4LvR6cnzaBdiljNnPDjbkwzahogN+S9uy9AoYw7ZjPnnXc6sjQAVCbqGb7MEgrWdpa6u/Tao79i4lWxg== 729 | 730 | esbuild-linux-arm64@0.13.15: 731 | version "0.13.15" 732 | resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz#3891aa3704ec579a1b92d2a586122e5b6a2bfba1" 733 | integrity sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA== 734 | 735 | esbuild-linux-arm64@0.14.28: 736 | version "0.14.28" 737 | resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.28.tgz#f69e6ace792a4985b9760b443dbf627e5e3d2126" 738 | integrity sha512-EjRHgwg+kgXABzyoPGPOPg4d5wZqRnZ/ZAxBDzLY+i6DS8OUfTSlZHWIOZzU4XF7125WxRBg9ULbrFJBl+57Eg== 739 | 740 | esbuild-linux-arm@0.13.15: 741 | version "0.13.15" 742 | resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz#8a00e99e6a0c6c9a6b7f334841364d8a2b4aecfe" 743 | integrity sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA== 744 | 745 | esbuild-linux-arm@0.14.28: 746 | version "0.14.28" 747 | resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.28.tgz#9c2fa45578686370a5d782314f321a2c6b641270" 748 | integrity sha512-L5isjmlLbh9E0WVllXiVETbScgMbth/+XkXQii1WwgO1RvLIfaGrVFz8d2n6EH/ImtgYxPYGx+OcvIKQBc91Rg== 749 | 750 | esbuild-linux-mips64le@0.13.15: 751 | version "0.13.15" 752 | resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz#36b07cc47c3d21e48db3bb1f4d9ef8f46aead4f7" 753 | integrity sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg== 754 | 755 | esbuild-linux-mips64le@0.14.28: 756 | version "0.14.28" 757 | resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.28.tgz#99d78f0380640aa7faa2c4c49ac21229bdf33c7c" 758 | integrity sha512-krx9SSg7yfiUKk64EmjefOyiEF6nv2bRE4um/LiTaQ6Y/6FP4UF3/Ou/AxZVyR154uSRq63xejcAsmswXAYRsw== 759 | 760 | esbuild-linux-ppc64le@0.13.15: 761 | version "0.13.15" 762 | resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz#f7e6bba40b9a11eb9dcae5b01550ea04670edad2" 763 | integrity sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ== 764 | 765 | esbuild-linux-ppc64le@0.14.28: 766 | version "0.14.28" 767 | resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.28.tgz#7388fa0c76033b4ca85b74071cb793d41ae77642" 768 | integrity sha512-LD0Xxu9g+DNuhsEBV5QuVZ4uKVBMup0xPIruLweuAf9/mHXFnaCuNXUBF5t0DxKl7GQ5MSioKtnb92oMo+QXEw== 769 | 770 | esbuild-linux-riscv64@0.14.28: 771 | version "0.14.28" 772 | resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.28.tgz#99e4a8afe4762e927ebe02009e1927e38f3256ab" 773 | integrity sha512-L/DWfRh2P0vxq4Y+qieSNXKGdMg+e9Qe8jkbN2/8XSGYDTPzO2OcAxSujob4qIh7iSl+cknbXV+BvH0YFR0jbg== 774 | 775 | esbuild-linux-s390x@0.14.28: 776 | version "0.14.28" 777 | resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.28.tgz#38a625399ffc78f3b8b555ebe2013347256a9a8a" 778 | integrity sha512-rrgxmsbmL8QQknWGnAL9bGJRQYLOi2AzXy5OTwfhxnj9eqjo5mSVbJXjgiq5LPUAMQZGdPH5yaNK0obAXS81Zw== 779 | 780 | esbuild-netbsd-64@0.13.15: 781 | version "0.13.15" 782 | resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz#a2fedc549c2b629d580a732d840712b08d440038" 783 | integrity sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w== 784 | 785 | esbuild-netbsd-64@0.14.28: 786 | version "0.14.28" 787 | resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.28.tgz#fdc09dd69313f42be034276cc780bf60c09266b6" 788 | integrity sha512-h8wntIyOR8/xMVVM6TvJxxWKh4AjmLK87IPKpuVi8Pq0kyk0RMA+eo4PFGk5j2XK0D7dj8PcSF5NSlP9kN/j0A== 789 | 790 | esbuild-openbsd-64@0.13.15: 791 | version "0.13.15" 792 | resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz#b22c0e5806d3a1fbf0325872037f885306b05cd7" 793 | integrity sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g== 794 | 795 | esbuild-openbsd-64@0.14.28: 796 | version "0.14.28" 797 | resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.28.tgz#9d7b0ca421ae580ab945c69c33eabd793262a84c" 798 | integrity sha512-HBv18rVapbuDx52/fhZ/c/w6TXyaQAvRxiDDn5Hz/pBcwOs3cdd2WxeIKlWmDoqm2JMx5EVlq4IWgoaRX9mVkw== 799 | 800 | esbuild-sunos-64@0.13.15: 801 | version "0.13.15" 802 | resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz#d0b6454a88375ee8d3964daeff55c85c91c7cef4" 803 | integrity sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw== 804 | 805 | esbuild-sunos-64@0.14.28: 806 | version "0.14.28" 807 | resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.28.tgz#5b82807ebe435519a2689e1a4d50b8a3cc5c64c0" 808 | integrity sha512-zlIxePhZxKYheR2vBCgPVvTixgo/ozOfOMoP6RZj8dxzquU1NgeyhjkcRXucbLCtmoNJ+i4PtWwPZTLuDd3bGg== 809 | 810 | esbuild-windows-32@0.13.15: 811 | version "0.13.15" 812 | resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz#c96d0b9bbb52f3303322582ef8e4847c5ad375a7" 813 | integrity sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw== 814 | 815 | esbuild-windows-32@0.14.28: 816 | version "0.14.28" 817 | resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.28.tgz#5cf740782fadc865c00aa0d8388e42012bcf496e" 818 | integrity sha512-am9DIJxXlld1BOAY/VlvBQHMUCPL7S3gB/lnXIY3M4ys0gfuRqPf4EvMwZMzYUbFKBY+/Qb8SRgPRRGhwnJ8Kg== 819 | 820 | esbuild-windows-64@0.13.15: 821 | version "0.13.15" 822 | resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz#1f79cb9b1e1bb02fb25cd414cb90d4ea2892c294" 823 | integrity sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ== 824 | 825 | esbuild-windows-64@0.14.28: 826 | version "0.14.28" 827 | resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.28.tgz#6e3ec1b0225d668a2da21e2ffeff2353b5c9a567" 828 | integrity sha512-78PhySDnmRZlsPNp/W/5Fim8iivlBQQxfhBFIqR7xwvfDmCFUSByyMKP7LCHgNtb04yNdop8nJJkJaQ8Xnwgiw== 829 | 830 | esbuild-windows-arm64@0.13.15: 831 | version "0.13.15" 832 | resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz#482173070810df22a752c686509c370c3be3b3c3" 833 | integrity sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA== 834 | 835 | esbuild-windows-arm64@0.14.28: 836 | version "0.14.28" 837 | resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.28.tgz#c527d52ec7d1f868259d0f74ecc4003e8475125d" 838 | integrity sha512-VhXGBTo6HELD8zyHXynV6+L2jWx0zkKnGx4TmEdSBK7UVFACtOyfUqpToG0EtnYyRZ0HESBhzPSVpP781ovmvA== 839 | 840 | esbuild@^0.13.12: 841 | version "0.13.15" 842 | resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.13.15.tgz#db56a88166ee373f87dbb2d8798ff449e0450cdf" 843 | integrity sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw== 844 | optionalDependencies: 845 | esbuild-android-arm64 "0.13.15" 846 | esbuild-darwin-64 "0.13.15" 847 | esbuild-darwin-arm64 "0.13.15" 848 | esbuild-freebsd-64 "0.13.15" 849 | esbuild-freebsd-arm64 "0.13.15" 850 | esbuild-linux-32 "0.13.15" 851 | esbuild-linux-64 "0.13.15" 852 | esbuild-linux-arm "0.13.15" 853 | esbuild-linux-arm64 "0.13.15" 854 | esbuild-linux-mips64le "0.13.15" 855 | esbuild-linux-ppc64le "0.13.15" 856 | esbuild-netbsd-64 "0.13.15" 857 | esbuild-openbsd-64 "0.13.15" 858 | esbuild-sunos-64 "0.13.15" 859 | esbuild-windows-32 "0.13.15" 860 | esbuild-windows-64 "0.13.15" 861 | esbuild-windows-arm64 "0.13.15" 862 | 863 | esbuild@^0.14.14: 864 | version "0.14.28" 865 | resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.28.tgz#7738635d2ea19e446bd319d83a1802545e6aebb8" 866 | integrity sha512-YLNprkCcMVKQ5sekmCKEQ3Obu/L7s6+iij38xNKyBeSmSsTWur4Ky/9zB3XIGT8SCJITG/bZwAR2l7YOAXch4Q== 867 | optionalDependencies: 868 | esbuild-android-64 "0.14.28" 869 | esbuild-android-arm64 "0.14.28" 870 | esbuild-darwin-64 "0.14.28" 871 | esbuild-darwin-arm64 "0.14.28" 872 | esbuild-freebsd-64 "0.14.28" 873 | esbuild-freebsd-arm64 "0.14.28" 874 | esbuild-linux-32 "0.14.28" 875 | esbuild-linux-64 "0.14.28" 876 | esbuild-linux-arm "0.14.28" 877 | esbuild-linux-arm64 "0.14.28" 878 | esbuild-linux-mips64le "0.14.28" 879 | esbuild-linux-ppc64le "0.14.28" 880 | esbuild-linux-riscv64 "0.14.28" 881 | esbuild-linux-s390x "0.14.28" 882 | esbuild-netbsd-64 "0.14.28" 883 | esbuild-openbsd-64 "0.14.28" 884 | esbuild-sunos-64 "0.14.28" 885 | esbuild-windows-32 "0.14.28" 886 | esbuild-windows-64 "0.14.28" 887 | esbuild-windows-arm64 "0.14.28" 888 | 889 | escalade@^3.1.1: 890 | version "3.1.1" 891 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 892 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 893 | 894 | esprima@^4.0.0: 895 | version "4.0.1" 896 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 897 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 898 | 899 | estree-walker@^2.0.2: 900 | version "2.0.2" 901 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" 902 | integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== 903 | 904 | execa@^5.1.1: 905 | version "5.1.1" 906 | resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" 907 | integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== 908 | dependencies: 909 | cross-spawn "^7.0.3" 910 | get-stream "^6.0.0" 911 | human-signals "^2.1.0" 912 | is-stream "^2.0.0" 913 | merge-stream "^2.0.0" 914 | npm-run-path "^4.0.1" 915 | onetime "^5.1.2" 916 | signal-exit "^3.0.3" 917 | strip-final-newline "^2.0.0" 918 | 919 | extend-shallow@^2.0.1: 920 | version "2.0.1" 921 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" 922 | integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= 923 | dependencies: 924 | is-extendable "^0.1.0" 925 | 926 | fast-glob@^3.2.9: 927 | version "3.2.11" 928 | resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" 929 | integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== 930 | dependencies: 931 | "@nodelib/fs.stat" "^2.0.2" 932 | "@nodelib/fs.walk" "^1.2.3" 933 | glob-parent "^5.1.2" 934 | merge2 "^1.3.0" 935 | micromatch "^4.0.4" 936 | 937 | fastq@^1.6.0: 938 | version "1.13.0" 939 | resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" 940 | integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== 941 | dependencies: 942 | reusify "^1.0.4" 943 | 944 | fill-range@^7.0.1: 945 | version "7.0.1" 946 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 947 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 948 | dependencies: 949 | to-regex-range "^5.0.1" 950 | 951 | fraction.js@^4.2.0: 952 | version "4.2.0" 953 | resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" 954 | integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== 955 | 956 | fs-extra@^10.0.0: 957 | version "10.0.1" 958 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.1.tgz#27de43b4320e833f6867cc044bfce29fdf0ef3b8" 959 | integrity sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag== 960 | dependencies: 961 | graceful-fs "^4.2.0" 962 | jsonfile "^6.0.1" 963 | universalify "^2.0.0" 964 | 965 | fsevents@~2.3.2: 966 | version "2.3.2" 967 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 968 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 969 | 970 | function-bind@^1.1.1: 971 | version "1.1.1" 972 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 973 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 974 | 975 | get-stream@^6.0.0: 976 | version "6.0.1" 977 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" 978 | integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== 979 | 980 | glob-parent@^5.1.2, glob-parent@~5.1.2: 981 | version "5.1.2" 982 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 983 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 984 | dependencies: 985 | is-glob "^4.0.1" 986 | 987 | globby@^11.0.4: 988 | version "11.1.0" 989 | resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" 990 | integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== 991 | dependencies: 992 | array-union "^2.1.0" 993 | dir-glob "^3.0.1" 994 | fast-glob "^3.2.9" 995 | ignore "^5.2.0" 996 | merge2 "^1.4.1" 997 | slash "^3.0.0" 998 | 999 | graceful-fs@^4.1.6, graceful-fs@^4.2.0: 1000 | version "4.2.9" 1001 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" 1002 | integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== 1003 | 1004 | gray-matter@^4.0.3: 1005 | version "4.0.3" 1006 | resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" 1007 | integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q== 1008 | dependencies: 1009 | js-yaml "^3.13.1" 1010 | kind-of "^6.0.2" 1011 | section-matter "^1.0.0" 1012 | strip-bom-string "^1.0.0" 1013 | 1014 | has-flag@^4.0.0: 1015 | version "4.0.0" 1016 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 1017 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 1018 | 1019 | has@^1.0.3: 1020 | version "1.0.3" 1021 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 1022 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 1023 | dependencies: 1024 | function-bind "^1.1.1" 1025 | 1026 | hash-sum@^2.0.0: 1027 | version "2.0.0" 1028 | resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a" 1029 | integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg== 1030 | 1031 | human-signals@^2.1.0: 1032 | version "2.1.0" 1033 | resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" 1034 | integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== 1035 | 1036 | ieee754@^1.1.13: 1037 | version "1.2.1" 1038 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" 1039 | integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== 1040 | 1041 | ignore@^5.2.0: 1042 | version "5.2.0" 1043 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" 1044 | integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== 1045 | 1046 | immutable@^4.0.0: 1047 | version "4.0.0" 1048 | resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23" 1049 | integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw== 1050 | 1051 | inherits@^2.0.3, inherits@^2.0.4: 1052 | version "2.0.4" 1053 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 1054 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 1055 | 1056 | is-binary-path@~2.1.0: 1057 | version "2.1.0" 1058 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 1059 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 1060 | dependencies: 1061 | binary-extensions "^2.0.0" 1062 | 1063 | is-core-module@^2.8.1: 1064 | version "2.8.1" 1065 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" 1066 | integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== 1067 | dependencies: 1068 | has "^1.0.3" 1069 | 1070 | is-extendable@^0.1.0: 1071 | version "0.1.1" 1072 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 1073 | integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= 1074 | 1075 | is-extglob@^2.1.1: 1076 | version "2.1.1" 1077 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 1078 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 1079 | 1080 | is-glob@^4.0.1, is-glob@~4.0.1: 1081 | version "4.0.3" 1082 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 1083 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 1084 | dependencies: 1085 | is-extglob "^2.1.1" 1086 | 1087 | is-interactive@^1.0.0: 1088 | version "1.0.0" 1089 | resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" 1090 | integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== 1091 | 1092 | is-number@^7.0.0: 1093 | version "7.0.0" 1094 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 1095 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 1096 | 1097 | is-stream@^2.0.0: 1098 | version "2.0.1" 1099 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" 1100 | integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== 1101 | 1102 | is-unicode-supported@^0.1.0: 1103 | version "0.1.0" 1104 | resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" 1105 | integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== 1106 | 1107 | isexe@^2.0.0: 1108 | version "2.0.0" 1109 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 1110 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 1111 | 1112 | js-yaml@^3.13.1: 1113 | version "3.14.1" 1114 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" 1115 | integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== 1116 | dependencies: 1117 | argparse "^1.0.7" 1118 | esprima "^4.0.0" 1119 | 1120 | jsonfile@^6.0.1: 1121 | version "6.1.0" 1122 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" 1123 | integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== 1124 | dependencies: 1125 | universalify "^2.0.0" 1126 | optionalDependencies: 1127 | graceful-fs "^4.1.6" 1128 | 1129 | kind-of@^6.0.0, kind-of@^6.0.2: 1130 | version "6.0.3" 1131 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" 1132 | integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== 1133 | 1134 | klona@^2.0.4: 1135 | version "2.0.5" 1136 | resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" 1137 | integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== 1138 | 1139 | linkify-it@^3.0.1: 1140 | version "3.0.3" 1141 | resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e" 1142 | integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ== 1143 | dependencies: 1144 | uc.micro "^1.0.1" 1145 | 1146 | log-symbols@^4.1.0: 1147 | version "4.1.0" 1148 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" 1149 | integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== 1150 | dependencies: 1151 | chalk "^4.1.0" 1152 | is-unicode-supported "^0.1.0" 1153 | 1154 | magic-string@^0.25.7: 1155 | version "0.25.9" 1156 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" 1157 | integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== 1158 | dependencies: 1159 | sourcemap-codec "^1.4.8" 1160 | 1161 | markdown-it-anchor@^8.4.1: 1162 | version "8.4.1" 1163 | resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-8.4.1.tgz#29e560593f5edb80b25fdab8b23f93ef8a91b31e" 1164 | integrity sha512-sLODeRetZ/61KkKLJElaU3NuU2z7MhXf12Ml1WJMSdwpngeofneCRF+JBbat8HiSqhniOMuTemXMrsI7hA6XyA== 1165 | 1166 | markdown-it-container@^3.0.0: 1167 | version "3.0.0" 1168 | resolved "https://registry.yarnpkg.com/markdown-it-container/-/markdown-it-container-3.0.0.tgz#1d19b06040a020f9a827577bb7dbf67aa5de9a5b" 1169 | integrity sha512-y6oKTq4BB9OQuY/KLfk/O3ysFhB3IMYoIWhGJEidXt1NQFocFK2sA2t0NYZAMyMShAGL6x5OPIbrmXPIqaN9rw== 1170 | 1171 | markdown-it-emoji@^2.0.0: 1172 | version "2.0.0" 1173 | resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-2.0.0.tgz#3164ad4c009efd946e98274f7562ad611089a231" 1174 | integrity sha512-39j7/9vP/CPCKbEI44oV8yoPJTpvfeReTn/COgRhSpNrjWF3PfP/JUxxB0hxV6ynOY8KH8Y8aX9NMDdo6z+6YQ== 1175 | 1176 | markdown-it@^12.3.2: 1177 | version "12.3.2" 1178 | resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.3.2.tgz#bf92ac92283fe983fe4de8ff8abfb5ad72cd0c90" 1179 | integrity sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg== 1180 | dependencies: 1181 | argparse "^2.0.1" 1182 | entities "~2.1.0" 1183 | linkify-it "^3.0.1" 1184 | mdurl "^1.0.1" 1185 | uc.micro "^1.0.5" 1186 | 1187 | mdn-data@2.0.23: 1188 | version "2.0.23" 1189 | resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.23.tgz#dfb6c41e50a0edb808cf340973ab29321b70808e" 1190 | integrity sha512-IonVb7pfla2U4zW8rc7XGrtgq11BvYeCxWN8HS+KFBnLDE7XDK9AAMVhRuG6fj9BBsjc69Fqsp6WEActEdNTDQ== 1191 | 1192 | mdurl@^1.0.1: 1193 | version "1.0.1" 1194 | resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" 1195 | integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= 1196 | 1197 | medium-zoom@^1.0.6: 1198 | version "1.0.6" 1199 | resolved "https://registry.yarnpkg.com/medium-zoom/-/medium-zoom-1.0.6.tgz#9247f21ca9313d8bbe9420aca153a410df08d027" 1200 | integrity sha512-UdiUWfvz9fZMg1pzf4dcuqA0W079o0mpqbTnOz5ip4VGYX96QjmbM+OgOU/0uOzAytxC0Ny4z+VcYQnhdifimg== 1201 | 1202 | merge-stream@^2.0.0: 1203 | version "2.0.0" 1204 | resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" 1205 | integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== 1206 | 1207 | merge2@^1.3.0, merge2@^1.4.1: 1208 | version "1.4.1" 1209 | resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" 1210 | integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== 1211 | 1212 | micromatch@^4.0.4: 1213 | version "4.0.5" 1214 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" 1215 | integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== 1216 | dependencies: 1217 | braces "^3.0.2" 1218 | picomatch "^2.3.1" 1219 | 1220 | mimic-fn@^2.1.0: 1221 | version "2.1.0" 1222 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" 1223 | integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== 1224 | 1225 | ms@2.1.2: 1226 | version "2.1.2" 1227 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 1228 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 1229 | 1230 | nanoid@^3.3.1: 1231 | version "3.3.1" 1232 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" 1233 | integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== 1234 | 1235 | neo-async@^2.6.2: 1236 | version "2.6.2" 1237 | resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" 1238 | integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== 1239 | 1240 | node-releases@^2.0.2: 1241 | version "2.0.2" 1242 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" 1243 | integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== 1244 | 1245 | normalize-path@^3.0.0, normalize-path@~3.0.0: 1246 | version "3.0.0" 1247 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 1248 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 1249 | 1250 | normalize-range@^0.1.2: 1251 | version "0.1.2" 1252 | resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" 1253 | integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= 1254 | 1255 | npm-run-path@^4.0.1: 1256 | version "4.0.1" 1257 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" 1258 | integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== 1259 | dependencies: 1260 | path-key "^3.0.0" 1261 | 1262 | nprogress@^0.2.0: 1263 | version "0.2.0" 1264 | resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" 1265 | integrity sha1-y480xTIT2JVyP8urkH6UIq28r7E= 1266 | 1267 | onetime@^5.1.0, onetime@^5.1.2: 1268 | version "5.1.2" 1269 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" 1270 | integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== 1271 | dependencies: 1272 | mimic-fn "^2.1.0" 1273 | 1274 | ora@^5.4.1: 1275 | version "5.4.1" 1276 | resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" 1277 | integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== 1278 | dependencies: 1279 | bl "^4.1.0" 1280 | chalk "^4.1.0" 1281 | cli-cursor "^3.1.0" 1282 | cli-spinners "^2.5.0" 1283 | is-interactive "^1.0.0" 1284 | is-unicode-supported "^0.1.0" 1285 | log-symbols "^4.1.0" 1286 | strip-ansi "^6.0.0" 1287 | wcwidth "^1.0.1" 1288 | 1289 | path-key@^3.0.0, path-key@^3.1.0: 1290 | version "3.1.1" 1291 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 1292 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 1293 | 1294 | path-parse@^1.0.7: 1295 | version "1.0.7" 1296 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 1297 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 1298 | 1299 | path-type@^4.0.0: 1300 | version "4.0.0" 1301 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 1302 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 1303 | 1304 | picocolors@^1.0.0: 1305 | version "1.0.0" 1306 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 1307 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 1308 | 1309 | picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: 1310 | version "2.3.1" 1311 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 1312 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 1313 | 1314 | postcss-csso@^6.0.0: 1315 | version "6.0.0" 1316 | resolved "https://registry.yarnpkg.com/postcss-csso/-/postcss-csso-6.0.0.tgz#ff3ec8ce0694d797b75f7f7e10c4ac5a35e7780f" 1317 | integrity sha512-LsrU+LVR0mNIYauoTEbYVC81i+yXcGWa9kqW6Lvm+gYUZTaNTJmJT6Dbv+fqT8gOnwXAH1RV+5RXvAVoRtwO+g== 1318 | dependencies: 1319 | csso "^5.0.1" 1320 | 1321 | postcss-value-parser@^4.2.0: 1322 | version "4.2.0" 1323 | resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" 1324 | integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== 1325 | 1326 | postcss@^8.1.10, postcss@^8.4.5, postcss@^8.4.6: 1327 | version "8.4.12" 1328 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" 1329 | integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== 1330 | dependencies: 1331 | nanoid "^3.3.1" 1332 | picocolors "^1.0.0" 1333 | source-map-js "^1.0.2" 1334 | 1335 | prismjs@^1.26.0: 1336 | version "1.27.0" 1337 | resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" 1338 | integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== 1339 | 1340 | queue-microtask@^1.2.2: 1341 | version "1.2.3" 1342 | resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" 1343 | integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== 1344 | 1345 | readable-stream@^3.4.0: 1346 | version "3.6.0" 1347 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" 1348 | integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== 1349 | dependencies: 1350 | inherits "^2.0.3" 1351 | string_decoder "^1.1.1" 1352 | util-deprecate "^1.0.1" 1353 | 1354 | readdirp@~3.6.0: 1355 | version "3.6.0" 1356 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 1357 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 1358 | dependencies: 1359 | picomatch "^2.2.1" 1360 | 1361 | resolve@^1.22.0: 1362 | version "1.22.0" 1363 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" 1364 | integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== 1365 | dependencies: 1366 | is-core-module "^2.8.1" 1367 | path-parse "^1.0.7" 1368 | supports-preserve-symlinks-flag "^1.0.0" 1369 | 1370 | restore-cursor@^3.1.0: 1371 | version "3.1.0" 1372 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" 1373 | integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== 1374 | dependencies: 1375 | onetime "^5.1.0" 1376 | signal-exit "^3.0.2" 1377 | 1378 | reusify@^1.0.4: 1379 | version "1.0.4" 1380 | resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" 1381 | integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== 1382 | 1383 | rollup@^2.59.0, rollup@^2.66.0: 1384 | version "2.70.1" 1385 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.70.1.tgz#824b1f1f879ea396db30b0fc3ae8d2fead93523e" 1386 | integrity sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA== 1387 | optionalDependencies: 1388 | fsevents "~2.3.2" 1389 | 1390 | run-parallel@^1.1.9: 1391 | version "1.2.0" 1392 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" 1393 | integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== 1394 | dependencies: 1395 | queue-microtask "^1.2.2" 1396 | 1397 | safe-buffer@~5.2.0: 1398 | version "5.2.1" 1399 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 1400 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1401 | 1402 | sass-loader@^12.4.0: 1403 | version "12.6.0" 1404 | resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.6.0.tgz#5148362c8e2cdd4b950f3c63ac5d16dbfed37bcb" 1405 | integrity sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA== 1406 | dependencies: 1407 | klona "^2.0.4" 1408 | neo-async "^2.6.2" 1409 | 1410 | sass@^1.49.0: 1411 | version "1.49.9" 1412 | resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.9.tgz#b15a189ecb0ca9e24634bae5d1ebc191809712f9" 1413 | integrity sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A== 1414 | dependencies: 1415 | chokidar ">=3.0.0 <4.0.0" 1416 | immutable "^4.0.0" 1417 | source-map-js ">=0.6.2 <2.0.0" 1418 | 1419 | section-matter@^1.0.0: 1420 | version "1.0.0" 1421 | resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" 1422 | integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA== 1423 | dependencies: 1424 | extend-shallow "^2.0.1" 1425 | kind-of "^6.0.0" 1426 | 1427 | shebang-command@^2.0.0: 1428 | version "2.0.0" 1429 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 1430 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 1431 | dependencies: 1432 | shebang-regex "^3.0.0" 1433 | 1434 | shebang-regex@^3.0.0: 1435 | version "3.0.0" 1436 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 1437 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 1438 | 1439 | signal-exit@^3.0.2, signal-exit@^3.0.3: 1440 | version "3.0.7" 1441 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" 1442 | integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== 1443 | 1444 | slash@^3.0.0: 1445 | version "3.0.0" 1446 | resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" 1447 | integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== 1448 | 1449 | "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2: 1450 | version "1.0.2" 1451 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" 1452 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== 1453 | 1454 | source-map@^0.6.1: 1455 | version "0.6.1" 1456 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 1457 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 1458 | 1459 | sourcemap-codec@^1.4.8: 1460 | version "1.4.8" 1461 | resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" 1462 | integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== 1463 | 1464 | sprintf-js@~1.0.2: 1465 | version "1.0.3" 1466 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1467 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 1468 | 1469 | string_decoder@^1.1.1: 1470 | version "1.3.0" 1471 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" 1472 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== 1473 | dependencies: 1474 | safe-buffer "~5.2.0" 1475 | 1476 | strip-ansi@^6.0.0: 1477 | version "6.0.1" 1478 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 1479 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 1480 | dependencies: 1481 | ansi-regex "^5.0.1" 1482 | 1483 | strip-bom-string@^1.0.0: 1484 | version "1.0.0" 1485 | resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" 1486 | integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= 1487 | 1488 | strip-final-newline@^2.0.0: 1489 | version "2.0.0" 1490 | resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" 1491 | integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== 1492 | 1493 | supports-color@^7.1.0: 1494 | version "7.2.0" 1495 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1496 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1497 | dependencies: 1498 | has-flag "^4.0.0" 1499 | 1500 | supports-preserve-symlinks-flag@^1.0.0: 1501 | version "1.0.0" 1502 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 1503 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 1504 | 1505 | to-regex-range@^5.0.1: 1506 | version "5.0.1" 1507 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1508 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1509 | dependencies: 1510 | is-number "^7.0.0" 1511 | 1512 | toml@^3.0.0: 1513 | version "3.0.0" 1514 | resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" 1515 | integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== 1516 | 1517 | ts-debounce@^4.0.0: 1518 | version "4.0.0" 1519 | resolved "https://registry.yarnpkg.com/ts-debounce/-/ts-debounce-4.0.0.tgz#33440ef64fab53793c3d546a8ca6ae539ec15841" 1520 | integrity sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg== 1521 | 1522 | uc.micro@^1.0.1, uc.micro@^1.0.5: 1523 | version "1.0.6" 1524 | resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" 1525 | integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== 1526 | 1527 | universalify@^2.0.0: 1528 | version "2.0.0" 1529 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" 1530 | integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== 1531 | 1532 | upath@^2.0.1: 1533 | version "2.0.1" 1534 | resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" 1535 | integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== 1536 | 1537 | util-deprecate@^1.0.1: 1538 | version "1.0.2" 1539 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1540 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1541 | 1542 | vite@^2.7.13: 1543 | version "2.8.6" 1544 | resolved "https://registry.yarnpkg.com/vite/-/vite-2.8.6.tgz#32d50e23c99ca31b26b8ccdc78b1d72d4d7323d3" 1545 | integrity sha512-e4H0QpludOVKkmOsRyqQ7LTcMUDF3mcgyNU4lmi0B5JUbe0ZxeBBl8VoZ8Y6Rfn9eFKYtdXNPcYK97ZwH+K2ug== 1546 | dependencies: 1547 | esbuild "^0.14.14" 1548 | postcss "^8.4.6" 1549 | resolve "^1.22.0" 1550 | rollup "^2.59.0" 1551 | optionalDependencies: 1552 | fsevents "~2.3.2" 1553 | 1554 | vue-demi@*: 1555 | version "0.12.4" 1556 | resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.12.4.tgz#420dd17628f95f1bbce1102ad3c51074713a8049" 1557 | integrity sha512-ztPDkFt0TSUdoq1ZI6oD730vgztBkiByhUW7L1cOTebiSBqSYfSQgnhYakYigBkyAybqCTH7h44yZuDJf2xILQ== 1558 | 1559 | vue-router@^4.0.12: 1560 | version "4.0.14" 1561 | resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.14.tgz#ce2028c1c5c33e30c7287950c973f397fce1bd65" 1562 | integrity sha512-wAO6zF9zxA3u+7AkMPqw9LjoUCjSxfFvINQj3E/DceTt6uEz1XZLraDhdg2EYmvVwTBSGlLYsUw8bDmx0754Mw== 1563 | dependencies: 1564 | "@vue/devtools-api" "^6.0.0" 1565 | 1566 | vue@^3.2.28: 1567 | version "3.2.31" 1568 | resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.31.tgz#e0c49924335e9f188352816788a4cca10f817ce6" 1569 | integrity sha512-odT3W2tcffTiQCy57nOT93INw1auq5lYLLYtWpPYQQYQOOdHiqFct9Xhna6GJ+pJQaF67yZABraH47oywkJgFw== 1570 | dependencies: 1571 | "@vue/compiler-dom" "3.2.31" 1572 | "@vue/compiler-sfc" "3.2.31" 1573 | "@vue/runtime-dom" "3.2.31" 1574 | "@vue/server-renderer" "3.2.31" 1575 | "@vue/shared" "3.2.31" 1576 | 1577 | vuepress-vite@2.0.0-beta.36: 1578 | version "2.0.0-beta.36" 1579 | resolved "https://registry.yarnpkg.com/vuepress-vite/-/vuepress-vite-2.0.0-beta.36.tgz#50e4e2c11ff4e057f725ba42de81d9ac50be4b45" 1580 | integrity sha512-KbN7HDhaCLVB7/YmJDydQClUjMBybLtBpB376mi5fD16RFBzHwMGI7zopb4lu7Nmj2BnvLI9kpottv9zuOJYLQ== 1581 | dependencies: 1582 | "@vuepress/bundler-vite" "2.0.0-beta.36" 1583 | "@vuepress/cli" "2.0.0-beta.36" 1584 | "@vuepress/core" "2.0.0-beta.36" 1585 | "@vuepress/theme-default" "2.0.0-beta.36" 1586 | 1587 | vuepress@^2.0.0-beta.36: 1588 | version "2.0.0-beta.36" 1589 | resolved "https://registry.yarnpkg.com/vuepress/-/vuepress-2.0.0-beta.36.tgz#e620ee1d7ebfff2fa755aaaab858adbc39c362e6" 1590 | integrity sha512-EObFjxn91cMRZ+9cgDGjKaTHaCH4NChMqUIGRnPTrIlJfKa4eX4aS0GzPtHSy+L1fKgNnDyUq67fW8q3hrHVjA== 1591 | dependencies: 1592 | vuepress-vite "2.0.0-beta.36" 1593 | 1594 | wcwidth@^1.0.1: 1595 | version "1.0.1" 1596 | resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" 1597 | integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= 1598 | dependencies: 1599 | defaults "^1.0.3" 1600 | 1601 | which@^2.0.1: 1602 | version "2.0.2" 1603 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 1604 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 1605 | dependencies: 1606 | isexe "^2.0.0" 1607 | --------------------------------------------------------------------------------