diff --git a/.github/docker/Dockerfile b/.github/docker/Dockerfile
new file mode 100644
index 0000000..462c2da
--- /dev/null
+++ b/.github/docker/Dockerfile
@@ -0,0 +1,22 @@
+ARG PHP_VERSION=8.4
+FROM dunglas/frankenphp:1.9-php${PHP_VERSION}
+
+RUN install-php-extensions \
+ bcmath \
+ exif \
+ gd \
+ intl \
+ mbstring \
+ mysqli \
+ opcache \
+ pdo_mysql \
+ zip \
+ curl \
+ xml \
+ dom \
+ simplexml \
+ tokenizer \
+ json \
+ fileinfo \
+ sockets \
+ imagick
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 2304f0a..5eca599 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -21,7 +21,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
- version: 9
+ version: 10
- name: Install Node.js LTS
uses: actions/setup-node@v4
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..a3d6a9e
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,174 @@
+name: E2E Tests
+
+on:
+ push:
+ pull_request:
+
+jobs:
+ e2e:
+ name: PHP ${{ matrix.php }} - WP ${{ matrix.wordpress }}
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ # php: [ '7.4', '8.0', '8.1', '8.2' ]
+ php: [ '8.2', '8.3', '8.4' ]
+ # wordpress: [ '5.9', '6.0', '6.3', '6.7', '6.8' ]
+ wordpress: [ '6.7', '6.8' ]
+ exclude:
+ # Exclude older PHP versions with newer WordPress
+ - php: '7.4'
+ wordpress: '6.5.3'
+
+ services:
+ mysql:
+ image: mysql:8.0
+ env:
+ MYSQL_DATABASE: wordpress
+ MYSQL_ROOT_PASSWORD: root
+ ports: [ 3306:3306 ]
+ options: >-
+ --health-cmd="mysqladmin ping -h 127.0.0.1 -uroot -proot"
+ --health-interval=10s
+ --health-timeout=5s
+ --health-retries=5
+
+ env:
+ WP_VERSION: ${{ matrix.wordpress }}
+ WP_SITE_URL: http://localhost:8100
+ WP_DB_NAME: wordpress
+ WP_DB_USER: root
+ WP_DB_PASS: root
+ WP_DB_HOST: 127.0.0.1
+
+ steps:
+ - name: Check MySQL tables
+ run: |
+ echo "Listing databases:"
+ mysql -h 127.0.0.1 -uroot -proot -e "SHOW DATABASES;"
+
+ echo "Checking if 'wordpress' database has any tables:"
+ mysql -h 127.0.0.1 -uroot -proot -D wordpress -e "SHOW TABLES;" || echo "No tables found (yet)."
+
+ - name: Checkout plugin
+ uses: actions/checkout@v4
+
+ - name: Set up PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ # Note: Specified version is only for running tests,
+ # as the WordPress PHP version is set inside the FrankenPHP Dockerfile.
+ php-version: 8.4
+ extensions: mysqli, zip, gd
+ coverage: none
+ tools: wp-cli
+
+ - name: Cache WordPress archive
+ id: cache-wordpress
+ uses: actions/cache@v3
+ with:
+ path: /tmp/wp
+ key: wp-${{ matrix.wordpress }}
+
+ - name: Download WordPress
+ if: steps.cache-wordpress.outputs.cache-hit != 'true'
+ run: |
+ mkdir -p /tmp/wp
+ curl -O https://wordpress.org/wordpress-${WP_VERSION}.tar.gz
+ tar -xzf wordpress-${WP_VERSION}.tar.gz --strip-components=1 -C /tmp/wp
+ rm wordpress-${WP_VERSION}.tar.gz
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Build FrankenPHP image (with cache)
+ id: build
+ uses: docker/build-push-action@v6
+ env:
+ DOCKER_BUILD_SUMMARY: false
+ with:
+ context: .
+ file: .github/docker/Dockerfile
+ tags: frankenphp-${{ matrix.php }}
+ load: true
+ build-args: |
+ PHP_VERSION=${{ matrix.php }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+
+ - name: Start FrankenPHP server
+ run: |
+ docker run -d \
+ --name frankenphp \
+ --network host \
+ -p 8100:8100 \
+ -v /tmp/wp:/var/www/html \
+ -v $GITHUB_WORKSPACE:/var/www/html/wp-content/plugins/simpleanalytics \
+ -v $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile \
+ frankenphp-${{ matrix.php }}
+
+ - name: Install WordPress
+ run: |
+ rm -f /tmp/wp/wp-config.php
+ wp config create \
+ --dbname="$WP_DB_NAME" \
+ --dbuser="$WP_DB_USER" \
+ --dbpass="$WP_DB_PASS" \
+ --dbhost="$WP_DB_HOST" \
+ --path=/tmp/wp \
+ --skip-check
+ wp core install \
+ --url="${WP_SITE_URL}" \
+ --title="Test Site" \
+ --admin_user=admin \
+ --admin_password=admin \
+ --admin_email=test@example.com \
+ --path=/tmp/wp \
+ --skip-email \
+ --allow-root
+ wp user create author author@local.test --role=author --user_pass=author --path=/tmp/wp
+ wp user create editor editor@local.test --role=editor --user_pass=editor --path=/tmp/wp
+ wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=/tmp/wp
+
+ - name: Show current config values
+ run: wp config list --path=/tmp/wp --allow-root
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: lts/*
+ cache: "pnpm"
+
+ - name: Install pnpm dependencies
+ run: pnpm install
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v3
+ with:
+ path: vendor
+ key: composer-${{ hashFiles('composer.lock') }}
+
+ - name: Run composer install
+ run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
+
+ - name: Run Pest tests
+ run: ./vendor/bin/phpunit
+
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: test-results-php${{ matrix.php }}-wp${{ matrix.wordpress }}
+ path: var/browser
+ retention-days: 30
+
+ - name: Show FrankenPHP logs
+ if: always()
+ run: |
+ echo "=== FrankenPHP logs ==="
+ docker logs frankenphp || echo "No logs found"
diff --git a/.gitignore b/.gitignore
index cedebe2..cf492a0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,8 @@
.svn
-node*
-vendor*
build
+vendor/
+node_modules/
+.phpunit.result.cache
+var
+drivers
+driver
diff --git a/Caddyfile b/Caddyfile
new file mode 100644
index 0000000..92bddef
--- /dev/null
+++ b/Caddyfile
@@ -0,0 +1,19 @@
+{
+ local_certs
+ auto_https off
+ frankenphp
+}
+
+:8100 {
+ @static {
+ file
+ path *.avif *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff *.woff2 *.gpx
+ }
+ header @static Cache-Control max-age=5184000
+ root * /var/www/html/
+ encode br zstd gzip
+ php_server
+ log {
+ format console
+ }
+}
diff --git a/composer.json b/composer.json
index a266a58..077a1c4 100644
--- a/composer.json
+++ b/composer.json
@@ -1,5 +1,19 @@
{
"require-dev": {
- "rector/rector": "^1.2"
+ "rector/rector": "^1.2",
+ "zenstruck/browser": "^1.9",
+ "phpunit/phpunit": "^12",
+ "symfony/panther": "^2.2",
+ "dbrekelmans/bdi": "^1.4"
+ },
+ "autoload": {
+ "psr-4": {
+ "Tests\\": "tests/"
+ }
+ },
+ "config": {
+ "allow-plugins": {
+ "pestphp/pest-plugin": true
+ }
}
}
diff --git a/composer.lock b/composer.lock
index 6b98e03..a8be8be 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,21 +4,500 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "eb58f3061bde78d58fa424c73947025f",
+ "content-hash": "038d4d3ecb67f10afe8c5937fe2778e4",
"packages": [],
"packages-dev": [
{
- "name": "phpstan/phpstan",
- "version": "1.12.0",
+ "name": "behat/mink",
+ "version": "v1.12.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/minkphp/Mink.git",
+ "reference": "7e4edec6c335937029cb3569ce7ef81182804d0a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/minkphp/Mink/zipball/7e4edec6c335937029cb3569ce7ef81182804d0a",
+ "reference": "7e4edec6c335937029cb3569ce7ef81182804d0a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2",
+ "symfony/css-selector": "^4.4 || ^5.0 || ^6.0 || ^7.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.10",
+ "phpstan/phpstan-phpunit": "^1.3",
+ "phpunit/phpunit": "^8.5.22 || ^9.5.11",
+ "symfony/error-handler": "^4.4 || ^5.0 || ^6.0 || ^7.0",
+ "symfony/phpunit-bridge": "^5.4 || ^6.0 || ^7.0"
+ },
+ "suggest": {
+ "behat/mink-browserkit-driver": "fast headless driver for any app without JS emulation",
+ "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)",
+ "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)",
+ "dmore/chrome-mink-driver": "fast and JS-enabled driver for any app (requires chromium or google chrome)"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Behat\\Mink\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ }
+ ],
+ "description": "Browser controller/emulator abstraction for PHP",
+ "homepage": "https://mink.behat.org/",
+ "keywords": [
+ "browser",
+ "testing",
+ "web"
+ ],
+ "support": {
+ "issues": "https://github.com/minkphp/Mink/issues",
+ "source": "https://github.com/minkphp/Mink/tree/v1.12.0"
+ },
+ "time": "2024-10-30T18:48:14+00:00"
+ },
+ {
+ "name": "dbrekelmans/bdi",
+ "version": "1.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/dbrekelmans/bdi.git",
+ "reference": "fa2ff9b5ed0508ddf5cd574f9dfa6fea954a9acd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/dbrekelmans/bdi/zipball/fa2ff9b5ed0508ddf5cd574f9dfa6fea954a9acd",
+ "reference": "fa2ff9b5ed0508ddf5cd574f9dfa6fea954a9acd",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-zip": "*",
+ "ext-zlib": "*",
+ "php": "^8.1"
+ },
+ "bin": [
+ "bdi",
+ "bdi.phar"
+ ],
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Daniël Brekelmans",
+ "homepage": "https://github.com/dbrekelmans"
+ },
+ {
+ "name": "Contributors",
+ "homepage": "https://github.com/dbrekelmans/bdi/graphs/contributors"
+ }
+ ],
+ "description": "PHAR distribution of dbrekelmans/browser-driver-installer.",
+ "homepage": "https://github.com/dbrekelmans/bdi",
+ "keywords": [
+ "browser-driver-installer"
+ ],
+ "support": {
+ "source": "https://github.com/dbrekelmans/bdi/tree/1.4.0"
+ },
+ "time": "2024-12-12T18:36:47+00:00"
+ },
+ {
+ "name": "masterminds/html5",
+ "version": "2.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Masterminds/html5-php.git",
+ "reference": "fcf91eb64359852f00d921887b219479b4f21251"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
+ "reference": "fcf91eb64359852f00d921887b219479b4f21251",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.7-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Masterminds\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Matt Butcher",
+ "email": "technosophos@gmail.com"
+ },
+ {
+ "name": "Matt Farina",
+ "email": "matt@mattfarina.com"
+ },
+ {
+ "name": "Asmir Mustafic",
+ "email": "goetas@gmail.com"
+ }
+ ],
+ "description": "An HTML5 parser and serializer.",
+ "homepage": "http://masterminds.github.io/html5-php",
+ "keywords": [
+ "HTML5",
+ "dom",
+ "html",
+ "parser",
+ "querypath",
+ "serializer",
+ "xml"
+ ],
+ "support": {
+ "issues": "https://github.com/Masterminds/html5-php/issues",
+ "source": "https://github.com/Masterminds/html5-php/tree/2.10.0"
+ },
+ "time": "2025-07-25T09:04:22+00:00"
+ },
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.13.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "conflict": {
+ "doctrine/collections": "<1.6.8",
+ "doctrine/common": "<2.13.3 || >=3 <3.2.2"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.6.8",
+ "doctrine/common": "^2.13.3 || ^3.2.2",
+ "phpspec/prophecy": "^1.10",
+ "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ],
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "support": {
+ "issues": "https://github.com/myclabs/DeepCopy/issues",
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-01T08:46:24+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v5.6.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "3a454ca033b9e06b63282ce19562e892747449bb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
+ "reference": "3a454ca033b9e06b63282ce19562e892747449bb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "php": ">=7.4"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^9.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
+ },
+ "time": "2025-10-21T19:32:17+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-phar": "*",
+ "ext-xmlwriter": "*",
+ "phar-io/version": "^3.0.1",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "support": {
+ "issues": "https://github.com/phar-io/manifest/issues",
+ "source": "https://github.com/phar-io/manifest/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:33:53+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "3.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "support": {
+ "issues": "https://github.com/phar-io/version/issues",
+ "source": "https://github.com/phar-io/version/tree/3.2.1"
+ },
+ "time": "2022-02-21T01:04:05+00:00"
+ },
+ {
+ "name": "php-webdriver/webdriver",
+ "version": "1.15.2",
"source": {
"type": "git",
- "url": "https://github.com/phpstan/phpstan.git",
- "reference": "384af967d35b2162f69526c7276acadce534d0e1"
+ "url": "https://github.com/php-webdriver/php-webdriver.git",
+ "reference": "998e499b786805568deaf8cbf06f4044f05d91bf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/998e499b786805568deaf8cbf06f4044f05d91bf",
+ "reference": "998e499b786805568deaf8cbf06f4044f05d91bf",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "ext-json": "*",
+ "ext-zip": "*",
+ "php": "^7.3 || ^8.0",
+ "symfony/polyfill-mbstring": "^1.12",
+ "symfony/process": "^5.0 || ^6.0 || ^7.0"
+ },
+ "replace": {
+ "facebook/webdriver": "*"
+ },
+ "require-dev": {
+ "ergebnis/composer-normalize": "^2.20.0",
+ "ondram/ci-detector": "^4.0",
+ "php-coveralls/php-coveralls": "^2.4",
+ "php-mock/php-mock-phpunit": "^2.0",
+ "php-parallel-lint/php-parallel-lint": "^1.2",
+ "phpunit/phpunit": "^9.3",
+ "squizlabs/php_codesniffer": "^3.5",
+ "symfony/var-dumper": "^5.0 || ^6.0 || ^7.0"
+ },
+ "suggest": {
+ "ext-SimpleXML": "For Firefox profile creation"
},
+ "type": "library",
+ "autoload": {
+ "files": [
+ "lib/Exception/TimeoutException.php"
+ ],
+ "psr-4": {
+ "Facebook\\WebDriver\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.",
+ "homepage": "https://github.com/php-webdriver/php-webdriver",
+ "keywords": [
+ "Chromedriver",
+ "geckodriver",
+ "php",
+ "selenium",
+ "webdriver"
+ ],
+ "support": {
+ "issues": "https://github.com/php-webdriver/php-webdriver/issues",
+ "source": "https://github.com/php-webdriver/php-webdriver/tree/1.15.2"
+ },
+ "time": "2024-11-21T15:12:59+00:00"
+ },
+ {
+ "name": "phpstan/phpstan",
+ "version": "1.12.32",
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/384af967d35b2162f69526c7276acadce534d0e1",
- "reference": "384af967d35b2162f69526c7276acadce534d0e1",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8",
+ "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8",
"shasum": ""
},
"require": {
@@ -63,74 +542,4341 @@
"type": "github"
}
],
- "time": "2024-08-27T09:18:05+00:00"
+ "time": "2025-09-30T10:16:31+00:00"
},
{
- "name": "rector/rector",
- "version": "1.2.4",
+ "name": "phpunit/php-code-coverage",
+ "version": "12.4.0",
"source": {
"type": "git",
- "url": "https://github.com/rectorphp/rector.git",
- "reference": "42a4aa23b48b4cfc8ebfeac2b570364e27744381"
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/rectorphp/rector/zipball/42a4aa23b48b4cfc8ebfeac2b570364e27744381",
- "reference": "42a4aa23b48b4cfc8ebfeac2b570364e27744381",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c",
+ "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c",
"shasum": ""
},
"require": {
- "php": "^7.2|^8.0",
- "phpstan/phpstan": "^1.11.11"
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-xmlwriter": "*",
+ "nikic/php-parser": "^5.6.1",
+ "php": ">=8.3",
+ "phpunit/php-file-iterator": "^6.0",
+ "phpunit/php-text-template": "^5.0",
+ "sebastian/complexity": "^5.0",
+ "sebastian/environment": "^8.0.3",
+ "sebastian/lines-of-code": "^4.0",
+ "sebastian/version": "^6.0",
+ "theseer/tokenizer": "^1.2.3"
},
- "conflict": {
- "rector/rector-doctrine": "*",
- "rector/rector-downgrade-php": "*",
- "rector/rector-phpunit": "*",
- "rector/rector-symfony": "*"
+ "require-dev": {
+ "phpunit/phpunit": "^12.3.7"
},
"suggest": {
- "ext-dom": "To manipulate phpunit.xml via the custom-rule command"
+ "ext-pcov": "PHP extension that provides line coverage",
+ "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
- "bin": [
- "bin/rector"
- ],
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "12.4.x-dev"
+ }
+ },
"autoload": {
- "files": [
- "bootstrap.php"
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+ "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-24T13:44:41+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "961bc913d42fe24a257bfff826a5068079ac7782"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782",
+ "reference": "961bc913d42fe24a257bfff826a5068079ac7782",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+ "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:58:37+00:00"
+ },
+ {
+ "name": "phpunit/php-invoker",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406",
+ "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^12.0"
+ },
+ "suggest": {
+ "ext-pcntl": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Invoke callables with a timeout",
+ "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+ "keywords": [
+ "process"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+ "security": "https://github.com/sebastianbergmann/php-invoker/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:58:58+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53",
+ "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+ "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:59:16+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "8.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc",
+ "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "8.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "security": "https://github.com/sebastianbergmann/php-timer/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:59:38+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "12.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f62aab5794e36ccd26860db2d1bbf89ac19028d9",
+ "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.13.4",
+ "phar-io/manifest": "^2.0.4",
+ "phar-io/version": "^3.2.1",
+ "php": ">=8.3",
+ "phpunit/php-code-coverage": "^12.4.0",
+ "phpunit/php-file-iterator": "^6.0.0",
+ "phpunit/php-invoker": "^6.0.0",
+ "phpunit/php-text-template": "^5.0.0",
+ "phpunit/php-timer": "^8.0.0",
+ "sebastian/cli-parser": "^4.2.0",
+ "sebastian/comparator": "^7.1.3",
+ "sebastian/diff": "^7.0.0",
+ "sebastian/environment": "^8.0.3",
+ "sebastian/exporter": "^7.0.2",
+ "sebastian/global-state": "^8.0.2",
+ "sebastian/object-enumerator": "^7.0.0",
+ "sebastian/type": "^6.0.3",
+ "sebastian/version": "^6.0.0",
+ "staabm/side-effects-detector": "^1.0.5"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "12.4-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/Framework/Assert/Functions.php"
+ ],
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://phpunit.de/sponsors.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-10-03T04:28:03+00:00"
+ },
+ {
+ "name": "psr/cache",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/cache.git",
+ "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
+ "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Cache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for caching libraries",
+ "keywords": [
+ "cache",
+ "psr",
+ "psr-6"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/cache/tree/3.0.0"
+ },
+ "time": "2021-02-03T23:26:27+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
+ },
+ {
+ "name": "psr/event-dispatcher",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/event-dispatcher.git",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\EventDispatcher\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Standard interfaces for event handling.",
+ "keywords": [
+ "events",
+ "psr",
+ "psr-14"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/event-dispatcher/issues",
+ "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
+ },
+ "time": "2019-01-08T18:20:26+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
+ },
+ "time": "2024-09-11T13:17:53+00:00"
+ },
+ {
+ "name": "rector/rector",
+ "version": "1.2.10",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/rectorphp/rector.git",
+ "reference": "40f9cf38c05296bd32f444121336a521a293fa61"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/rectorphp/rector/zipball/40f9cf38c05296bd32f444121336a521a293fa61",
+ "reference": "40f9cf38c05296bd32f444121336a521a293fa61",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2|^8.0",
+ "phpstan/phpstan": "^1.12.5"
+ },
+ "conflict": {
+ "rector/rector-doctrine": "*",
+ "rector/rector-downgrade-php": "*",
+ "rector/rector-phpunit": "*",
+ "rector/rector-symfony": "*"
+ },
+ "suggest": {
+ "ext-dom": "To manipulate phpunit.xml via the custom-rule command"
+ },
+ "bin": [
+ "bin/rector"
+ ],
+ "type": "library",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Instant Upgrade and Automated Refactoring of any PHP code",
+ "keywords": [
+ "automation",
+ "dev",
+ "migration",
+ "refactoring"
+ ],
+ "support": {
+ "issues": "https://github.com/rectorphp/rector/issues",
+ "source": "https://github.com/rectorphp/rector/tree/1.2.10"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/tomasvotruba",
+ "type": "github"
+ }
+ ],
+ "time": "2024-11-08T13:59:10+00:00"
+ },
+ {
+ "name": "sebastian/cli-parser",
+ "version": "4.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/90f41072d220e5c40df6e8635f5dafba2d9d4d04",
+ "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for parsing CLI options",
+ "homepage": "https://github.com/sebastianbergmann/cli-parser",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+ "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-14T09:36:45+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "7.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dc904b4bb3ab070865fa4068cd84f3da8b945148",
+ "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-mbstring": "*",
+ "php": ">=8.3",
+ "sebastian/diff": "^7.0",
+ "sebastian/exporter": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.2"
+ },
+ "suggest": {
+ "ext-bcmath": "For comparing BcMath\\Number objects"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
+ "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-20T11:27:00+00:00"
+ },
+ {
+ "name": "sebastian/complexity",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb",
+ "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for calculating the complexity of PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/complexity",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/complexity/issues",
+ "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:55:25+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "7.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "7ab1ea946c012266ca32390913653d844ecd085f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f",
+ "reference": "7ab1ea946c012266ca32390913653d844ecd085f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0",
+ "symfony/process": "^7.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
+ "security": "https://github.com/sebastianbergmann/diff/security/policy",
+ "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:55:46+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "8.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/24a711b5c916efc6d6e62aa65aa2ec98fef77f68",
+ "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "suggest": {
+ "ext-posix": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "8.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "https://github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
+ "security": "https://github.com/sebastianbergmann/environment/security/policy",
+ "source": "https://github.com/sebastianbergmann/environment/tree/8.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/environment",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-12T14:11:56+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "7.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "016951ae10980765e4e7aee491eb288c64e505b7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/016951ae10980765e4e7aee491eb288c64e505b7",
+ "reference": "016951ae10980765e4e7aee491eb288c64e505b7",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=8.3",
+ "sebastian/recursion-context": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "https://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
+ "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-24T06:16:11+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "8.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "ef1377171613d09edd25b7816f05be8313f9115d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d",
+ "reference": "ef1377171613d09edd25b7816f05be8313f9115d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3",
+ "sebastian/object-reflector": "^5.0",
+ "sebastian/recursion-context": "^7.0"
+ },
+ "require-dev": {
+ "ext-dom": "*",
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "8.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "https://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/global-state/issues",
+ "security": "https://github.com/sebastianbergmann/global-state/security/policy",
+ "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-29T11:29:25+00:00"
+ },
+ {
+ "name": "sebastian/lines-of-code",
+ "version": "4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f",
+ "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for counting the lines of code in PHP source code",
+ "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+ "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:57:28+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "7.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894",
+ "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3",
+ "sebastian/object-reflector": "^5.0",
+ "sebastian/recursion-context": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+ "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:57:48+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "4bfa827c969c98be1e527abd576533293c634f6a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a",
+ "reference": "4bfa827c969c98be1e527abd576533293c634f6a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+ "security": "https://github.com/sebastianbergmann/object-reflector/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T04:58:17+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "7.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c",
+ "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "https://github.com/sebastianbergmann/recursion-context",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+ "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-13T04:44:59+00:00"
+ },
+ {
+ "name": "sebastian/type",
+ "version": "6.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/type.git",
+ "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d",
+ "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^12.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the types of the PHP type system",
+ "homepage": "https://github.com/sebastianbergmann/type",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/type/issues",
+ "security": "https://github.com/sebastianbergmann/type/security/policy",
+ "source": "https://github.com/sebastianbergmann/type/tree/6.0.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/type",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-09T06:57:12+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c",
+ "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/version/issues",
+ "security": "https://github.com/sebastianbergmann/version/security/policy",
+ "source": "https://github.com/sebastianbergmann/version/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2025-02-07T05:00:38+00:00"
+ },
+ {
+ "name": "staabm/side-effects-detector",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/staabm/side-effects-detector.git",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": "^7.4 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/extension-installer": "^1.4.3",
+ "phpstan/phpstan": "^1.12.6",
+ "phpunit/phpunit": "^9.6.21",
+ "symfony/var-dumper": "^5.4.43",
+ "tomasvotruba/type-coverage": "1.0.0",
+ "tomasvotruba/unused-public": "1.0.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "lib/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A static analysis tool to detect side effects in PHP code",
+ "keywords": [
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/staabm/side-effects-detector/issues",
+ "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/staabm",
+ "type": "github"
+ }
+ ],
+ "time": "2024-10-20T05:08:20+00:00"
+ },
+ {
+ "name": "symfony/browser-kit",
+ "version": "v7.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/browser-kit.git",
+ "reference": "f0b889b73a845cddef1d25fe207b37fd04cb5419"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/browser-kit/zipball/f0b889b73a845cddef1d25fe207b37fd04cb5419",
+ "reference": "f0b889b73a845cddef1d25fe207b37fd04cb5419",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/dom-crawler": "^6.4|^7.0"
+ },
+ "require-dev": {
+ "symfony/css-selector": "^6.4|^7.0",
+ "symfony/http-client": "^6.4|^7.0",
+ "symfony/mime": "^6.4|^7.0",
+ "symfony/process": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\BrowserKit\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/browser-kit/tree/v7.3.2"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-10T08:47:49+00:00"
+ },
+ {
+ "name": "symfony/cache",
+ "version": "v7.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/cache.git",
+ "reference": "4a55feb59664f49042a0824c0f955e2f4c1412ad"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/cache/zipball/4a55feb59664f49042a0824c0f955e2f4c1412ad",
+ "reference": "4a55feb59664f49042a0824c0f955e2f4c1412ad",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/cache": "^2.0|^3.0",
+ "psr/log": "^1.1|^2|^3",
+ "symfony/cache-contracts": "^3.6",
+ "symfony/deprecation-contracts": "^2.5|^3.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/var-exporter": "^6.4|^7.0"
+ },
+ "conflict": {
+ "doctrine/dbal": "<3.6",
+ "symfony/dependency-injection": "<6.4",
+ "symfony/http-kernel": "<6.4",
+ "symfony/var-dumper": "<6.4"
+ },
+ "provide": {
+ "psr/cache-implementation": "2.0|3.0",
+ "psr/simple-cache-implementation": "1.0|2.0|3.0",
+ "symfony/cache-implementation": "1.1|2.0|3.0"
+ },
+ "require-dev": {
+ "cache/integration-tests": "dev-master",
+ "doctrine/dbal": "^3.6|^4",
+ "predis/predis": "^1.1|^2.0",
+ "psr/simple-cache": "^1.0|^2.0|^3.0",
+ "symfony/clock": "^6.4|^7.0",
+ "symfony/config": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/filesystem": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/messenger": "^6.4|^7.0",
+ "symfony/var-dumper": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Cache\\": ""
+ },
+ "classmap": [
+ "Traits/ValueWrapper.php"
+ ],
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides extended PSR-6, PSR-16 (and tags) implementations",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "caching",
+ "psr6"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/cache/tree/v7.3.5"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-10-16T13:55:38+00:00"
+ },
+ {
+ "name": "symfony/cache-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/cache-contracts.git",
+ "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868",
+ "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/cache": "^3.0"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Cache\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to caching",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-03-13T15:25:07+00:00"
+ },
+ {
+ "name": "symfony/config",
+ "version": "v7.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/config.git",
+ "reference": "8a09223170046d2cfda3d2e11af01df2c641e961"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/config/zipball/8a09223170046d2cfda3d2e11af01df2c641e961",
+ "reference": "8a09223170046d2cfda3d2e11af01df2c641e961",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/filesystem": "^7.1",
+ "symfony/polyfill-ctype": "~1.8"
+ },
+ "conflict": {
+ "symfony/finder": "<6.4",
+ "symfony/service-contracts": "<2.5"
+ },
+ "require-dev": {
+ "symfony/event-dispatcher": "^6.4|^7.0",
+ "symfony/finder": "^6.4|^7.0",
+ "symfony/messenger": "^6.4|^7.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/yaml": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Config\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/config/tree/v7.3.4"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-22T12:46:16+00:00"
+ },
+ {
+ "name": "symfony/css-selector",
+ "version": "v7.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/css-selector.git",
+ "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2",
+ "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\CssSelector\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Jean-François Simon",
+ "email": "jeanfrancois.simon@sensiolabs.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Converts CSS selectors to XPath expressions",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/css-selector/tree/v7.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/dependency-injection",
+ "version": "v7.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/dependency-injection.git",
+ "reference": "82119812ab0bf3425c1234d413efd1b19bb92ae4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/82119812ab0bf3425c1234d413efd1b19bb92ae4",
+ "reference": "82119812ab0bf3425c1234d413efd1b19bb92ae4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/service-contracts": "^3.5",
+ "symfony/var-exporter": "^6.4.20|^7.2.5"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2",
+ "symfony/config": "<6.4",
+ "symfony/finder": "<6.4",
+ "symfony/yaml": "<6.4"
+ },
+ "provide": {
+ "psr/container-implementation": "1.1|2.0",
+ "symfony/service-implementation": "1.1|2.0|3.0"
+ },
+ "require-dev": {
+ "symfony/config": "^6.4|^7.0",
+ "symfony/expression-language": "^6.4|^7.0",
+ "symfony/yaml": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\DependencyInjection\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Allows you to standardize and centralize the way objects are constructed in your application",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/dependency-injection/tree/v7.3.4"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-11T10:12:26+00:00"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/dom-crawler",
+ "version": "v7.3.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/dom-crawler.git",
+ "reference": "efa076ea0eeff504383ff0dcf827ea5ce15690ba"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/efa076ea0eeff504383ff0dcf827ea5ce15690ba",
+ "reference": "efa076ea0eeff504383ff0dcf827ea5ce15690ba",
+ "shasum": ""
+ },
+ "require": {
+ "masterminds/html5": "^2.6",
+ "php": ">=8.2",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.0"
+ },
+ "require-dev": {
+ "symfony/css-selector": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\DomCrawler\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Eases DOM navigation for HTML and XML documents",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/dom-crawler/tree/v7.3.3"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-06T20:13:54+00:00"
+ },
+ {
+ "name": "symfony/error-handler",
+ "version": "v7.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/error-handler.git",
+ "reference": "99f81bc944ab8e5dae4f21b4ca9972698bbad0e4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/error-handler/zipball/99f81bc944ab8e5dae4f21b4ca9972698bbad0e4",
+ "reference": "99f81bc944ab8e5dae4f21b4ca9972698bbad0e4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/log": "^1|^2|^3",
+ "symfony/var-dumper": "^6.4|^7.0"
+ },
+ "conflict": {
+ "symfony/deprecation-contracts": "<2.5",
+ "symfony/http-kernel": "<6.4"
+ },
+ "require-dev": {
+ "symfony/console": "^6.4|^7.0",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/serializer": "^6.4|^7.0",
+ "symfony/webpack-encore-bundle": "^1.0|^2.0"
+ },
+ "bin": [
+ "Resources/bin/patch-type-declarations"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\ErrorHandler\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides tools to manage errors and ease debugging PHP code",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/error-handler/tree/v7.3.4"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-11T10:12:26+00:00"
+ },
+ {
+ "name": "symfony/event-dispatcher",
+ "version": "v7.3.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/event-dispatcher.git",
+ "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191",
+ "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/event-dispatcher-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<6.4",
+ "symfony/service-contracts": "<2.5"
+ },
+ "provide": {
+ "psr/event-dispatcher-implementation": "1.0",
+ "symfony/event-dispatcher-implementation": "2.0|3.0"
+ },
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/error-handler": "^6.4|^7.0",
+ "symfony/expression-language": "^6.4|^7.0",
+ "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/stopwatch": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\EventDispatcher\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-08-13T11:49:31+00:00"
+ },
+ {
+ "name": "symfony/event-dispatcher-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/event-dispatcher-contracts.git",
+ "reference": "59eb412e93815df44f05f342958efa9f46b1e586"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586",
+ "reference": "59eb412e93815df44f05f342958efa9f46b1e586",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/event-dispatcher": "^1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\EventDispatcher\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to dispatching event",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/filesystem",
+ "version": "v7.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/filesystem.git",
+ "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd",
+ "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.8"
+ },
+ "require-dev": {
+ "symfony/process": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Filesystem\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides basic utilities for the filesystem",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/filesystem/tree/v7.3.2"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-07T08:17:47+00:00"
+ },
+ {
+ "name": "symfony/finder",
+ "version": "v7.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/finder.git",
+ "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
+ "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "symfony/filesystem": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Finder\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Finds files and directories via an intuitive fluent interface",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/finder/tree/v7.3.2"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-15T13:41:35+00:00"
+ },
+ {
+ "name": "symfony/framework-bundle",
+ "version": "v7.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/framework-bundle.git",
+ "reference": "ebd42b1fc2652b96d33520195ea0f6e55c36f09d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/ebd42b1fc2652b96d33520195ea0f6e55c36f09d",
+ "reference": "ebd42b1fc2652b96d33520195ea0f6e55c36f09d",
+ "shasum": ""
+ },
+ "require": {
+ "composer-runtime-api": ">=2.1",
+ "ext-xml": "*",
+ "php": ">=8.2",
+ "symfony/cache": "^6.4|^7.0",
+ "symfony/config": "^7.3",
+ "symfony/dependency-injection": "^7.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/error-handler": "^7.3",
+ "symfony/event-dispatcher": "^6.4|^7.0",
+ "symfony/filesystem": "^7.1",
+ "symfony/finder": "^6.4|^7.0",
+ "symfony/http-foundation": "^7.3",
+ "symfony/http-kernel": "^7.2",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/routing": "^6.4|^7.0"
+ },
+ "conflict": {
+ "doctrine/persistence": "<1.3",
+ "phpdocumentor/reflection-docblock": "<3.2.2",
+ "phpdocumentor/type-resolver": "<1.4.0",
+ "symfony/asset": "<6.4",
+ "symfony/asset-mapper": "<6.4",
+ "symfony/clock": "<6.4",
+ "symfony/console": "<6.4",
+ "symfony/dom-crawler": "<6.4",
+ "symfony/dotenv": "<6.4",
+ "symfony/form": "<6.4",
+ "symfony/http-client": "<6.4",
+ "symfony/json-streamer": ">=7.4",
+ "symfony/lock": "<6.4",
+ "symfony/mailer": "<6.4",
+ "symfony/messenger": "<6.4",
+ "symfony/mime": "<6.4",
+ "symfony/object-mapper": ">=7.4",
+ "symfony/property-access": "<6.4",
+ "symfony/property-info": "<6.4",
+ "symfony/runtime": "<6.4.13|>=7.0,<7.1.6",
+ "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4",
+ "symfony/security-core": "<6.4",
+ "symfony/security-csrf": "<7.2",
+ "symfony/serializer": "<7.2.5",
+ "symfony/stopwatch": "<6.4",
+ "symfony/translation": "<7.3",
+ "symfony/twig-bridge": "<6.4",
+ "symfony/twig-bundle": "<6.4",
+ "symfony/validator": "<6.4",
+ "symfony/web-profiler-bundle": "<6.4",
+ "symfony/webhook": "<7.2",
+ "symfony/workflow": "<7.3.0-beta2"
+ },
+ "require-dev": {
+ "doctrine/persistence": "^1.3|^2|^3",
+ "dragonmantank/cron-expression": "^3.1",
+ "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
+ "seld/jsonlint": "^1.10",
+ "symfony/asset": "^6.4|^7.0",
+ "symfony/asset-mapper": "^6.4|^7.0",
+ "symfony/browser-kit": "^6.4|^7.0",
+ "symfony/clock": "^6.4|^7.0",
+ "symfony/console": "^6.4|^7.0",
+ "symfony/css-selector": "^6.4|^7.0",
+ "symfony/dom-crawler": "^6.4|^7.0",
+ "symfony/dotenv": "^6.4|^7.0",
+ "symfony/expression-language": "^6.4|^7.0",
+ "symfony/form": "^6.4|^7.0",
+ "symfony/html-sanitizer": "^6.4|^7.0",
+ "symfony/http-client": "^6.4|^7.0",
+ "symfony/json-streamer": "7.3.*",
+ "symfony/lock": "^6.4|^7.0",
+ "symfony/mailer": "^6.4|^7.0",
+ "symfony/messenger": "^6.4|^7.0",
+ "symfony/mime": "^6.4|^7.0",
+ "symfony/notifier": "^6.4|^7.0",
+ "symfony/object-mapper": "^v7.3.0-beta2",
+ "symfony/polyfill-intl-icu": "~1.0",
+ "symfony/process": "^6.4|^7.0",
+ "symfony/property-info": "^6.4|^7.0",
+ "symfony/rate-limiter": "^6.4|^7.0",
+ "symfony/scheduler": "^6.4.4|^7.0.4",
+ "symfony/security-bundle": "^6.4|^7.0",
+ "symfony/semaphore": "^6.4|^7.0",
+ "symfony/serializer": "^7.2.5",
+ "symfony/stopwatch": "^6.4|^7.0",
+ "symfony/string": "^6.4|^7.0",
+ "symfony/translation": "^7.3",
+ "symfony/twig-bundle": "^6.4|^7.0",
+ "symfony/type-info": "^7.1.8",
+ "symfony/uid": "^6.4|^7.0",
+ "symfony/validator": "^6.4|^7.0",
+ "symfony/web-link": "^6.4|^7.0",
+ "symfony/webhook": "^7.2",
+ "symfony/workflow": "^7.3",
+ "symfony/yaml": "^6.4|^7.0",
+ "twig/twig": "^3.12"
+ },
+ "type": "symfony-bundle",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bundle\\FrameworkBundle\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/framework-bundle/tree/v7.3.5"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-10-16T16:16:53+00:00"
+ },
+ {
+ "name": "symfony/http-client",
+ "version": "v7.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/http-client.git",
+ "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62",
+ "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/log": "^1|^2|^3",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/http-client-contracts": "~3.4.4|^3.5.2",
+ "symfony/polyfill-php83": "^1.29",
+ "symfony/service-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "amphp/amp": "<2.5",
+ "amphp/socket": "<1.1",
+ "php-http/discovery": "<1.15",
+ "symfony/http-foundation": "<6.4"
+ },
+ "provide": {
+ "php-http/async-client-implementation": "*",
+ "php-http/client-implementation": "*",
+ "psr/http-client-implementation": "1.0",
+ "symfony/http-client-implementation": "3.0"
+ },
+ "require-dev": {
+ "amphp/http-client": "^4.2.1|^5.0",
+ "amphp/http-tunnel": "^1.0|^2.0",
+ "guzzlehttp/promises": "^1.4|^2.0",
+ "nyholm/psr7": "^1.0",
+ "php-http/httplug": "^1.0|^2.0",
+ "psr/http-client": "^1.0",
+ "symfony/amphp-http-client-meta": "^1.0|^2.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/messenger": "^6.4|^7.0",
+ "symfony/process": "^6.4|^7.0",
+ "symfony/rate-limiter": "^6.4|^7.0",
+ "symfony/stopwatch": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\HttpClient\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "http"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/http-client/tree/v7.3.4"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-11T10:12:26+00:00"
+ },
+ {
+ "name": "symfony/http-client-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/http-client-contracts.git",
+ "reference": "75d7043853a42837e68111812f4d964b01e5101c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c",
+ "reference": "75d7043853a42837e68111812f4d964b01e5101c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\HttpClient\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to HTTP clients",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-04-29T11:18:49+00:00"
+ },
+ {
+ "name": "symfony/http-foundation",
+ "version": "v7.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/http-foundation.git",
+ "reference": "ce31218c7cac92eab280762c4375fb70a6f4f897"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ce31218c7cac92eab280762c4375fb70a6f4f897",
+ "reference": "ce31218c7cac92eab280762c4375fb70a6f4f897",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3.0",
+ "symfony/polyfill-mbstring": "~1.1",
+ "symfony/polyfill-php83": "^1.27"
+ },
+ "conflict": {
+ "doctrine/dbal": "<3.6",
+ "symfony/cache": "<6.4.12|>=7.0,<7.1.5"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^3.6|^4",
+ "predis/predis": "^1.1|^2.0",
+ "symfony/cache": "^6.4.12|^7.1.5",
+ "symfony/clock": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/expression-language": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/mime": "^6.4|^7.0",
+ "symfony/rate-limiter": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\HttpFoundation\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Defines an object-oriented layer for the HTTP specification",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/http-foundation/tree/v7.3.5"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-10-24T21:42:11+00:00"
+ },
+ {
+ "name": "symfony/http-kernel",
+ "version": "v7.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/http-kernel.git",
+ "reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/24fd3f123532e26025f49f1abefcc01a69ef15ab",
+ "reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/log": "^1|^2|^3",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/error-handler": "^6.4|^7.0",
+ "symfony/event-dispatcher": "^7.3",
+ "symfony/http-foundation": "^7.3",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "conflict": {
+ "symfony/browser-kit": "<6.4",
+ "symfony/cache": "<6.4",
+ "symfony/config": "<6.4",
+ "symfony/console": "<6.4",
+ "symfony/dependency-injection": "<6.4",
+ "symfony/doctrine-bridge": "<6.4",
+ "symfony/form": "<6.4",
+ "symfony/http-client": "<6.4",
+ "symfony/http-client-contracts": "<2.5",
+ "symfony/mailer": "<6.4",
+ "symfony/messenger": "<6.4",
+ "symfony/translation": "<6.4",
+ "symfony/translation-contracts": "<2.5",
+ "symfony/twig-bridge": "<6.4",
+ "symfony/validator": "<6.4",
+ "symfony/var-dumper": "<6.4",
+ "twig/twig": "<3.12"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0|2.0|3.0"
+ },
+ "require-dev": {
+ "psr/cache": "^1.0|^2.0|^3.0",
+ "symfony/browser-kit": "^6.4|^7.0",
+ "symfony/clock": "^6.4|^7.0",
+ "symfony/config": "^6.4|^7.0",
+ "symfony/console": "^6.4|^7.0",
+ "symfony/css-selector": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/dom-crawler": "^6.4|^7.0",
+ "symfony/expression-language": "^6.4|^7.0",
+ "symfony/finder": "^6.4|^7.0",
+ "symfony/http-client-contracts": "^2.5|^3",
+ "symfony/process": "^6.4|^7.0",
+ "symfony/property-access": "^7.1",
+ "symfony/routing": "^6.4|^7.0",
+ "symfony/serializer": "^7.1",
+ "symfony/stopwatch": "^6.4|^7.0",
+ "symfony/translation": "^6.4|^7.0",
+ "symfony/translation-contracts": "^2.5|^3",
+ "symfony/uid": "^6.4|^7.0",
+ "symfony/validator": "^6.4|^7.0",
+ "symfony/var-dumper": "^6.4|^7.0",
+ "symfony/var-exporter": "^6.4|^7.0",
+ "twig/twig": "^3.12"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\HttpKernel\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides a structured process for converting a Request into a Response",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/http-kernel/tree/v7.3.5"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-10-28T10:19:01+00:00"
+ },
+ {
+ "name": "symfony/panther",
+ "version": "v2.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/panther.git",
+ "reference": "b7e0f834c9046918972edb3dde2ecc4a20f6155e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/panther/zipball/b7e0f834c9046918972edb3dde2ecc4a20f6155e",
+ "reference": "b7e0f834c9046918972edb3dde2ecc4a20f6155e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "php": ">=8.0",
+ "php-webdriver/webdriver": "^1.8.2",
+ "symfony/browser-kit": "^5.4 || ^6.4 || ^7.0",
+ "symfony/dependency-injection": "^5.4 || ^6.4 || ^7.0",
+ "symfony/deprecation-contracts": "^2.4 || ^3",
+ "symfony/dom-crawler": "^5.4 || ^6.4 || ^7.0",
+ "symfony/http-client": "^6.4 || ^7.0",
+ "symfony/http-kernel": "^5.4 || ^6.4 || ^7.0",
+ "symfony/process": "^5.4 || ^6.4 || ^7.0"
+ },
+ "require-dev": {
+ "symfony/css-selector": "^5.4 || ^6.4 || ^7.0",
+ "symfony/framework-bundle": "^5.4 || ^6.4 || ^7.0",
+ "symfony/mime": "^5.4 || ^6.4 || ^7.0",
+ "symfony/phpunit-bridge": "^7.2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Panther\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Kévin Dunglas",
+ "email": "dunglas@gmail.com",
+ "homepage": "https://dunglas.fr"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "A browser testing and web scraping library for PHP and Symfony.",
+ "homepage": "https://dunglas.fr",
+ "keywords": [
+ "e2e",
+ "scraping",
+ "selenium",
+ "symfony",
+ "testing",
+ "webdriver"
+ ],
+ "support": {
+ "issues": "https://github.com/symfony/panther/issues",
+ "source": "https://github.com/symfony/panther/tree/v2.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://www.panthera.org/donate",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/dunglas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/panther",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-01-30T13:11:55+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-12-23T08:48:59+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php80",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
+ "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-01-02T08:10:11+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php81",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php81.git",
+ "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
+ "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php81\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php83",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php83.git",
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php83\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-08T02:45:35+00:00"
+ },
+ {
+ "name": "symfony/process",
+ "version": "v7.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/process.git",
+ "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b",
+ "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Process\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Executes commands in sub-processes",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/process/tree/v7.3.4"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-11T10:12:26+00:00"
+ },
+ {
+ "name": "symfony/routing",
+ "version": "v7.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/routing.git",
+ "reference": "8dc648e159e9bac02b703b9fbd937f19ba13d07c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/routing/zipball/8dc648e159e9bac02b703b9fbd937f19ba13d07c",
+ "reference": "8dc648e159e9bac02b703b9fbd937f19ba13d07c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "symfony/config": "<6.4",
+ "symfony/dependency-injection": "<6.4",
+ "symfony/yaml": "<6.4"
+ },
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/expression-language": "^6.4|^7.0",
+ "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/yaml": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Routing\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Maps an HTTP request to a set of configuration variables",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "router",
+ "routing",
+ "uri",
+ "url"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/routing/tree/v7.3.4"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-11T10:12:26+00:00"
+ },
+ {
+ "name": "symfony/service-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
- "description": "Instant Upgrade and Automated Refactoring of any PHP code",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-04-25T09:37:31+00:00"
+ },
+ {
+ "name": "symfony/var-dumper",
+ "version": "v7.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/var-dumper.git",
+ "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
+ "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-mbstring": "~1.0"
+ },
+ "conflict": {
+ "symfony/console": "<6.4"
+ },
+ "require-dev": {
+ "symfony/console": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/process": "^6.4|^7.0",
+ "symfony/uid": "^6.4|^7.0",
+ "twig/twig": "^3.12"
+ },
+ "bin": [
+ "Resources/bin/var-dump-server"
+ ],
+ "type": "library",
+ "autoload": {
+ "files": [
+ "Resources/functions/dump.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\VarDumper\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides mechanisms for walking through any arbitrary PHP variable",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "debug",
+ "dump"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/var-dumper/tree/v7.3.5"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-27T09:00:46+00:00"
+ },
+ {
+ "name": "symfony/var-exporter",
+ "version": "v7.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/var-exporter.git",
+ "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0f020b544a30a7fe8ba972e53ee48a74c0bc87f4",
+ "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "require-dev": {
+ "symfony/property-access": "^6.4|^7.0",
+ "symfony/serializer": "^6.4|^7.0",
+ "symfony/var-dumper": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\VarExporter\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Allows exporting any serializable PHP data structure to plain PHP code",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "clone",
+ "construct",
+ "export",
+ "hydrate",
+ "instantiate",
+ "lazy-loading",
+ "proxy",
+ "serialize"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/var-exporter/tree/v7.3.4"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-11T10:12:26+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "support": {
+ "issues": "https://github.com/theseer/tokenizer/issues",
+ "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:36:25+00:00"
+ },
+ {
+ "name": "zenstruck/assert",
+ "version": "v1.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zenstruck/assert.git",
+ "reference": "f333d554e9f8e275e221f5b27bdbdc1b0aadbf02"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zenstruck/assert/zipball/f333d554e9f8e275e221f5b27bdbdc1b0aadbf02",
+ "reference": "f333d554e9f8e275e221f5b27bdbdc1b0aadbf02",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0",
+ "symfony/polyfill-php81": "^1.23",
+ "symfony/var-exporter": "^5.4|^6.0|^7.0|^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.4",
+ "phpunit/phpunit": "^9.5.21",
+ "symfony/phpunit-bridge": "^6.3|^7.0|^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Zenstruck\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Kevin Bond",
+ "email": "kevinbond@gmail.com"
+ }
+ ],
+ "description": "Standalone, lightweight, framework agnostic, test assertion library.",
+ "homepage": "https://github.com/zenstruck/assert",
+ "keywords": [
+ "assertion",
+ "phpunit",
+ "test"
+ ],
+ "support": {
+ "issues": "https://github.com/zenstruck/assert/issues",
+ "source": "https://github.com/zenstruck/assert/tree/v1.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/kbond",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nikophil",
+ "type": "github"
+ }
+ ],
+ "time": "2025-11-02T14:41:16+00:00"
+ },
+ {
+ "name": "zenstruck/browser",
+ "version": "v1.9.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zenstruck/browser.git",
+ "reference": "a1518531749b157347de60eef2a0a6f5fbd97b97"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zenstruck/browser/zipball/a1518531749b157347de60eef2a0a6f5fbd97b97",
+ "reference": "a1518531749b157347de60eef2a0a6f5fbd97b97",
+ "shasum": ""
+ },
+ "require": {
+ "behat/mink": "^1.8",
+ "php": ">=8.0",
+ "symfony/browser-kit": "^5.4|^6.0|^7.0",
+ "symfony/css-selector": "^5.4|^6.0|^7.0",
+ "symfony/dom-crawler": "^5.4|^6.0|^7.0",
+ "symfony/framework-bundle": "^5.4|^6.0|^7.0",
+ "zenstruck/assert": "^1.1",
+ "zenstruck/callback": "^1.4.2"
+ },
+ "require-dev": {
+ "dbrekelmans/bdi": "^1.0",
+ "justinrainbow/json-schema": "^5.3",
+ "mtdowling/jmespath.php": "^2.6",
+ "phpstan/phpstan": "^1.4",
+ "phpunit/phpunit": "^9.6.21|^10.4",
+ "symfony/mime": "^5.4|^6.0|^7.0",
+ "symfony/panther": "^1.1|^2.0.1",
+ "symfony/phpunit-bridge": "^6.0|^7.0",
+ "symfony/security-bundle": "^5.4|^6.0|^7.0"
+ },
+ "suggest": {
+ "justinrainbow/json-schema": "Json schema validator. Needed to use Json::assertMatchesSchema().",
+ "mtdowling/jmespath.php": "PHP implementation for JMESPath. Needed to use Json assertions."
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Zenstruck\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Kevin Bond",
+ "email": "kevinbond@gmail.com"
+ }
+ ],
+ "description": "A fluent interface for your Symfony functional tests.",
+ "homepage": "https://github.com/zenstruck/browser",
"keywords": [
- "automation",
"dev",
- "migration",
- "refactoring"
+ "symfony",
+ "test"
],
"support": {
- "issues": "https://github.com/rectorphp/rector/issues",
- "source": "https://github.com/rectorphp/rector/tree/1.2.4"
+ "issues": "https://github.com/zenstruck/browser/issues",
+ "source": "https://github.com/zenstruck/browser/tree/v1.9.1"
},
"funding": [
{
- "url": "https://github.com/tomasvotruba",
+ "url": "https://github.com/kbond",
+ "type": "github"
+ }
+ ],
+ "time": "2024-11-05T12:21:53+00:00"
+ },
+ {
+ "name": "zenstruck/callback",
+ "version": "v1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/zenstruck/callback.git",
+ "reference": "eed9a532fd8974368e60c4a2550ed65eab7e5432"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/zenstruck/callback/zipball/eed9a532fd8974368e60c4a2550ed65eab7e5432",
+ "reference": "eed9a532fd8974368e60c4a2550ed65eab7e5432",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.5",
+ "symfony/polyfill-php80": "^1.14"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "^5.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Zenstruck\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Kevin Bond",
+ "email": "kevinbond@gmail.com"
+ }
+ ],
+ "description": "Callable wrapper to validate and inject arguments.",
+ "homepage": "https://github.com/zenstruck/callback",
+ "keywords": [
+ "callable",
+ "callback",
+ "utility"
+ ],
+ "support": {
+ "issues": "https://github.com/zenstruck/callback/issues",
+ "source": "https://github.com/zenstruck/callback/tree/v1.5.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/kbond",
"type": "github"
}
],
- "time": "2024-08-23T09:03:01+00:00"
+ "time": "2022-08-31T14:56:15+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
- "platform": [],
- "platform-dev": [],
+ "platform": {},
+ "platform-dev": {},
"plugin-api-version": "2.6.0"
}
diff --git a/package.json b/package.json
index 595a1ae..17da06f 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,15 @@
{
- "private": true,
- "scripts": {
- "dev": "tailwindcss -i resources/css/settings.css -o build/css/settings.css --watch",
- "build": "tailwindcss build -i resources/css/settings.css -o build/css/settings.css"
- },
- "devDependencies": {
- "@tailwindcss/forms": "^0.5.8",
- "tailwindcss": "^3.4.10"
- }
+ "private": true,
+ "scripts": {
+ "dev": "tailwindcss -i resources/css/settings.css -o build/css/settings.css --watch",
+ "build": "tailwindcss build -i resources/css/settings.css -o build/css/settings.css",
+ "tests:install": "playwright install --with-deps chromium",
+ "tests": "playwright test"
+ },
+ "devDependencies": {
+ "@tailwindcss/forms": "^0.5.10",
+ "@types/node": "^22.18.10",
+ "playwright": "^1.56.1",
+ "tailwindcss": "^3.4.18"
+ }
}
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..ae4dafb
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ ./tests
+
+
+
+
+
+
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fa86b90..8086be1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,11 +9,17 @@ importers:
.:
devDependencies:
'@tailwindcss/forms':
- specifier: ^0.5.8
- version: 0.5.8(tailwindcss@3.4.10)
+ specifier: ^0.5.10
+ version: 0.5.10(tailwindcss@3.4.18(yaml@2.5.0))
+ '@types/node':
+ specifier: ^22.18.10
+ version: 22.18.10
+ playwright:
+ specifier: ^1.56.1
+ version: 1.56.1
tailwindcss:
- specifier: ^3.4.10
- version: 3.4.10
+ specifier: ^3.4.18
+ version: 3.4.18(yaml@2.5.0)
packages:
@@ -25,23 +31,18 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
- '@jridgewell/gen-mapping@0.3.5':
- resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
- engines: {node: '>=6.0.0'}
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
'@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
- '@jridgewell/set-array@1.2.1':
- resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
- engines: {node: '>=6.0.0'}
-
- '@jridgewell/sourcemap-codec@1.5.0':
- resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
- '@jridgewell/trace-mapping@0.3.25':
- resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
@@ -59,25 +60,28 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
- '@tailwindcss/forms@0.5.8':
- resolution: {integrity: sha512-DJs7B7NPD0JH7BVvdHWNviWmunlFhuEkz7FyFxE4japOWYMLl9b1D6+Z9mivJJPWr6AEbmlPqgiFRyLwFB1SgQ==}
+ '@tailwindcss/forms@0.5.10':
+ resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==}
peerDependencies:
- tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20'
+ tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1'
+
+ '@types/node@22.18.10':
+ resolution: {integrity: sha512-anNG/V/Efn/YZY4pRzbACnKxNKoBng2VTFydVu8RRs5hQjikP8CQfaeAV59VFSCzKNp90mXiVXW2QzV56rwMrg==}
ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
- ansi-regex@6.0.1:
- resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+ ansi-regex@6.2.2:
+ resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==}
engines: {node: '>=12'}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
- ansi-styles@6.2.1:
- resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+ ansi-styles@6.2.3:
+ resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
any-promise@1.3.0:
@@ -97,8 +101,8 @@ packages:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
- brace-expansion@2.0.1:
- resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ brace-expansion@2.0.2:
+ resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
@@ -123,8 +127,8 @@ packages:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
- cross-spawn@7.0.3:
- resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
cssesc@3.0.0:
@@ -147,21 +151,26 @@ packages:
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
- fast-glob@3.3.2:
- resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
+ fast-glob@3.3.3:
+ resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
engines: {node: '>=8.6.0'}
- fastq@1.17.1:
- resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
+ fastq@1.19.1:
+ resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
- foreground-child@3.3.0:
- resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
+ foreground-child@3.3.1:
+ resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
+ fsevents@2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -190,8 +199,8 @@ packages:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
- is-core-module@2.15.1:
- resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
engines: {node: '>= 0.4'}
is-extglob@2.1.1:
@@ -216,16 +225,12 @@ packages:
jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
- jiti@1.21.6:
- resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
+ jiti@1.21.7:
+ resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
hasBin: true
- lilconfig@2.1.0:
- resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
- engines: {node: '>=10'}
-
- lilconfig@3.1.2:
- resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==}
+ lilconfig@3.1.3:
+ resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
engines: {node: '>=14'}
lines-and-columns@1.2.4:
@@ -257,8 +262,8 @@ packages:
mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
- nanoid@3.3.7:
- resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
@@ -274,8 +279,8 @@ packages:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
- package-json-from-dist@1.0.0:
- resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==}
+ package-json-from-dist@1.0.1:
+ resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
@@ -288,8 +293,8 @@ packages:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
- picocolors@1.1.0:
- resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==}
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
@@ -299,32 +304,48 @@ packages:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
- pirates@4.0.6:
- resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
+ pirates@4.0.7:
+ resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
engines: {node: '>= 6'}
+ playwright-core@1.56.1:
+ resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ playwright@1.56.1:
+ resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
postcss-import@15.1.0:
resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
engines: {node: '>=14.0.0'}
peerDependencies:
postcss: ^8.0.0
- postcss-js@4.0.1:
- resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
+ postcss-js@4.1.0:
+ resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==}
engines: {node: ^12 || ^14 || >= 16}
peerDependencies:
postcss: ^8.4.21
- postcss-load-config@4.0.2:
- resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
- engines: {node: '>= 14'}
+ postcss-load-config@6.0.1:
+ resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
+ engines: {node: '>= 18'}
peerDependencies:
+ jiti: '>=1.21.0'
postcss: '>=8.0.9'
- ts-node: '>=9.0.0'
+ tsx: ^4.8.1
+ yaml: ^2.4.2
peerDependenciesMeta:
+ jiti:
+ optional: true
postcss:
optional: true
- ts-node:
+ tsx:
+ optional: true
+ yaml:
optional: true
postcss-nested@6.2.0:
@@ -340,8 +361,8 @@ packages:
postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
- postcss@8.4.44:
- resolution: {integrity: sha512-Aweb9unOEpQ3ezu4Q00DPvvM2ZTUitJdNKeP/+uQgr1IBIqu574IaZoURId7BKtWMREwzKa9OgzPzezWGPWFQw==}
+ postcss@8.5.6:
+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
queue-microtask@1.2.3:
@@ -354,12 +375,13 @@ packages:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
- resolve@1.22.8:
- resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
+ resolve@1.22.10:
+ resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
+ engines: {node: '>= 0.4'}
hasBin: true
- reusify@1.0.4:
- resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ reusify@1.1.0:
+ resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
run-parallel@1.2.0:
@@ -377,8 +399,8 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
- source-map-js@1.2.0:
- resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
string-width@4.2.3:
@@ -393,8 +415,8 @@ packages:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
- strip-ansi@7.1.0:
- resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+ strip-ansi@7.1.2:
+ resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
engines: {node: '>=12'}
sucrase@3.35.0:
@@ -406,8 +428,8 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
- tailwindcss@3.4.10:
- resolution: {integrity: sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==}
+ tailwindcss@3.4.18:
+ resolution: {integrity: sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==}
engines: {node: '>=14.0.0'}
hasBin: true
@@ -425,6 +447,9 @@ packages:
ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
+ undici-types@6.21.0:
+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@@ -454,27 +479,24 @@ snapshots:
dependencies:
string-width: 5.1.2
string-width-cjs: string-width@4.2.3
- strip-ansi: 7.1.0
+ strip-ansi: 7.1.2
strip-ansi-cjs: strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
- '@jridgewell/gen-mapping@0.3.5':
+ '@jridgewell/gen-mapping@0.3.13':
dependencies:
- '@jridgewell/set-array': 1.2.1
- '@jridgewell/sourcemap-codec': 1.5.0
- '@jridgewell/trace-mapping': 0.3.25
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
'@jridgewell/resolve-uri@3.1.2': {}
- '@jridgewell/set-array@1.2.1': {}
-
- '@jridgewell/sourcemap-codec@1.5.0': {}
+ '@jridgewell/sourcemap-codec@1.5.5': {}
- '@jridgewell/trace-mapping@0.3.25':
+ '@jridgewell/trace-mapping@0.3.31':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/sourcemap-codec': 1.5.5
'@nodelib/fs.scandir@2.1.5':
dependencies:
@@ -486,25 +508,29 @@ snapshots:
'@nodelib/fs.walk@1.2.8':
dependencies:
'@nodelib/fs.scandir': 2.1.5
- fastq: 1.17.1
+ fastq: 1.19.1
'@pkgjs/parseargs@0.11.0':
optional: true
- '@tailwindcss/forms@0.5.8(tailwindcss@3.4.10)':
+ '@tailwindcss/forms@0.5.10(tailwindcss@3.4.18(yaml@2.5.0))':
dependencies:
mini-svg-data-uri: 1.4.4
- tailwindcss: 3.4.10
+ tailwindcss: 3.4.18(yaml@2.5.0)
+
+ '@types/node@22.18.10':
+ dependencies:
+ undici-types: 6.21.0
ansi-regex@5.0.1: {}
- ansi-regex@6.0.1: {}
+ ansi-regex@6.2.2: {}
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
- ansi-styles@6.2.1: {}
+ ansi-styles@6.2.3: {}
any-promise@1.3.0: {}
@@ -519,7 +545,7 @@ snapshots:
binary-extensions@2.3.0: {}
- brace-expansion@2.0.1:
+ brace-expansion@2.0.2:
dependencies:
balanced-match: 1.0.2
@@ -549,7 +575,7 @@ snapshots:
commander@4.1.1: {}
- cross-spawn@7.0.3:
+ cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
@@ -567,7 +593,7 @@ snapshots:
emoji-regex@9.2.2: {}
- fast-glob@3.3.2:
+ fast-glob@3.3.3:
dependencies:
'@nodelib/fs.stat': 2.0.5
'@nodelib/fs.walk': 1.2.8
@@ -575,19 +601,22 @@ snapshots:
merge2: 1.4.1
micromatch: 4.0.8
- fastq@1.17.1:
+ fastq@1.19.1:
dependencies:
- reusify: 1.0.4
+ reusify: 1.1.0
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
- foreground-child@3.3.0:
+ foreground-child@3.3.1:
dependencies:
- cross-spawn: 7.0.3
+ cross-spawn: 7.0.6
signal-exit: 4.1.0
+ fsevents@2.3.2:
+ optional: true
+
fsevents@2.3.3:
optional: true
@@ -603,11 +632,11 @@ snapshots:
glob@10.4.5:
dependencies:
- foreground-child: 3.3.0
+ foreground-child: 3.3.1
jackspeak: 3.4.3
minimatch: 9.0.5
minipass: 7.1.2
- package-json-from-dist: 1.0.0
+ package-json-from-dist: 1.0.1
path-scurry: 1.11.1
hasown@2.0.2:
@@ -618,7 +647,7 @@ snapshots:
dependencies:
binary-extensions: 2.3.0
- is-core-module@2.15.1:
+ is-core-module@2.16.1:
dependencies:
hasown: 2.0.2
@@ -640,11 +669,9 @@ snapshots:
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
- jiti@1.21.6: {}
+ jiti@1.21.7: {}
- lilconfig@2.1.0: {}
-
- lilconfig@3.1.2: {}
+ lilconfig@3.1.3: {}
lines-and-columns@1.2.4: {}
@@ -661,7 +688,7 @@ snapshots:
minimatch@9.0.5:
dependencies:
- brace-expansion: 2.0.1
+ brace-expansion: 2.0.2
minipass@7.1.2: {}
@@ -671,7 +698,7 @@ snapshots:
object-assign: 4.1.1
thenify-all: 1.6.0
- nanoid@3.3.7: {}
+ nanoid@3.3.11: {}
normalize-path@3.0.0: {}
@@ -679,7 +706,7 @@ snapshots:
object-hash@3.0.0: {}
- package-json-from-dist@1.0.0: {}
+ package-json-from-dist@1.0.1: {}
path-key@3.1.1: {}
@@ -690,36 +717,45 @@ snapshots:
lru-cache: 10.4.3
minipass: 7.1.2
- picocolors@1.1.0: {}
+ picocolors@1.1.1: {}
picomatch@2.3.1: {}
pify@2.3.0: {}
- pirates@4.0.6: {}
+ pirates@4.0.7: {}
+
+ playwright-core@1.56.1: {}
- postcss-import@15.1.0(postcss@8.4.44):
+ playwright@1.56.1:
dependencies:
- postcss: 8.4.44
+ playwright-core: 1.56.1
+ optionalDependencies:
+ fsevents: 2.3.2
+
+ postcss-import@15.1.0(postcss@8.5.6):
+ dependencies:
+ postcss: 8.5.6
postcss-value-parser: 4.2.0
read-cache: 1.0.0
- resolve: 1.22.8
+ resolve: 1.22.10
- postcss-js@4.0.1(postcss@8.4.44):
+ postcss-js@4.1.0(postcss@8.5.6):
dependencies:
camelcase-css: 2.0.1
- postcss: 8.4.44
+ postcss: 8.5.6
- postcss-load-config@4.0.2(postcss@8.4.44):
+ postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.5.0):
dependencies:
- lilconfig: 3.1.2
- yaml: 2.5.0
+ lilconfig: 3.1.3
optionalDependencies:
- postcss: 8.4.44
+ jiti: 1.21.7
+ postcss: 8.5.6
+ yaml: 2.5.0
- postcss-nested@6.2.0(postcss@8.4.44):
+ postcss-nested@6.2.0(postcss@8.5.6):
dependencies:
- postcss: 8.4.44
+ postcss: 8.5.6
postcss-selector-parser: 6.1.2
postcss-selector-parser@6.1.2:
@@ -729,11 +765,11 @@ snapshots:
postcss-value-parser@4.2.0: {}
- postcss@8.4.44:
+ postcss@8.5.6:
dependencies:
- nanoid: 3.3.7
- picocolors: 1.1.0
- source-map-js: 1.2.0
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
queue-microtask@1.2.3: {}
@@ -745,13 +781,13 @@ snapshots:
dependencies:
picomatch: 2.3.1
- resolve@1.22.8:
+ resolve@1.22.10:
dependencies:
- is-core-module: 2.15.1
+ is-core-module: 2.16.1
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
- reusify@1.0.4: {}
+ reusify@1.1.0: {}
run-parallel@1.2.0:
dependencies:
@@ -765,7 +801,7 @@ snapshots:
signal-exit@4.1.0: {}
- source-map-js@1.2.0: {}
+ source-map-js@1.2.1: {}
string-width@4.2.3:
dependencies:
@@ -777,54 +813,55 @@ snapshots:
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
- strip-ansi: 7.1.0
+ strip-ansi: 7.1.2
strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
- strip-ansi@7.1.0:
+ strip-ansi@7.1.2:
dependencies:
- ansi-regex: 6.0.1
+ ansi-regex: 6.2.2
sucrase@3.35.0:
dependencies:
- '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/gen-mapping': 0.3.13
commander: 4.1.1
glob: 10.4.5
lines-and-columns: 1.2.4
mz: 2.7.0
- pirates: 4.0.6
+ pirates: 4.0.7
ts-interface-checker: 0.1.13
supports-preserve-symlinks-flag@1.0.0: {}
- tailwindcss@3.4.10:
+ tailwindcss@3.4.18(yaml@2.5.0):
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
chokidar: 3.6.0
didyoumean: 1.2.2
dlv: 1.1.3
- fast-glob: 3.3.2
+ fast-glob: 3.3.3
glob-parent: 6.0.2
is-glob: 4.0.3
- jiti: 1.21.6
- lilconfig: 2.1.0
+ jiti: 1.21.7
+ lilconfig: 3.1.3
micromatch: 4.0.8
normalize-path: 3.0.0
object-hash: 3.0.0
- picocolors: 1.1.0
- postcss: 8.4.44
- postcss-import: 15.1.0(postcss@8.4.44)
- postcss-js: 4.0.1(postcss@8.4.44)
- postcss-load-config: 4.0.2(postcss@8.4.44)
- postcss-nested: 6.2.0(postcss@8.4.44)
+ picocolors: 1.1.1
+ postcss: 8.5.6
+ postcss-import: 15.1.0(postcss@8.5.6)
+ postcss-js: 4.1.0(postcss@8.5.6)
+ postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.5.0)
+ postcss-nested: 6.2.0(postcss@8.5.6)
postcss-selector-parser: 6.1.2
- resolve: 1.22.8
+ resolve: 1.22.10
sucrase: 3.35.0
transitivePeerDependencies:
- - ts-node
+ - tsx
+ - yaml
thenify-all@1.6.0:
dependencies:
@@ -840,6 +877,8 @@ snapshots:
ts-interface-checker@0.1.13: {}
+ undici-types@6.21.0: {}
+
util-deprecate@1.0.2: {}
which@2.0.2:
@@ -854,8 +893,9 @@ snapshots:
wrap-ansi@8.1.0:
dependencies:
- ansi-styles: 6.2.1
+ ansi-styles: 6.2.3
string-width: 5.1.2
- strip-ansi: 7.1.0
+ strip-ansi: 7.1.2
- yaml@2.5.0: {}
+ yaml@2.5.0:
+ optional: true
diff --git a/simple-analytics.php b/simple-analytics.php
index 719e178..27a5f28 100644
--- a/simple-analytics.php
+++ b/simple-analytics.php
@@ -29,12 +29,13 @@
*/
require __DIR__ . '/src/Support/SvgIcon.php';
require __DIR__ . '/helpers.php';
-require __DIR__ . '/src/PluginLifecycle.php';
require __DIR__ . '/src/Plugin.php';
+require __DIR__ . '/src/WordPressHooks.php';
+require __DIR__ . '/src/WordPressSettings.php';
require __DIR__ . '/src/Setting.php';
require __DIR__ . '/src/SettingName.php';
-require __DIR__ . '/src/TrackingPolicy.php';
-require __DIR__ . '/src/ScriptManager.php';
+require __DIR__ . '/src/TrackingRules.php';
+require __DIR__ . '/src/ScriptRegistry.php';
require __DIR__ . '/src/Scripts/Contracts/Script.php';
require __DIR__ . '/src/Scripts/Contracts/HideScriptId.php';
require __DIR__ . '/src/Scripts/Contracts/HasAttributes.php';
@@ -52,7 +53,7 @@
require __DIR__ . '/src/Settings/Concerns/HasPlaceholder.php';
require __DIR__ . '/src/Settings/Concerns/ManagesBlocks.php';
require __DIR__ . '/src/Settings/Concerns/WordPressPageIntegration.php';
-require __DIR__ . '/src/Settings/Page.php';
+require __DIR__ . '/src/Settings/AdminPage.php';
require __DIR__ . '/src/Settings/Blocks/Fields/Field.php';
require __DIR__ . '/src/Settings/Blocks/Fields/Input.php';
require __DIR__ . '/src/Settings/Blocks/Fields/Checkboxes.php';
@@ -63,6 +64,106 @@
require __DIR__ . '/src/UI/TabListComponent.php';
require __DIR__ . '/src/UI/PageLayoutComponent.php';
-use SimpleAnalytics\Plugin;
+use SimpleAnalytics\SettingName;
+use SimpleAnalytics\Settings\Tab;
+use function SimpleAnalytics\get_icon;
-(new Plugin)->boot();
+$settings = new SimpleAnalytics\WordPressSettings();
+$hooks = new SimpleAnalytics\WordPressHooks();
+$rules = new SimpleAnalytics\TrackingRules($settings);
+$scripts = new SimpleAnalytics\ScriptRegistry(/*TODO TAKE $hooks WordPressHooks as arg/dependency*/);
+
+$adminPage = SimpleAnalytics\Settings\AdminPage::title('Simple Analytics')
+ ->slug('simpleanalytics')
+ ->tab('General', function (Tab $tab) {
+ $tab->input(SettingName::CUSTOM_DOMAIN, 'Custom Domain')
+ ->placeholder('Enter your custom domain or leave it empty.')
+ ->description('E.g. api.example.com. Leave empty to use the default domain (most users).')
+ ->docs('https://docs.simpleanalytics.com/bypass-ad-blockers');
+ })
+ ->tab('Ignore Rules', function (Tab $tab) {
+ $tab->icon(get_icon('eye-slash'));
+
+ $tab->input(SettingName::IGNORE_PAGES, 'Ignore Pages')
+ ->description('Comma separated list of pages to ignore. E.g. /contact, /about')
+ ->placeholder('Example: /page1, /page2, /category/*')
+ ->docs('https://docs.simpleanalytics.com/ignore-pages');
+
+ $tab->callout('IP and role exclusion only works when there is no page caching.');
+
+ $tab->multiCheckbox(SettingName::EXCLUDED_ROLES, 'Specific User Roles to Exclude')
+ ->description('When none selected, all authenticated users will be excluded from tracking.')
+ ->options(function () {
+ return wp_roles()->get_names();
+ });
+
+ $tab->ipList(SettingName::EXCLUDED_IP_ADDRESSES, 'Exclude IP Addresses')
+ ->placeholder("127.0.0.1\n192.168.0.1")
+ ->description('IP addresses to exclude from tracking.');
+ })
+ ->tab('Advanced', function (Tab $tab) {
+ $tab->icon(get_icon('cog'));
+
+ $tab->checkbox(SettingName::COLLECT_DNT, 'Collect Do Not Track')
+ ->description('If you want to collect visitors with Do Not Track enabled, turn this on.')
+ ->docs('https://docs.simpleanalytics.com/dnt');
+
+ $tab->checkbox(SettingName::HASH_MODE, 'Hash mode')
+ ->description('If your website uses hash (#) navigation, turn this on. On most WordPress websites this is not relevant.')
+ ->docs('https://docs.simpleanalytics.com/hash-mode');
+
+ $tab->checkbox(SettingName::MANUAL_COLLECT, 'Manually collect page views')
+ ->description('In case you don’t want to auto collect page views, but via `sa_pageview` function in JavaScript.')
+ ->docs('https://docs.simpleanalytics.com/trigger-custom-page-views#use-custom-collection-anyway');
+
+ $tab->checkbox(SettingName::NOSCRIPT, 'Support no JavaScript mode')
+ ->description('Collect analytics from visitors with disabled or no JavaScript.');
+
+ $tab->input(SettingName::ONLOAD_CALLBACK, 'Onload Callback')
+ ->description('JavaScript function to call when the script is loaded.')
+ ->placeholder('Example: sa_event("My event")')
+ ->docs('https://docs.simpleanalytics.com/trigger-custom-page-views#use-custom-collection-anyway');
+
+ $tab->input(SettingName::HOSTNAME, 'Overwrite domain name')
+ ->description('Override the domain that is sent to Simple Analytics. Useful for multi-domain setups.')
+ ->placeholder('Example: example.com')
+ ->docs('https://docs.simpleanalytics.com/overwrite-domain-name');
+
+ $tab->input(SettingName::SA_GLOBAL, 'Global variable name')
+ ->description('Change the global variable name of Simple Analytics. Default is `sa_event`.')
+ ->placeholder('Example: ba_event')
+ ->docs('https://docs.simpleanalytics.com/events#the-variable-sa_event-is-already-used');
+ })
+ ->tab('Events', function (Tab $tab) {
+ $tab->title('Automated events')
+ ->icon(get_icon('events'))
+ ->description("It will track outbound links, email addresses clicks,
+ and amount of downloads for common files (pdf, csv, docx, xIsx).
+ Events will appear on your events page on simpleanalytics.com");
+
+ $tab->checkbox(SettingName::AUTOMATED_EVENTS, 'Collect automated events');
+
+ $tab->input(SettingName::EVENT_COLLECT_DOWNLOADS, 'Auto collect downloads')
+ ->placeholder('Example: outbound,emails,downloads')
+ ->docs('https://docs.simpleanalytics.com/automated-events');
+
+ $tab->input(SettingName::EVENT_EXTENSIONS, 'Download file extensions')
+ ->description('Comma separated list of file extensions to track as downloads. E.g. pdf, zip')
+ ->placeholder('Example: pdf, zip')
+ ->docs('https://docs.simpleanalytics.com/automated-events');
+
+ $tab->checkbox(SettingName::EVENT_USE_TITLE, 'Use titles of page')
+ ->description('Use the title of the page as the event name. Default is the URL.')
+ ->docs('https://docs.simpleanalytics.com/automated-events');
+
+ $tab->checkbox(SettingName::EVENT_FULL_URLS, 'Use full URLs')
+ ->description('Use full URLs instead of the path. Default is the path.')
+ ->docs('https://docs.simpleanalytics.com/automated-events');
+
+ $tab->input(SettingName::EVENT_SA_GLOBAL, 'Override global')
+ ->description('Override the global variable name of Simple Analytics. Default is `sa_event`.')
+ ->placeholder('Example: ba_event')
+ ->docs('https://docs.simpleanalytics.com/events#the-variable-sa_event-is-already-used');
+ });
+
+(new SimpleAnalytics\Plugin($hooks, $settings, $rules, $scripts, $adminPage))->boot();
diff --git a/src/Plugin.php b/src/Plugin.php
index 6627663..c195c44 100644
--- a/src/Plugin.php
+++ b/src/Plugin.php
@@ -2,187 +2,84 @@
namespace SimpleAnalytics;
-use SimpleAnalytics\Settings\{Page, Tab};
use SimpleAnalytics\Actions\AddInactiveComment;
use SimpleAnalytics\Actions\AddNoScriptTag;
use SimpleAnalytics\Actions\AddPluginSettingsLink;
use SimpleAnalytics\Scripts\AnalyticsScript;
use SimpleAnalytics\Scripts\AutomatedEventsScript;
use SimpleAnalytics\Scripts\InactiveScript;
+use SimpleAnalytics\Settings\AdminPage;
final class Plugin
{
- use PluginLifecycle;
-
- protected function onBoot(): void
- {
- if (is_admin()) {
- $this->defineAdminPage();
- AddPluginSettingsLink::register();
- }
+ protected $hooks;
+ protected $settings;
+ protected $trackingRules;
+ protected $scripts;
+ protected $adminPage;
+
+ public function __construct(
+ WordPressHooks $hooks,
+ WordPressSettings $settings,
+ TrackingRules $trackingRules,
+ ScriptRegistry $scripts,
+ AdminPage $adminPage
+ ) {
+ $this->hooks = $hooks;
+ $this->settings = $settings;
+ $this->trackingRules = $trackingRules;
+ $this->scripts = $scripts;
+ $this->adminPage = $adminPage;
}
- public function onActivation(): void
+ public function boot(): void
{
- $this->addOptions();
- }
+ $this->hooks->addAction('init', \Closure::fromCallable([$this, 'onInit']));
+ $this->hooks->onActivation(\Closure::fromCallable([$this, 'onActivation']));
+ $this->hooks->onDeactivation(\Closure::fromCallable([$this, 'onUninstall']));
- public function onUninstall(): void
- {
- $this->deleteOptions();
+ if ($this->hooks->isAdmin()) {
+ $this->adminPage->register();
+ AddPluginSettingsLink::register();
+ }
}
public function onInit(): void
{
- $shouldCollect = (new TrackingPolicy)->shouldCollectAnalytics();
- $this->addScripts($shouldCollect);
- if (! $shouldCollect) {
+ $tracking = ! $this->trackingRules->hasExcludedIp() && ! $this->trackingRules->hasExcludedUserRole();
+
+ if ($tracking) {
+ $this->scripts->push(new AnalyticsScript);
+ } else {
+ $this->scripts->push(new InactiveScript);
AddInactiveComment::register();
}
- if ($shouldCollect && Setting::boolean(SettingName::NOSCRIPT)) {
+
+ if ($tracking && $this->settings->get(SettingName::NOSCRIPT)) {
AddNoScriptTag::register();
}
- }
- /**
- * Register plugin options and autoload them.
- *
- * @note Eliminates any unnecessary database lookups by preloading on each request.
- * @note Thanks to option autoloading, we don't need to use one serialized option, but several.
- * This allows the usage of native hooks and filters and reduces the chance of data corruption.
- */
- protected function addOptions(): void
- {
- // Add options with default values
- add_option(SettingName::ENABLED, '1', null, true);
-
- // Add all remaining options
- $optionNames = array_diff(SettingName::cases(), [SettingName::ENABLED]);
- foreach ($optionNames as $name) {
- add_option($name, null, null, true);
+ if ($this->settings->boolean(SettingName::AUTOMATED_EVENTS)) {
+ $this->scripts->push(new AutomatedEventsScript);
}
- // Legacy. Update the option introduced in a previous release to use autoloading.
- update_option(SettingName::CUSTOM_DOMAIN, get_option(SettingName::CUSTOM_DOMAIN), true);
- }
-
- protected function deleteOptions(): void
- {
- foreach (SettingName::cases() as $name) {
- delete_option($name);
- }
+ $this->scripts->register();
}
- protected function addScripts(bool $collect): void
+ public function onActivation(): void
{
- $scripts = new ScriptManager;
+ $this->settings->register(SettingName::ENABLED, true);
- if ($collect) {
- $scripts->add(new AnalyticsScript);
- } elseif (is_user_logged_in()) {
- $scripts->add(new InactiveScript);
+ foreach (array_diff(SettingName::cases(), [SettingName::ENABLED]) as $name) {
+ $this->settings->register($name);
}
- if (Setting::boolean(SettingName::AUTOMATED_EVENTS)) {
- $scripts->add(new AutomatedEventsScript);
- }
-
- $scripts->register();
+ // Legacy. Update the option introduced in a previous release to use autoloading.
+ $this->settings->update(SettingName::CUSTOM_DOMAIN, $this->settings->get(SettingName::CUSTOM_DOMAIN), true);
}
- protected function defineAdminPage(): void
+ public function onUninstall(): void
{
- Page::title('Simple Analytics')
- ->slug('simpleanalytics')
- ->tab('General', function (Tab $tab) {
- $tab->input(SettingName::CUSTOM_DOMAIN, 'Custom Domain')
- ->placeholder('Enter your custom domain or leave it empty.')
- ->description('E.g. api.example.com. Leave empty to use the default domain (most users).')
- ->docs('https://docs.simpleanalytics.com/bypass-ad-blockers');
- })
- ->tab('Ignore Rules', function (Tab $tab) {
- $tab->icon(get_icon('eye-slash'));
-
- $tab->input(SettingName::IGNORE_PAGES, 'Ignore Pages')
- ->description('Comma separated list of pages to ignore. E.g. /contact, /about')
- ->placeholder('Example: /page1, /page2, /category/*')
- ->docs('https://docs.simpleanalytics.com/ignore-pages');
-
- $tab->callout('IP and role exclusion only works when there is no page caching.');
-
- $tab->multiCheckbox(SettingName::EXCLUDED_ROLES, 'Exclude User Roles')
- ->options(function () {
- return wp_roles()->get_names();
- });
-
- $tab->ipList(SettingName::EXCLUDED_IP_ADDRESSES, 'Exclude IP Addresses')
- ->placeholder("127.0.0.1\n192.168.0.1")
- ->description('IP addresses to exclude from tracking.');
- })
- ->tab('Advanced', function (Tab $tab) {
- $tab->icon(get_icon('cog'));
-
- $tab->checkbox(SettingName::COLLECT_DNT, 'Collect Do Not Track')
- ->description('If you want to collect visitors with Do Not Track enabled, turn this on.')
- ->docs('https://docs.simpleanalytics.com/dnt');
-
- $tab->checkbox(SettingName::HASH_MODE, 'Hash mode')
- ->description('If your website uses hash (#) navigation, turn this on. On most WordPress websites this is not relevant.')
- ->docs('https://docs.simpleanalytics.com/hash-mode');
-
- $tab->checkbox(SettingName::MANUAL_COLLECT, 'Manually collect page views')
- ->description('In case you don’t want to auto collect page views, but via `sa_pageview` function in JavaScript.')
- ->docs('https://docs.simpleanalytics.com/trigger-custom-page-views#use-custom-collection-anyway');
-
- $tab->checkbox(SettingName::NOSCRIPT, 'Support no JavaScript mode')
- ->description('Collect analytics from visitors with disabled or no JavaScript.');
-
- $tab->input(SettingName::ONLOAD_CALLBACK, 'Onload Callback')
- ->description('JavaScript function to call when the script is loaded.')
- ->placeholder('Example: sa_event("My event")')
- ->docs('https://docs.simpleanalytics.com/trigger-custom-page-views#use-custom-collection-anyway');
-
- $tab->input(SettingName::HOSTNAME, 'Overwrite domain name')
- ->description('Override the domain that is sent to Simple Analytics. Useful for multi-domain setups.')
- ->placeholder('Example: example.com')
- ->docs('https://docs.simpleanalytics.com/overwrite-domain-name');
-
- $tab->input(SettingName::SA_GLOBAL, 'Global variable name')
- ->description('Change the global variable name of Simple Analytics. Default is `sa_event`.')
- ->placeholder('Example: ba_event')
- ->docs('https://docs.simpleanalytics.com/events#the-variable-sa_event-is-already-used');
- })
- ->tab('Events', function (Tab $tab) {
- $tab->title('Automated events')
- ->icon(get_icon('events'))
- ->description("It will track outbound links, email addresses clicks,
- and amount of downloads for common files (pdf, csv, docx, xIsx).
- Events will appear on your events page on simpleanalytics.com");
-
- $tab->checkbox(SettingName::AUTOMATED_EVENTS, 'Collect automated events');
-
- $tab->input(SettingName::EVENT_COLLECT_DOWNLOADS, 'Auto collect downloads')
- ->placeholder('Example: outbound,emails,downloads')
- ->docs('https://docs.simpleanalytics.com/automated-events');
-
- $tab->input(SettingName::EVENT_EXTENSIONS, 'Download file extensions')
- ->description('Comma separated list of file extensions to track as downloads. E.g. pdf, zip')
- ->placeholder('Example: pdf, zip')
- ->docs('https://docs.simpleanalytics.com/automated-events');
-
- $tab->checkbox(SettingName::EVENT_USE_TITLE, 'Use titles of page')
- ->description('Use the title of the page as the event name. Default is the URL.')
- ->docs('https://docs.simpleanalytics.com/automated-events');
-
- $tab->checkbox(SettingName::EVENT_FULL_URLS, 'Use full URLs')
- ->description('Use full URLs instead of the path. Default is the path.')
- ->docs('https://docs.simpleanalytics.com/automated-events');
-
- $tab->input(SettingName::EVENT_SA_GLOBAL, 'Override global')
- ->description('Override the global variable name of Simple Analytics. Default is `sa_event`.')
- ->placeholder('Example: ba_event')
- ->docs('https://docs.simpleanalytics.com/events#the-variable-sa_event-is-already-used');
- })
- ->register();
+ foreach (SettingName::cases() as $key) $this->settings->delete($key);
}
}
diff --git a/src/PluginLifecycle.php b/src/PluginLifecycle.php
deleted file mode 100644
index b115877..0000000
--- a/src/PluginLifecycle.php
+++ /dev/null
@@ -1,26 +0,0 @@
-onBoot();
- add_action('init', \Closure::fromCallable([$this, 'onInit']));
- register_activation_hook(ENTRYPOINT_FILE, \Closure::fromCallable([$this, 'onActivation']));
- register_deactivation_hook(ENTRYPOINT_FILE, \Closure::fromCallable([$this, 'onUninstall']));
- }
-
- /** @internal */
- abstract protected function onBoot(): void;
-
- /** @internal */
- abstract public function onInit(): void;
-
- /** @internal */
- abstract public function onActivation(): void;
-
- /** @internal */
- abstract public function onUninstall(): void;
-}
diff --git a/src/ScriptManager.php b/src/ScriptRegistry.php
similarity index 91%
rename from src/ScriptManager.php
rename to src/ScriptRegistry.php
index 5eb8945..e79099f 100644
--- a/src/ScriptManager.php
+++ b/src/ScriptRegistry.php
@@ -9,16 +9,16 @@
/**
* Register scripts with WordPress.
*/
-final class ScriptManager
+final class ScriptRegistry
{
+ /** @var Script[] */
private $scripts = [];
- public function __construct($scripts = [])
+
+ public function __construct()
{
- /** @var Script[] */
- $this->scripts = $scripts;
}
- public function add(Script $script): void
+ public function push(Script $script): void
{
$this->scripts[] = $script;
}
diff --git a/src/Settings/Page.php b/src/Settings/AdminPage.php
similarity index 98%
rename from src/Settings/Page.php
rename to src/Settings/AdminPage.php
index 88d5430..22c6058 100644
--- a/src/Settings/Page.php
+++ b/src/Settings/AdminPage.php
@@ -5,7 +5,7 @@
use SimpleAnalytics\Settings\Concerns\WordPressPageIntegration;
use SimpleAnalytics\Support\Str;
-class Page
+class AdminPage
{
use WordPressPageIntegration;
diff --git a/src/Settings/Concerns/WordPressPageIntegration.php b/src/Settings/Concerns/WordPressPageIntegration.php
index b50699f..391d7a1 100644
--- a/src/Settings/Concerns/WordPressPageIntegration.php
+++ b/src/Settings/Concerns/WordPressPageIntegration.php
@@ -8,6 +8,9 @@
trait WordPressPageIntegration
{
+ /** @return Tab[] */
+ abstract function getTabs(): array;
+
public function register(): void
{
add_action('admin_menu', [$this, 'wpAddMenu']);
diff --git a/src/TrackingPolicy.php b/src/TrackingPolicy.php
deleted file mode 100644
index 2f5a178..0000000
--- a/src/TrackingPolicy.php
+++ /dev/null
@@ -1,36 +0,0 @@
-isClientIpExcluded()) {
- return false;
- }
-
- if (! is_user_logged_in()) {
- return true;
- }
-
- return ! $this->containsExcludedRole();
- }
-
- protected function isClientIpExcluded(): bool
- {
- $ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
-
- if (empty($ip)) return false;
-
- return in_array($ip, Setting::array(SettingName::EXCLUDED_IP_ADDRESSES));
- }
-
- protected function containsExcludedRole(): bool
- {
- $currentRoles = wp_get_current_user()->roles;
- $excludedRoles = Setting::array(SettingName::EXCLUDED_ROLES);
-
- return array_intersect($excludedRoles, $currentRoles) !== [];
- }
-}
diff --git a/src/TrackingRules.php b/src/TrackingRules.php
new file mode 100644
index 0000000..02d0505
--- /dev/null
+++ b/src/TrackingRules.php
@@ -0,0 +1,41 @@
+settings = $settings;
+ }
+
+ public function hasExcludedIp(): bool
+ {
+ $ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
+
+ if (empty($ip)) return false;
+
+ $list = $this->settings->array(SettingName::EXCLUDED_IP_ADDRESSES);
+
+ return in_array($ip, $list);
+ }
+
+ public function hasExcludedUserRole(): bool
+ {
+ if (! is_user_logged_in()) {
+ return false;
+ }
+
+ $needle = $this->settings->array(SettingName::EXCLUDED_ROLES);
+
+ if ($needle === []) {
+ return true;
+ }
+
+ $current = wp_get_current_user()->roles;
+
+ return array_intersect($needle, $current) !== [];
+ }
+}
diff --git a/src/UI/PageLayoutComponent.php b/src/UI/PageLayoutComponent.php
index 512940a..0a8d81c 100644
--- a/src/UI/PageLayoutComponent.php
+++ b/src/UI/PageLayoutComponent.php
@@ -2,7 +2,7 @@
namespace SimpleAnalytics\UI;
-use SimpleAnalytics\Settings\{Page, Tab};
+use SimpleAnalytics\Settings\{AdminPage, Tab};
use function SimpleAnalytics\get_icon;
use const SimpleAnalytics\PLUGIN_URL;
@@ -10,10 +10,10 @@ class PageLayoutComponent
{
/**
* @readonly
- * @var \SimpleAnalytics\Settings\Page
+ * @var \SimpleAnalytics\Settings\AdminPage
*/
private $page;
- public function __construct(Page $page)
+ public function __construct(AdminPage $page)
{
$this->page = $page;
}
diff --git a/src/WordPressHooks.php b/src/WordPressHooks.php
new file mode 100644
index 0000000..c72529d
--- /dev/null
+++ b/src/WordPressHooks.php
@@ -0,0 +1,26 @@
+get($key, []);
+
+ return is_array($value) ? $value : [$value];
+ }
+}
diff --git a/tests/Browser/BrowserTestCase.php b/tests/Browser/BrowserTestCase.php
new file mode 100644
index 0000000..34c0ba5
--- /dev/null
+++ b/tests/Browser/BrowserTestCase.php
@@ -0,0 +1,48 @@
+pantherBrowser(['external_base_uri' => 'http://localhost:8100']);
+ }
+
+ protected function asUser($login, $password)
+ {
+ return $this->myBrowser()
+ ->visit('http://localhost:8100/wp-admin')
+ ->fillField('user_login', $login)
+ ->fillField('user_pass', $password)
+ ->click('wp-submit')
+ ->assertOn('http://localhost:8100/wp-admin/');
+ }
+
+ protected function asAdmin()
+ {
+ return $this->asUser('admin', 'admin');
+ }
+
+ protected function asAuthor()
+ {
+ return $this->asUser('author', 'author');
+ }
+
+ protected function asEditor()
+ {
+ return $this->asUser('editor', 'editor');
+ }
+}
diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php
new file mode 100644
index 0000000..d898120
--- /dev/null
+++ b/tests/Browser/PluginSettingsTest.php
@@ -0,0 +1,34 @@
+asAdmin()->visit('/wp-admin/plugins.php')
+ ->click('#activate-simpleanalytics')
+ ->assertSeeElement('#deactivate-simpleanalytics')
+ ->visit('/')
+ ->assertContains('')
+ ->assertContains('');
+ }
+
+ public function test_adds_script_with_ignored_pages(): void
+ {
+ $this->asAdmin()
+ ->visit('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules')
+ ->fillField('simpleanalytics_ignore_pages', '/vouchers')
+ ->click('Save Changes')
+ ->visit('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules')
+ ->assertFieldEquals('simpleanalytics_ignore_pages', '/vouchers');
+
+ $this->myBrowser()
+ ->visit('/')
+ ->assertContains('data-ignore-pages="/vouchers"');
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 0000000..690e86f
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,9 @@
+