diff --git a/.gitignore b/.gitignore
index e9b28ae1901f15..1f5680e2c6c2da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ coverage
yarn.lock
/artifacts
/perf-envs
+/composer.lock
.cache
*.tsbuildinfo
diff --git a/composer.json b/composer.json
index 4d0db1947690e3..b91bb973ade417 100644
--- a/composer.json
+++ b/composer.json
@@ -31,7 +31,6 @@
"phpcompatibility/php-compatibility": "^9.3",
"wp-coding-standards/wpcs": "^2.2",
"sirbrillig/phpcs-variable-analysis": "^2.8",
- "phpunit/phpunit": "^6.5",
"spatie/phpunit-watcher": "^1.23",
"yoast/phpunit-polyfills": "^1.0"
},
diff --git a/composer.lock b/composer.lock
deleted file mode 100644
index f358bb3462cab8..00000000000000
--- a/composer.lock
+++ /dev/null
@@ -1,3839 +0,0 @@
-{
- "_readme": [
- "This file locks the dependencies of your project to a known state",
- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
- "This file is @generated automatically"
- ],
- "content-hash": "35cc4f57b35ccba38e5ac0c76c85309e",
- "packages": [
- {
- "name": "composer/installers",
- "version": "v1.12.0",
- "source": {
- "type": "git",
- "url": "https://github.com/composer/installers.git",
- "reference": "d20a64ed3c94748397ff5973488761b22f6d3f19"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/composer/installers/zipball/d20a64ed3c94748397ff5973488761b22f6d3f19",
- "reference": "d20a64ed3c94748397ff5973488761b22f6d3f19",
- "shasum": ""
- },
- "require": {
- "composer-plugin-api": "^1.0 || ^2.0"
- },
- "replace": {
- "roundcube/plugin-installer": "*",
- "shama/baton": "*"
- },
- "require-dev": {
- "composer/composer": "1.6.* || ^2.0",
- "composer/semver": "^1 || ^3",
- "phpstan/phpstan": "^0.12.55",
- "phpstan/phpstan-phpunit": "^0.12.16",
- "symfony/phpunit-bridge": "^4.2 || ^5",
- "symfony/process": "^2.3"
- },
- "type": "composer-plugin",
- "extra": {
- "class": "Composer\\Installers\\Plugin",
- "branch-alias": {
- "dev-main": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Composer\\Installers\\": "src/Composer/Installers"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Kyle Robinson Young",
- "email": "kyle@dontkry.com",
- "homepage": "https://github.com/shama"
- }
- ],
- "description": "A multi-framework Composer library installer",
- "homepage": "https://composer.github.io/installers/",
- "keywords": [
- "Craft",
- "Dolibarr",
- "Eliasis",
- "Hurad",
- "ImageCMS",
- "Kanboard",
- "Lan Management System",
- "MODX Evo",
- "MantisBT",
- "Mautic",
- "Maya",
- "OXID",
- "Plentymarkets",
- "Porto",
- "RadPHP",
- "SMF",
- "Starbug",
- "Thelia",
- "Whmcs",
- "WolfCMS",
- "agl",
- "aimeos",
- "annotatecms",
- "attogram",
- "bitrix",
- "cakephp",
- "chef",
- "cockpit",
- "codeigniter",
- "concrete5",
- "croogo",
- "dokuwiki",
- "drupal",
- "eZ Platform",
- "elgg",
- "expressionengine",
- "fuelphp",
- "grav",
- "installer",
- "itop",
- "joomla",
- "known",
- "kohana",
- "laravel",
- "lavalite",
- "lithium",
- "magento",
- "majima",
- "mako",
- "mediawiki",
- "miaoxing",
- "modulework",
- "modx",
- "moodle",
- "osclass",
- "pantheon",
- "phpbb",
- "piwik",
- "ppi",
- "processwire",
- "puppet",
- "pxcms",
- "reindex",
- "roundcube",
- "shopware",
- "silverstripe",
- "sydes",
- "sylius",
- "symfony",
- "tastyigniter",
- "typo3",
- "wordpress",
- "yawik",
- "zend",
- "zikula"
- ],
- "support": {
- "issues": "https://github.com/composer/installers/issues",
- "source": "https://github.com/composer/installers/tree/v1.12.0"
- },
- "funding": [
- {
- "url": "https://packagist.com",
- "type": "custom"
- },
- {
- "url": "https://github.com/composer",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
- }
- ],
- "time": "2021-09-13T08:19:44+00:00"
- }
- ],
- "packages-dev": [
- {
- "name": "clue/stdio-react",
- "version": "v2.6.0",
- "source": {
- "type": "git",
- "url": "https://github.com/clue/reactphp-stdio.git",
- "reference": "dfa6c378aabdff718202d4e2453f752c38ea3399"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/clue/reactphp-stdio/zipball/dfa6c378aabdff718202d4e2453f752c38ea3399",
- "reference": "dfa6c378aabdff718202d4e2453f752c38ea3399",
- "shasum": ""
- },
- "require": {
- "clue/term-react": "^1.0 || ^0.1.1",
- "clue/utf8-react": "^1.0 || ^0.1",
- "php": ">=5.3",
- "react/event-loop": "^1.2",
- "react/stream": "^1.2"
- },
- "require-dev": {
- "clue/arguments": "^2.0",
- "clue/commander": "^1.2",
- "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
- },
- "suggest": {
- "ext-mbstring": "Using ext-mbstring should provide slightly better performance for handling I/O"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Clue\\React\\Stdio\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Christian Lück",
- "email": "christian@clue.engineering"
- }
- ],
- "description": "Async, event-driven console input & output (STDIN, STDOUT) for truly interactive CLI applications, built on top of ReactPHP",
- "homepage": "https://github.com/clue/reactphp-stdio",
- "keywords": [
- "async",
- "autocomplete",
- "autocompletion",
- "cli",
- "history",
- "interactive",
- "reactphp",
- "readline",
- "stdin",
- "stdio",
- "stdout"
- ],
- "support": {
- "issues": "https://github.com/clue/reactphp-stdio/issues",
- "source": "https://github.com/clue/reactphp-stdio/tree/v2.6.0"
- },
- "funding": [
- {
- "url": "https://clue.engineering/support",
- "type": "custom"
- },
- {
- "url": "https://github.com/clue",
- "type": "github"
- }
- ],
- "time": "2022-03-18T15:09:30+00:00"
- },
- {
- "name": "clue/term-react",
- "version": "v1.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/clue/reactphp-term.git",
- "reference": "eb6eb063eda04a714ef89f066586a2c49588f7ca"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/clue/reactphp-term/zipball/eb6eb063eda04a714ef89f066586a2c49588f7ca",
- "reference": "eb6eb063eda04a714ef89f066586a2c49588f7ca",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3",
- "react/stream": "^1.0 || ^0.7"
- },
- "require-dev": {
- "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8",
- "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Clue\\React\\Term\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Christian Lück",
- "email": "christian@clue.engineering"
- }
- ],
- "description": "Streaming terminal emulator, built on top of ReactPHP.",
- "homepage": "https://github.com/clue/reactphp-term",
- "keywords": [
- "C0",
- "CSI",
- "ansi",
- "apc",
- "ascii",
- "c1",
- "control codes",
- "dps",
- "osc",
- "pm",
- "reactphp",
- "streaming",
- "terminal",
- "vt100",
- "xterm"
- ],
- "support": {
- "issues": "https://github.com/clue/reactphp-term/issues",
- "source": "https://github.com/clue/reactphp-term/tree/v1.3.0"
- },
- "funding": [
- {
- "url": "https://clue.engineering/support",
- "type": "custom"
- },
- {
- "url": "https://github.com/clue",
- "type": "github"
- }
- ],
- "time": "2020-11-06T11:50:12+00:00"
- },
- {
- "name": "clue/utf8-react",
- "version": "v1.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/clue/reactphp-utf8.git",
- "reference": "8bc3f8c874cdf642c8f10f9ae93aadb8cd63da96"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/clue/reactphp-utf8/zipball/8bc3f8c874cdf642c8f10f9ae93aadb8cd63da96",
- "reference": "8bc3f8c874cdf642c8f10f9ae93aadb8cd63da96",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3",
- "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4 || ^0.3"
- },
- "require-dev": {
- "phpunit/phpunit": "^9.3 ||^5.7 || ^4.8",
- "react/stream": "^1.0 || ^0.7"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Clue\\React\\Utf8\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Christian Lück",
- "email": "christian@clue.engineering"
- }
- ],
- "description": "Streaming UTF-8 parser, built on top of ReactPHP.",
- "homepage": "https://github.com/clue/reactphp-utf8",
- "keywords": [
- "reactphp",
- "streaming",
- "unicode",
- "utf-8",
- "utf8"
- ],
- "support": {
- "issues": "https://github.com/clue/reactphp-utf8/issues",
- "source": "https://github.com/clue/reactphp-utf8/tree/v1.2.0"
- },
- "funding": [
- {
- "url": "https://clue.engineering/support",
- "type": "custom"
- },
- {
- "url": "https://github.com/clue",
- "type": "github"
- }
- ],
- "time": "2020-11-06T11:48:09+00:00"
- },
- {
- "name": "dealerdirect/phpcodesniffer-composer-installer",
- "version": "v0.7.2",
- "source": {
- "type": "git",
- "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
- "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db",
- "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db",
- "shasum": ""
- },
- "require": {
- "composer-plugin-api": "^1.0 || ^2.0",
- "php": ">=5.3",
- "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0"
- },
- "require-dev": {
- "composer/composer": "*",
- "php-parallel-lint/php-parallel-lint": "^1.3.1",
- "phpcompatibility/php-compatibility": "^9.0"
- },
- "type": "composer-plugin",
- "extra": {
- "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
- },
- "autoload": {
- "psr-4": {
- "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Franck Nijhof",
- "email": "franck.nijhof@dealerdirect.com",
- "homepage": "http://www.frenck.nl",
- "role": "Developer / IT Manager"
- },
- {
- "name": "Contributors",
- "homepage": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors"
- }
- ],
- "description": "PHP_CodeSniffer Standards Composer Installer Plugin",
- "homepage": "http://www.dealerdirect.com",
- "keywords": [
- "PHPCodeSniffer",
- "PHP_CodeSniffer",
- "code quality",
- "codesniffer",
- "composer",
- "installer",
- "phpcbf",
- "phpcs",
- "plugin",
- "qa",
- "quality",
- "standard",
- "standards",
- "style guide",
- "stylecheck",
- "tests"
- ],
- "support": {
- "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues",
- "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer"
- },
- "time": "2022-02-04T12:51:07+00:00"
- },
- {
- "name": "doctrine/instantiator",
- "version": "1.4.1",
- "source": {
- "type": "git",
- "url": "https://github.com/doctrine/instantiator.git",
- "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
- "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
- "shasum": ""
- },
- "require": {
- "php": "^7.1 || ^8.0"
- },
- "require-dev": {
- "doctrine/coding-standard": "^9",
- "ext-pdo": "*",
- "ext-phar": "*",
- "phpbench/phpbench": "^0.16 || ^1",
- "phpstan/phpstan": "^1.4",
- "phpstan/phpstan-phpunit": "^1",
- "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
- "vimeo/psalm": "^4.22"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Marco Pivetta",
- "email": "ocramius@gmail.com",
- "homepage": "https://ocramius.github.io/"
- }
- ],
- "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
- "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
- "keywords": [
- "constructor",
- "instantiate"
- ],
- "support": {
- "issues": "https://github.com/doctrine/instantiator/issues",
- "source": "https://github.com/doctrine/instantiator/tree/1.4.1"
- },
- "funding": [
- {
- "url": "https://www.doctrine-project.org/sponsorship.html",
- "type": "custom"
- },
- {
- "url": "https://www.patreon.com/phpdoctrine",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
- "type": "tidelift"
- }
- ],
- "time": "2022-03-03T08:28:38+00:00"
- },
- {
- "name": "evenement/evenement",
- "version": "v3.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/igorw/evenement.git",
- "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/igorw/evenement/zipball/531bfb9d15f8aa57454f5f0285b18bec903b8fb7",
- "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7",
- "shasum": ""
- },
- "require": {
- "php": ">=7.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.0"
- },
- "type": "library",
- "autoload": {
- "psr-0": {
- "Evenement": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Igor Wiedler",
- "email": "igor@wiedler.ch"
- }
- ],
- "description": "Événement is a very simple event dispatching library for PHP",
- "keywords": [
- "event-dispatcher",
- "event-emitter"
- ],
- "support": {
- "issues": "https://github.com/igorw/evenement/issues",
- "source": "https://github.com/igorw/evenement/tree/master"
- },
- "time": "2017-07-23T21:35:13+00:00"
- },
- {
- "name": "jolicode/jolinotif",
- "version": "v2.4.0",
- "source": {
- "type": "git",
- "url": "https://github.com/jolicode/JoliNotif.git",
- "reference": "a15bfc0d5aef432f150385924ede4e099643edb7"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/jolicode/JoliNotif/zipball/a15bfc0d5aef432f150385924ede4e099643edb7",
- "reference": "a15bfc0d5aef432f150385924ede4e099643edb7",
- "shasum": ""
- },
- "require": {
- "php": ">=7.4",
- "symfony/process": "^4.0|^5.0|^6.0"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.0",
- "symfony/finder": "^5.0",
- "symfony/phpunit-bridge": "^5.0"
- },
- "bin": [
- "jolinotif"
- ],
- "type": "library",
- "autoload": {
- "psr-4": {
- "Joli\\JoliNotif\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Loïck Piera",
- "email": "pyrech@gmail.com"
- }
- ],
- "description": "Send desktop notifications on Windows, Linux, MacOS.",
- "keywords": [
- "MAC",
- "growl",
- "linux",
- "notification",
- "windows"
- ],
- "support": {
- "issues": "https://github.com/jolicode/JoliNotif/issues",
- "source": "https://github.com/jolicode/JoliNotif/tree/v2.4.0"
- },
- "funding": [
- {
- "url": "https://tidelift.com/funding/github/packagist/jolicode/jolinotif",
- "type": "tidelift"
- }
- ],
- "time": "2021-12-01T16:20:42+00:00"
- },
- {
- "name": "myclabs/deep-copy",
- "version": "1.11.0",
- "source": {
- "type": "git",
- "url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
- "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
- "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",
- "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.11.0"
- },
- "funding": [
- {
- "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
- "type": "tidelift"
- }
- ],
- "time": "2022-03-03T13:19:32+00:00"
- },
- {
- "name": "phar-io/manifest",
- "version": "1.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/phar-io/manifest.git",
- "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0",
- "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "ext-phar": "*",
- "phar-io/version": "^1.0.1",
- "php": "^5.6 || ^7.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.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/master"
- },
- "time": "2017-03-05T18:14:27+00:00"
- },
- {
- "name": "phar-io/version",
- "version": "1.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/phar-io/version.git",
- "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df",
- "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df",
- "shasum": ""
- },
- "require": {
- "php": "^5.6 || ^7.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/master"
- },
- "time": "2017-03-05T17:38:23+00:00"
- },
- {
- "name": "phpcompatibility/php-compatibility",
- "version": "9.3.5",
- "source": {
- "type": "git",
- "url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
- "reference": "9fb324479acf6f39452e0655d2429cc0d3914243"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243",
- "reference": "9fb324479acf6f39452e0655d2429cc0d3914243",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3",
- "squizlabs/php_codesniffer": "^2.3 || ^3.0.2"
- },
- "conflict": {
- "squizlabs/php_codesniffer": "2.6.2"
- },
- "require-dev": {
- "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0"
- },
- "suggest": {
- "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.",
- "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
- },
- "type": "phpcodesniffer-standard",
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "LGPL-3.0-or-later"
- ],
- "authors": [
- {
- "name": "Wim Godden",
- "homepage": "https://github.com/wimg",
- "role": "lead"
- },
- {
- "name": "Juliette Reinders Folmer",
- "homepage": "https://github.com/jrfnl",
- "role": "lead"
- },
- {
- "name": "Contributors",
- "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors"
- }
- ],
- "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.",
- "homepage": "http://techblog.wimgodden.be/tag/codesniffer/",
- "keywords": [
- "compatibility",
- "phpcs",
- "standards"
- ],
- "support": {
- "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues",
- "source": "https://github.com/PHPCompatibility/PHPCompatibility"
- },
- "time": "2019-12-27T09:44:58+00:00"
- },
- {
- "name": "phpdocumentor/reflection-common",
- "version": "2.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
- "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
- "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
- "shasum": ""
- },
- "require": {
- "php": "^7.2 || ^8.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-2.x": "2.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Jaap van Otterdijk",
- "email": "opensource@ijaap.nl"
- }
- ],
- "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
- "homepage": "http://www.phpdoc.org",
- "keywords": [
- "FQSEN",
- "phpDocumentor",
- "phpdoc",
- "reflection",
- "static analysis"
- ],
- "support": {
- "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
- "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
- },
- "time": "2020-06-27T09:03:43+00:00"
- },
- {
- "name": "phpdocumentor/reflection-docblock",
- "version": "5.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "622548b623e81ca6d78b721c5e029f4ce664f170"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170",
- "reference": "622548b623e81ca6d78b721c5e029f4ce664f170",
- "shasum": ""
- },
- "require": {
- "ext-filter": "*",
- "php": "^7.2 || ^8.0",
- "phpdocumentor/reflection-common": "^2.2",
- "phpdocumentor/type-resolver": "^1.3",
- "webmozart/assert": "^1.9.1"
- },
- "require-dev": {
- "mockery/mockery": "~1.3.2",
- "psalm/phar": "^4.8"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Mike van Riel",
- "email": "me@mikevanriel.com"
- },
- {
- "name": "Jaap van Otterdijk",
- "email": "account@ijaap.nl"
- }
- ],
- "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
- "support": {
- "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
- "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0"
- },
- "time": "2021-10-19T17:43:47+00:00"
- },
- {
- "name": "phpdocumentor/type-resolver",
- "version": "1.6.1",
- "source": {
- "type": "git",
- "url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "77a32518733312af16a44300404e945338981de3"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3",
- "reference": "77a32518733312af16a44300404e945338981de3",
- "shasum": ""
- },
- "require": {
- "php": "^7.2 || ^8.0",
- "phpdocumentor/reflection-common": "^2.0"
- },
- "require-dev": {
- "ext-tokenizer": "*",
- "psalm/phar": "^4.8"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-1.x": "1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "phpDocumentor\\Reflection\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Mike van Riel",
- "email": "me@mikevanriel.com"
- }
- ],
- "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
- "support": {
- "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
- "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1"
- },
- "time": "2022-03-15T21:29:03+00:00"
- },
- {
- "name": "phpspec/prophecy",
- "version": "v1.10.3",
- "source": {
- "type": "git",
- "url": "https://github.com/phpspec/prophecy.git",
- "reference": "451c3cd1418cf640de218914901e51b064abb093"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093",
- "reference": "451c3cd1418cf640de218914901e51b064abb093",
- "shasum": ""
- },
- "require": {
- "doctrine/instantiator": "^1.0.2",
- "php": "^5.3|^7.0",
- "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
- "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0",
- "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0"
- },
- "require-dev": {
- "phpspec/phpspec": "^2.5 || ^3.2",
- "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.10.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Prophecy\\": "src/Prophecy"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Konstantin Kudryashov",
- "email": "ever.zet@gmail.com",
- "homepage": "http://everzet.com"
- },
- {
- "name": "Marcello Duarte",
- "email": "marcello.duarte@gmail.com"
- }
- ],
- "description": "Highly opinionated mocking framework for PHP 5.3+",
- "homepage": "https://github.com/phpspec/prophecy",
- "keywords": [
- "Double",
- "Dummy",
- "fake",
- "mock",
- "spy",
- "stub"
- ],
- "support": {
- "issues": "https://github.com/phpspec/prophecy/issues",
- "source": "https://github.com/phpspec/prophecy/tree/v1.10.3"
- },
- "time": "2020-03-05T15:02:03+00:00"
- },
- {
- "name": "phpunit/php-code-coverage",
- "version": "5.3.2",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "c89677919c5dd6d3b3852f230a663118762218ac"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac",
- "reference": "c89677919c5dd6d3b3852f230a663118762218ac",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "ext-xmlwriter": "*",
- "php": "^7.0",
- "phpunit/php-file-iterator": "^1.4.2",
- "phpunit/php-text-template": "^1.2.1",
- "phpunit/php-token-stream": "^2.0.1",
- "sebastian/code-unit-reverse-lookup": "^1.0.1",
- "sebastian/environment": "^3.0",
- "sebastian/version": "^2.0.1",
- "theseer/tokenizer": "^1.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.0"
- },
- "suggest": {
- "ext-xdebug": "^2.5.5"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.3.x-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 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",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/5.3"
- },
- "time": "2018-04-06T15:36:58+00:00"
- },
- {
- "name": "phpunit/php-file-iterator",
- "version": "1.4.5",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
- "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.4.x-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.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": {
- "irc": "irc://irc.freenode.net/phpunit",
- "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
- "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5"
- },
- "time": "2017-11-27T13:52:08+00:00"
- },
- {
- "name": "phpunit/php-text-template",
- "version": "1.2.1",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-text-template.git",
- "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
- "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "type": "library",
- "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",
- "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
- },
- "time": "2015-06-21T13:50:34+00:00"
- },
- {
- "name": "phpunit/php-timer",
- "version": "1.0.9",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
- "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
- "shasum": ""
- },
- "require": {
- "php": "^5.3.3 || ^7.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sb@sebastian-bergmann.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",
- "source": "https://github.com/sebastianbergmann/php-timer/tree/master"
- },
- "time": "2017-02-26T11:10:40+00:00"
- },
- {
- "name": "phpunit/php-token-stream",
- "version": "2.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "791198a2c6254db10131eecfe8c06670700904db"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
- "reference": "791198a2c6254db10131eecfe8c06670700904db",
- "shasum": ""
- },
- "require": {
- "ext-tokenizer": "*",
- "php": "^7.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.2.4"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Wrapper around PHP's tokenizer extension.",
- "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
- "keywords": [
- "tokenizer"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
- "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master"
- },
- "abandoned": true,
- "time": "2017-11-27T05:48:46+00:00"
- },
- {
- "name": "phpunit/phpunit",
- "version": "6.5.14",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bac23fe7ff13dbdb461481f706f0e9fe746334b7",
- "reference": "bac23fe7ff13dbdb461481f706f0e9fe746334b7",
- "shasum": ""
- },
- "require": {
- "ext-dom": "*",
- "ext-json": "*",
- "ext-libxml": "*",
- "ext-mbstring": "*",
- "ext-xml": "*",
- "myclabs/deep-copy": "^1.6.1",
- "phar-io/manifest": "^1.0.1",
- "phar-io/version": "^1.0",
- "php": "^7.0",
- "phpspec/prophecy": "^1.7",
- "phpunit/php-code-coverage": "^5.3",
- "phpunit/php-file-iterator": "^1.4.3",
- "phpunit/php-text-template": "^1.2.1",
- "phpunit/php-timer": "^1.0.9",
- "phpunit/phpunit-mock-objects": "^5.0.9",
- "sebastian/comparator": "^2.1",
- "sebastian/diff": "^2.0",
- "sebastian/environment": "^3.1",
- "sebastian/exporter": "^3.1",
- "sebastian/global-state": "^2.0",
- "sebastian/object-enumerator": "^3.0.3",
- "sebastian/resource-operations": "^1.0",
- "sebastian/version": "^2.0.1"
- },
- "conflict": {
- "phpdocumentor/reflection-docblock": "3.0.2",
- "phpunit/dbunit": "<3.0"
- },
- "require-dev": {
- "ext-pdo": "*"
- },
- "suggest": {
- "ext-xdebug": "*",
- "phpunit/php-invoker": "^1.1"
- },
- "bin": [
- "phpunit"
- ],
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "6.5.x-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": "The PHP Unit Testing framework.",
- "homepage": "https://phpunit.de/",
- "keywords": [
- "phpunit",
- "testing",
- "xunit"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/phpunit/issues",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/6.5.14"
- },
- "time": "2019-02-01T05:22:47+00:00"
- },
- {
- "name": "phpunit/phpunit-mock-objects",
- "version": "5.0.10",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
- "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f",
- "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f",
- "shasum": ""
- },
- "require": {
- "doctrine/instantiator": "^1.0.5",
- "php": "^7.0",
- "phpunit/php-text-template": "^1.2.1",
- "sebastian/exporter": "^3.1"
- },
- "conflict": {
- "phpunit/phpunit": "<6.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.5.11"
- },
- "suggest": {
- "ext-soap": "*"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.0.x-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": "Mock Object library for PHPUnit",
- "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
- "keywords": [
- "mock",
- "xunit"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues",
- "source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/5.0.10"
- },
- "abandoned": true,
- "time": "2018-08-09T05:50:03+00:00"
- },
- {
- "name": "psr/container",
- "version": "1.1.2",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/container.git",
- "reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
- "reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
- "shasum": ""
- },
- "require": {
- "php": ">=7.4.0"
- },
- "type": "library",
- "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/1.1.2"
- },
- "time": "2021-11-05T16:50:12+00:00"
- },
- {
- "name": "react/event-loop",
- "version": "v1.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/reactphp/event-loop.git",
- "reference": "187fb56f46d424afb6ec4ad089269c72eec2e137"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/reactphp/event-loop/zipball/187fb56f46d424afb6ec4ad089269c72eec2e137",
- "reference": "187fb56f46d424afb6ec4ad089269c72eec2e137",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
- },
- "suggest": {
- "ext-event": "~1.0 for ExtEventLoop",
- "ext-pcntl": "For signal handling support when using the StreamSelectLoop",
- "ext-uv": "* for ExtUvLoop"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "React\\EventLoop\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Christian Lück",
- "email": "christian@clue.engineering",
- "homepage": "https://clue.engineering/"
- },
- {
- "name": "Cees-Jan Kiewiet",
- "email": "reactphp@ceesjankiewiet.nl",
- "homepage": "https://wyrihaximus.net/"
- },
- {
- "name": "Jan Sorgalla",
- "email": "jsorgalla@gmail.com",
- "homepage": "https://sorgalla.com/"
- },
- {
- "name": "Chris Boden",
- "email": "cboden@gmail.com",
- "homepage": "https://cboden.dev/"
- }
- ],
- "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
- "keywords": [
- "asynchronous",
- "event-loop"
- ],
- "support": {
- "issues": "https://github.com/reactphp/event-loop/issues",
- "source": "https://github.com/reactphp/event-loop/tree/v1.3.0"
- },
- "funding": [
- {
- "url": "https://github.com/WyriHaximus",
- "type": "github"
- },
- {
- "url": "https://github.com/clue",
- "type": "github"
- }
- ],
- "time": "2022-03-17T11:10:22+00:00"
- },
- {
- "name": "react/stream",
- "version": "v1.2.0",
- "source": {
- "type": "git",
- "url": "https://github.com/reactphp/stream.git",
- "reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/reactphp/stream/zipball/7a423506ee1903e89f1e08ec5f0ed430ff784ae9",
- "reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9",
- "shasum": ""
- },
- "require": {
- "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
- "php": ">=5.3.8",
- "react/event-loop": "^1.2"
- },
- "require-dev": {
- "clue/stream-filter": "~1.2",
- "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "React\\Stream\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Christian Lück",
- "email": "christian@clue.engineering",
- "homepage": "https://clue.engineering/"
- },
- {
- "name": "Cees-Jan Kiewiet",
- "email": "reactphp@ceesjankiewiet.nl",
- "homepage": "https://wyrihaximus.net/"
- },
- {
- "name": "Jan Sorgalla",
- "email": "jsorgalla@gmail.com",
- "homepage": "https://sorgalla.com/"
- },
- {
- "name": "Chris Boden",
- "email": "cboden@gmail.com",
- "homepage": "https://cboden.dev/"
- }
- ],
- "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
- "keywords": [
- "event-driven",
- "io",
- "non-blocking",
- "pipe",
- "reactphp",
- "readable",
- "stream",
- "writable"
- ],
- "support": {
- "issues": "https://github.com/reactphp/stream/issues",
- "source": "https://github.com/reactphp/stream/tree/v1.2.0"
- },
- "funding": [
- {
- "url": "https://github.com/WyriHaximus",
- "type": "github"
- },
- {
- "url": "https://github.com/clue",
- "type": "github"
- }
- ],
- "time": "2021-07-11T12:37:55+00:00"
- },
- {
- "name": "sebastian/code-unit-reverse-lookup",
- "version": "1.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
- "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619",
- "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619",
- "shasum": ""
- },
- "require": {
- "php": ">=5.6"
- },
- "require-dev": {
- "phpunit/phpunit": "^8.5"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Looks up which function or method a line of code belongs to",
- "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
- "support": {
- "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
- "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2020-11-30T08:15:22+00:00"
- },
- {
- "name": "sebastian/comparator",
- "version": "2.1.3",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9",
- "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9",
- "shasum": ""
- },
- "require": {
- "php": "^7.0",
- "sebastian/diff": "^2.0 || ^3.0",
- "sebastian/exporter": "^3.1"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.4"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1.x-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Jeff Welch",
- "email": "whatthejeff@gmail.com"
- },
- {
- "name": "Volker Dusch",
- "email": "github@wallbash.com"
- },
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@2bepublished.at"
- },
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "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",
- "source": "https://github.com/sebastianbergmann/comparator/tree/master"
- },
- "time": "2018-02-01T13:46:46+00:00"
- },
- {
- "name": "sebastian/diff",
- "version": "2.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
- "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd",
- "shasum": ""
- },
- "require": {
- "php": "^7.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.2"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Kore Nordmann",
- "email": "mail@kore-nordmann.de"
- },
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Diff implementation",
- "homepage": "https://github.com/sebastianbergmann/diff",
- "keywords": [
- "diff"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/diff/issues",
- "source": "https://github.com/sebastianbergmann/diff/tree/master"
- },
- "time": "2017-08-03T08:09:46+00:00"
- },
- {
- "name": "sebastian/environment",
- "version": "3.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
- "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
- "shasum": ""
- },
- "require": {
- "php": "^7.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.1.x-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": "http://www.github.com/sebastianbergmann/environment",
- "keywords": [
- "Xdebug",
- "environment",
- "hhvm"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/environment/issues",
- "source": "https://github.com/sebastianbergmann/environment/tree/master"
- },
- "time": "2017-07-01T08:51:00+00:00"
- },
- {
- "name": "sebastian/exporter",
- "version": "3.1.4",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "0c32ea2e40dbf59de29f3b49bf375176ce7dd8db"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0c32ea2e40dbf59de29f3b49bf375176ce7dd8db",
- "reference": "0c32ea2e40dbf59de29f3b49bf375176ce7dd8db",
- "shasum": ""
- },
- "require": {
- "php": ">=7.0",
- "sebastian/recursion-context": "^3.0"
- },
- "require-dev": {
- "ext-mbstring": "*",
- "phpunit/phpunit": "^8.5"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.1.x-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": "http://www.github.com/sebastianbergmann/exporter",
- "keywords": [
- "export",
- "exporter"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/exporter/issues",
- "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.4"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2021-11-11T13:51:24+00:00"
- },
- {
- "name": "sebastian/global-state",
- "version": "2.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
- "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
- "shasum": ""
- },
- "require": {
- "php": "^7.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.0"
- },
- "suggest": {
- "ext-uopz": "*"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.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": "http://www.github.com/sebastianbergmann/global-state",
- "keywords": [
- "global state"
- ],
- "support": {
- "issues": "https://github.com/sebastianbergmann/global-state/issues",
- "source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0"
- },
- "time": "2017-04-27T15:39:26+00:00"
- },
- {
- "name": "sebastian/object-enumerator",
- "version": "3.0.4",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/object-enumerator.git",
- "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2",
- "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2",
- "shasum": ""
- },
- "require": {
- "php": ">=7.0",
- "sebastian/object-reflector": "^1.1.1",
- "sebastian/recursion-context": "^3.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.0.x-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",
- "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2020-11-30T07:40:27+00:00"
- },
- {
- "name": "sebastian/object-reflector",
- "version": "1.1.2",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/object-reflector.git",
- "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d",
- "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d",
- "shasum": ""
- },
- "require": {
- "php": ">=7.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.1-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",
- "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2020-11-30T07:37:18+00:00"
- },
- {
- "name": "sebastian/recursion-context",
- "version": "3.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb",
- "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb",
- "shasum": ""
- },
- "require": {
- "php": ">=7.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^6.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.0.x-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": "http://www.github.com/sebastianbergmann/recursion-context",
- "support": {
- "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
- "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1"
- },
- "funding": [
- {
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
- }
- ],
- "time": "2020-11-30T07:34:24+00:00"
- },
- {
- "name": "sebastian/resource-operations",
- "version": "1.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/resource-operations.git",
- "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
- "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
- "shasum": ""
- },
- "require": {
- "php": ">=5.6.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Provides a list of PHP built-in functions that operate on resources",
- "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
- "support": {
- "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
- "source": "https://github.com/sebastianbergmann/resource-operations/tree/master"
- },
- "time": "2015-07-28T20:34:47+00:00"
- },
- {
- "name": "sebastian/version",
- "version": "2.0.1",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/version.git",
- "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
- "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
- "shasum": ""
- },
- "require": {
- "php": ">=5.6"
- },
- "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": "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",
- "source": "https://github.com/sebastianbergmann/version/tree/master"
- },
- "time": "2016-10-03T07:35:21+00:00"
- },
- {
- "name": "sirbrillig/phpcs-variable-analysis",
- "version": "v2.11.3",
- "source": {
- "type": "git",
- "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git",
- "reference": "c921498b474212fe4552928bbeb68d70250ce5e8"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/c921498b474212fe4552928bbeb68d70250ce5e8",
- "reference": "c921498b474212fe4552928bbeb68d70250ce5e8",
- "shasum": ""
- },
- "require": {
- "php": ">=5.4.0",
- "squizlabs/php_codesniffer": "^3.5"
- },
- "require-dev": {
- "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
- "limedeck/phpunit-detailed-printer": "^3.1 || ^4.0 || ^5.0",
- "phpstan/phpstan": "^0.11.8",
- "phpunit/phpunit": "^5.0 || ^6.5 || ^7.0 || ^8.0",
- "sirbrillig/phpcs-import-detection": "^1.1"
- },
- "type": "phpcodesniffer-standard",
- "autoload": {
- "psr-4": {
- "VariableAnalysis\\": "VariableAnalysis/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-2-Clause"
- ],
- "authors": [
- {
- "name": "Sam Graham",
- "email": "php-codesniffer-variableanalysis@illusori.co.uk"
- },
- {
- "name": "Payton Swick",
- "email": "payton@foolord.com"
- }
- ],
- "description": "A PHPCS sniff to detect problems with variables.",
- "support": {
- "issues": "https://github.com/sirbrillig/phpcs-variable-analysis/issues",
- "source": "https://github.com/sirbrillig/phpcs-variable-analysis",
- "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki"
- },
- "time": "2022-02-21T17:01:13+00:00"
- },
- {
- "name": "spatie/phpunit-watcher",
- "version": "1.23.6",
- "source": {
- "type": "git",
- "url": "https://github.com/spatie/phpunit-watcher.git",
- "reference": "c192fff763810c8378511bcf0069df4b91478866"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/spatie/phpunit-watcher/zipball/c192fff763810c8378511bcf0069df4b91478866",
- "reference": "c192fff763810c8378511bcf0069df4b91478866",
- "shasum": ""
- },
- "require": {
- "clue/stdio-react": "^2.4",
- "jolicode/jolinotif": "^2.2",
- "php": "^7.2 | ^8.0 | ^8.1",
- "symfony/console": "^5 | ^6",
- "symfony/finder": "^5.4 | ^6",
- "symfony/process": "^5.4 | ^6",
- "symfony/yaml": "^5.2 | ^6",
- "yosymfony/resource-watcher": "^2.0 | ^3.0"
- },
- "conflict": {
- "symfony/console": "<5.2",
- "yosymfony/resource-watcher": "<2.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^8.6 | ^9.0"
- },
- "bin": [
- "phpunit-watcher"
- ],
- "type": "library",
- "autoload": {
- "psr-4": {
- "Spatie\\PhpUnitWatcher\\": "src"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Freek Van der Herten",
- "email": "freek@spatie.be",
- "homepage": "https://spatie.be",
- "role": "Developer"
- }
- ],
- "description": "Automatically rerun PHPUnit tests when source code changes",
- "homepage": "https://github.com/spatie/phpunit-watcher",
- "keywords": [
- "phpunit-watcher",
- "spatie"
- ],
- "support": {
- "issues": "https://github.com/spatie/phpunit-watcher/issues",
- "source": "https://github.com/spatie/phpunit-watcher/tree/1.23.6"
- },
- "time": "2022-01-31T11:57:13+00:00"
- },
- {
- "name": "squizlabs/php_codesniffer",
- "version": "3.7.1",
- "source": {
- "type": "git",
- "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
- "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619",
- "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619",
- "shasum": ""
- },
- "require": {
- "ext-simplexml": "*",
- "ext-tokenizer": "*",
- "ext-xmlwriter": "*",
- "php": ">=5.4.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
- },
- "bin": [
- "bin/phpcs",
- "bin/phpcbf"
- ],
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.x-dev"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Greg Sherwood",
- "role": "lead"
- }
- ],
- "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
- "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
- "keywords": [
- "phpcs",
- "standards"
- ],
- "support": {
- "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
- "source": "https://github.com/squizlabs/PHP_CodeSniffer",
- "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
- },
- "time": "2022-06-18T07:21:10+00:00"
- },
- {
- "name": "symfony/console",
- "version": "v5.4.10",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/console.git",
- "reference": "4d671ab4ddac94ee439ea73649c69d9d200b5000"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/4d671ab4ddac94ee439ea73649c69d9d200b5000",
- "reference": "4d671ab4ddac94ee439ea73649c69d9d200b5000",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php73": "^1.9",
- "symfony/polyfill-php80": "^1.16",
- "symfony/service-contracts": "^1.1|^2|^3",
- "symfony/string": "^5.1|^6.0"
- },
- "conflict": {
- "psr/log": ">=3",
- "symfony/dependency-injection": "<4.4",
- "symfony/dotenv": "<5.1",
- "symfony/event-dispatcher": "<4.4",
- "symfony/lock": "<4.4",
- "symfony/process": "<4.4"
- },
- "provide": {
- "psr/log-implementation": "1.0|2.0"
- },
- "require-dev": {
- "psr/log": "^1|^2",
- "symfony/config": "^4.4|^5.0|^6.0",
- "symfony/dependency-injection": "^4.4|^5.0|^6.0",
- "symfony/event-dispatcher": "^4.4|^5.0|^6.0",
- "symfony/lock": "^4.4|^5.0|^6.0",
- "symfony/process": "^4.4|^5.0|^6.0",
- "symfony/var-dumper": "^4.4|^5.0|^6.0"
- },
- "suggest": {
- "psr/log": "For using the console logger",
- "symfony/event-dispatcher": "",
- "symfony/lock": "",
- "symfony/process": ""
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Console\\": ""
- },
- "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 the creation of beautiful and testable command line interfaces",
- "homepage": "https://symfony.com",
- "keywords": [
- "cli",
- "command line",
- "console",
- "terminal"
- ],
- "support": {
- "source": "https://github.com/symfony/console/tree/v5.4.10"
- },
- "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": "2022-06-26T13:00:04+00:00"
- },
- {
- "name": "symfony/deprecation-contracts",
- "version": "v2.5.2",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
- "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
- }
- },
- "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/v2.5.2"
- },
- "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": "2022-01-02T09:53:40+00:00"
- },
- {
- "name": "symfony/finder",
- "version": "v5.4.8",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/finder.git",
- "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/9b630f3427f3ebe7cd346c277a1408b00249dad9",
- "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-php80": "^1.16"
- },
- "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/v5.4.8"
- },
- "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": "2022-04-15T08:07:45+00:00"
- },
- {
- "name": "symfony/polyfill-ctype",
- "version": "v1.26.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
- "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "provide": {
- "ext-ctype": "*"
- },
- "suggest": {
- "ext-ctype": "For best performance"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.26-dev"
- },
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/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.26.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": "2022-05-24T11:49:31+00:00"
- },
- {
- "name": "symfony/polyfill-intl-grapheme",
- "version": "v1.26.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "433d05519ce6990bf3530fba6957499d327395c2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2",
- "reference": "433d05519ce6990bf3530fba6957499d327395c2",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "suggest": {
- "ext-intl": "For best performance"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.26-dev"
- },
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
- }
- },
- "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 intl's grapheme_* functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "grapheme",
- "intl",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.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": "2022-05-24T11:49:31+00:00"
- },
- {
- "name": "symfony/polyfill-intl-normalizer",
- "version": "v1.26.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "219aa369ceff116e673852dce47c3a41794c14bd"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
- "reference": "219aa369ceff116e673852dce47c3a41794c14bd",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "suggest": {
- "ext-intl": "For best performance"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.26-dev"
- },
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
- },
- "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 for intl's Normalizer class and related functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "intl",
- "normalizer",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.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": "2022-05-24T11:49:31+00:00"
- },
- {
- "name": "symfony/polyfill-mbstring",
- "version": "v1.26.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
- "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "provide": {
- "ext-mbstring": "*"
- },
- "suggest": {
- "ext-mbstring": "For best performance"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.26-dev"
- },
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/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.26.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": "2022-05-24T11:49:31+00:00"
- },
- {
- "name": "symfony/polyfill-php73",
- "version": "v1.26.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-php73.git",
- "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85",
- "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.26-dev"
- },
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Php73\\": ""
- },
- "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 7.3+ features to lower PHP versions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.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": "2022-05-24T11:49:31+00:00"
- },
- {
- "name": "symfony/polyfill-php80",
- "version": "v1.26.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
- "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.26-dev"
- },
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/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.26.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": "2022-05-10T07:21:04+00:00"
- },
- {
- "name": "symfony/process",
- "version": "v5.4.8",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/process.git",
- "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/597f3fff8e3e91836bb0bd38f5718b56ddbde2f3",
- "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/polyfill-php80": "^1.16"
- },
- "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/v5.4.8"
- },
- "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": "2022-04-08T05:07:18+00:00"
- },
- {
- "name": "symfony/service-contracts",
- "version": "v2.5.2",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/service-contracts.git",
- "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
- "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "psr/container": "^1.1",
- "symfony/deprecation-contracts": "^2.1|^3"
- },
- "conflict": {
- "ext-psr": "<1.1|>=2"
- },
- "suggest": {
- "symfony/service-implementation": ""
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Contracts\\Service\\": ""
- }
- },
- "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 writing services",
- "homepage": "https://symfony.com",
- "keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
- ],
- "support": {
- "source": "https://github.com/symfony/service-contracts/tree/v2.5.2"
- },
- "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": "2022-05-30T19:17:29+00:00"
- },
- {
- "name": "symfony/string",
- "version": "v5.4.10",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/string.git",
- "reference": "4432bc7df82a554b3e413a8570ce2fea90e94097"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/4432bc7df82a554b3e413a8570ce2fea90e94097",
- "reference": "4432bc7df82a554b3e413a8570ce2fea90e94097",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-intl-grapheme": "~1.0",
- "symfony/polyfill-intl-normalizer": "~1.0",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php80": "~1.15"
- },
- "conflict": {
- "symfony/translation-contracts": ">=3.0"
- },
- "require-dev": {
- "symfony/error-handler": "^4.4|^5.0|^6.0",
- "symfony/http-client": "^4.4|^5.0|^6.0",
- "symfony/translation-contracts": "^1.1|^2",
- "symfony/var-exporter": "^4.4|^5.0|^6.0"
- },
- "type": "library",
- "autoload": {
- "files": [
- "Resources/functions.php"
- ],
- "psr-4": {
- "Symfony\\Component\\String\\": ""
- },
- "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 an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
- "homepage": "https://symfony.com",
- "keywords": [
- "grapheme",
- "i18n",
- "string",
- "unicode",
- "utf-8",
- "utf8"
- ],
- "support": {
- "source": "https://github.com/symfony/string/tree/v5.4.10"
- },
- "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": "2022-06-26T15:57:47+00:00"
- },
- {
- "name": "symfony/yaml",
- "version": "v5.4.10",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/yaml.git",
- "reference": "04e42926429d9e8b39c174387ab990bf7817f7a2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/04e42926429d9e8b39c174387ab990bf7817f7a2",
- "reference": "04e42926429d9e8b39c174387ab990bf7817f7a2",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-ctype": "^1.8"
- },
- "conflict": {
- "symfony/console": "<5.3"
- },
- "require-dev": {
- "symfony/console": "^5.3|^6.0"
- },
- "suggest": {
- "symfony/console": "For validating YAML files using the lint command"
- },
- "bin": [
- "Resources/bin/yaml-lint"
- ],
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Yaml\\": ""
- },
- "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": "Loads and dumps YAML files",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/yaml/tree/v5.4.10"
- },
- "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": "2022-06-20T11:50:59+00:00"
- },
- {
- "name": "theseer/tokenizer",
- "version": "1.2.1",
- "source": {
- "type": "git",
- "url": "https://github.com/theseer/tokenizer.git",
- "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
- "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
- "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.1"
- },
- "funding": [
- {
- "url": "https://github.com/theseer",
- "type": "github"
- }
- ],
- "time": "2021-07-28T10:34:58+00:00"
- },
- {
- "name": "webmozart/assert",
- "version": "1.11.0",
- "source": {
- "type": "git",
- "url": "https://github.com/webmozarts/assert.git",
- "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
- "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
- "shasum": ""
- },
- "require": {
- "ext-ctype": "*",
- "php": "^7.2 || ^8.0"
- },
- "conflict": {
- "phpstan/phpstan": "<0.12.20",
- "vimeo/psalm": "<4.6.1 || 4.6.2"
- },
- "require-dev": {
- "phpunit/phpunit": "^8.5.13"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.10-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Webmozart\\Assert\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Bernhard Schussek",
- "email": "bschussek@gmail.com"
- }
- ],
- "description": "Assertions to validate method input/output with nice error messages.",
- "keywords": [
- "assert",
- "check",
- "validate"
- ],
- "support": {
- "issues": "https://github.com/webmozarts/assert/issues",
- "source": "https://github.com/webmozarts/assert/tree/1.11.0"
- },
- "time": "2022-06-03T18:03:27+00:00"
- },
- {
- "name": "wp-coding-standards/wpcs",
- "version": "2.3.0",
- "source": {
- "type": "git",
- "url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
- "reference": "7da1894633f168fe244afc6de00d141f27517b62"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62",
- "reference": "7da1894633f168fe244afc6de00d141f27517b62",
- "shasum": ""
- },
- "require": {
- "php": ">=5.4",
- "squizlabs/php_codesniffer": "^3.3.1"
- },
- "require-dev": {
- "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
- "phpcompatibility/php-compatibility": "^9.0",
- "phpcsstandards/phpcsdevtools": "^1.0",
- "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
- },
- "suggest": {
- "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
- },
- "type": "phpcodesniffer-standard",
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Contributors",
- "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
- }
- ],
- "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
- "keywords": [
- "phpcs",
- "standards",
- "wordpress"
- ],
- "support": {
- "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues",
- "source": "https://github.com/WordPress/WordPress-Coding-Standards",
- "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki"
- },
- "time": "2020-05-13T23:57:56+00:00"
- },
- {
- "name": "yoast/phpunit-polyfills",
- "version": "1.0.3",
- "source": {
- "type": "git",
- "url": "https://github.com/Yoast/PHPUnit-Polyfills.git",
- "reference": "5ea3536428944955f969bc764bbe09738e151ada"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/5ea3536428944955f969bc764bbe09738e151ada",
- "reference": "5ea3536428944955f969bc764bbe09738e151ada",
- "shasum": ""
- },
- "require": {
- "php": ">=5.4",
- "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0"
- },
- "require-dev": {
- "yoast/yoastcs": "^2.2.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "1.x-dev",
- "dev-develop": "1.x-dev"
- }
- },
- "autoload": {
- "files": [
- "phpunitpolyfills-autoload.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
- {
- "name": "Team Yoast",
- "email": "support@yoast.com",
- "homepage": "https://yoast.com"
- },
- {
- "name": "Contributors",
- "homepage": "https://github.com/Yoast/PHPUnit-Polyfills/graphs/contributors"
- }
- ],
- "description": "Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit cross-version compatible tests",
- "homepage": "https://github.com/Yoast/PHPUnit-Polyfills",
- "keywords": [
- "phpunit",
- "polyfill",
- "testing"
- ],
- "support": {
- "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues",
- "source": "https://github.com/Yoast/PHPUnit-Polyfills"
- },
- "time": "2021-11-23T01:37:03+00:00"
- },
- {
- "name": "yosymfony/resource-watcher",
- "version": "v3.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/yosymfony/resource-watcher.git",
- "reference": "2f197cee0231c06db865d4ad2d8d7cd3faead2f8"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/yosymfony/resource-watcher/zipball/2f197cee0231c06db865d4ad2d8d7cd3faead2f8",
- "reference": "2f197cee0231c06db865d4ad2d8d7cd3faead2f8",
- "shasum": ""
- },
- "require": {
- "php": ">=5.6",
- "symfony/finder": "^2.7|^3.0|^4.0|^5.0"
- },
- "require-dev": {
- "phpunit/phpunit": "^5.7",
- "symfony/filesystem": "^2.7|^3.0|^4.0|^5.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Yosymfony\\ResourceWatcher\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Victor Puertas",
- "email": "vpgugr@gmail.com"
- }
- ],
- "description": "A simple resource watcher using Symfony Finder",
- "homepage": "http://yosymfony.com",
- "keywords": [
- "finder",
- "resources",
- "symfony",
- "watcher"
- ],
- "support": {
- "issues": "https://github.com/yosymfony/resource-watcher/issues",
- "source": "https://github.com/yosymfony/resource-watcher/tree/master"
- },
- "time": "2020-06-10T14:58:36+00:00"
- }
- ],
- "aliases": [],
- "minimum-stability": "stable",
- "stability-flags": [],
- "prefer-stable": false,
- "prefer-lowest": false,
- "platform": [],
- "platform-dev": [],
- "platform-overrides": {
- "php": "7.4"
- },
- "plugin-api-version": "2.3.0"
-}
diff --git a/lib/experimental/class-wp-webfonts-provider-local.php b/lib/experimental/class-wp-webfonts-provider-local.php
index f96b18ea698637..dea47dc5ddefe3 100644
--- a/lib/experimental/class-wp-webfonts-provider-local.php
+++ b/lib/experimental/class-wp-webfonts-provider-local.php
@@ -22,19 +22,46 @@
* generate styles from locally-hosted font files is contained
* in this provider.
*
- * @since 6.0.0
+ * @since 6.1.0
*/
class WP_Webfonts_Provider_Local extends WP_Webfonts_Provider {
/**
* The provider's unique ID.
*
- * @since 6.0.0
+ * @since 6.1.0
*
* @var string
*/
protected $id = 'local';
+ /**
+ * Holds a string which contains the type attribute for style tag.
+ *
+ * If the active theme does not declare HTML5 support for 'style',
+ * then it initializes as `type='text/css'`.
+ *
+ * @since 6.1.0
+ *
+ * @var string
+ */
+ private $type_attr = '';
+
+ /**
+ * Constructor.
+ *
+ * @since 6.1.0
+ */
+ public function __construct() {
+ if (
+ function_exists( 'is_admin' ) && ! is_admin()
+ &&
+ function_exists( 'current_theme_supports' ) && ! current_theme_supports( 'html5', 'style' )
+ ) {
+ $this->type_attr = " type='text/css'";
+ }
+ }
+
/**
* Gets the `@font-face` CSS styles for locally-hosted font files.
*
@@ -81,7 +108,7 @@ class WP_Webfonts_Provider_Local extends WP_Webfonts_Provider {
* }
*
*
- * @since 6.0.0
+ * @since 6.1.0
*
* @return string The `@font-face` CSS.
*/
@@ -96,6 +123,12 @@ public function get_css() {
$css .= '@font-face{' . $this->build_font_face_css( $webfont ) . '}';
}
+ $css = sprintf(
+ "\n",
+ $this->type_attr,
+ $css
+ );
+
return $css;
}
diff --git a/lib/experimental/class-wp-webfonts-provider.php b/lib/experimental/class-wp-webfonts-provider.php
index a49b8a324b7f5f..24dd93b9615048 100644
--- a/lib/experimental/class-wp-webfonts-provider.php
+++ b/lib/experimental/class-wp-webfonts-provider.php
@@ -69,4 +69,13 @@ public function set_webfonts( array $webfonts ) {
* @return string The `@font-face` CSS.
*/
abstract public function get_css();
+
+ /**
+ * Prints the generated styles.
+ *
+ * @since 6.1.0
+ */
+ public function print_styles() {
+ echo $this->get_css();
+ }
}
diff --git a/lib/experimental/class-wp-webfonts-utils.php b/lib/experimental/class-wp-webfonts-utils.php
new file mode 100644
index 00000000000000..cf506209bc8a0d
--- /dev/null
+++ b/lib/experimental/class-wp-webfonts-utils.php
@@ -0,0 +1,113 @@
+register_provider( 'local', 'WP_Webfonts_Provider_Local' );
-
- // Register callback to generate and enqueue styles.
- if ( did_action( 'wp_enqueue_scripts' ) ) {
- $this->stylesheet_handle = 'webfonts-footer';
- $hook = 'wp_print_footer_scripts';
- } else {
- $this->stylesheet_handle = 'webfonts';
- $hook = 'wp_enqueue_scripts';
- }
- add_action( $hook, array( $this, 'generate_and_enqueue_styles' ) );
-
- // Enqueue webfonts in the block editor.
- add_action( 'admin_init', array( $this, 'generate_and_enqueue_editor_styles' ) );
+ public function __construct() {
+ /**
+ * Fires when the WP_Webfonts instance is initialized.
+ *
+ * @since X.X.X
+ *
+ * @param WP_Webfonts $wp_webfonts WP_Webfonts instance (passed by reference).
+ */
+ do_action_ref_array( 'wp_default_webfonts', array( &$this ) );
}
/**
- * Get the list of registered fonts.
+ * Gets the list of all registered web fonts and variations.
*
- * @since 6.0.0
+ * @since 6.1.0
*
- * @return array[]
+ * @return string[]
*/
- public function get_registered_webfonts() {
- return $this->registered_webfonts;
+ public function get_registered() {
+ return array_keys( $this->registered );
}
/**
- * Get the list of enqueued fonts.
+ * Gets the list of enqueued web fonts and variations.
+ *
+ * @since 6.1.0
*
* @return array[]
*/
- public function get_enqueued_webfonts() {
- return $this->enqueued_webfonts;
+ public function get_enqueued() {
+ return $this->queue;
}
/**
- * Get the list of all fonts.
+ * Gets a list of all registered variations for the given font family.
*
- * @return array[]
+ * @since 6.1.0
+ *
+ * @param string $font_family_handle The font family for the variations.
+ * @return array An array of registered variations.
*/
- public function get_all_webfonts() {
- return array_merge( $this->get_registered_webfonts(), $this->get_enqueued_webfonts() );
+ public function get_variations( $font_family_handle ) {
+ if ( ! isset( $this->registered[ $font_family_handle ] ) ) {
+ return array();
+ }
+
+ return $this->registered[ $font_family_handle ]->deps;
}
/**
- * Get the list of providers.
+ * Removes a font family and all registered variations.
*
- * @since 6.0.0
+ * @since 6.1.0
*
- * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID.
+ * @param string $font_family_handle The font family to remove.
*/
- public function get_providers() {
- return $this->providers;
+ public function remove_font_family( $font_family_handle ) {
+ if ( ! isset( $this->registered[ $font_family_handle ] ) ) {
+ return;
+ }
+
+ $variations = $this->registered[ $font_family_handle ]->deps;
+
+ foreach ( $variations as $variation ) {
+ $this->remove( $variation );
+ }
+
+ $this->remove( $font_family_handle );
}
/**
- * Register a webfont.
+ * Registers a variation to the given font family.
*
- * @since 6.0.0
+ * @since 6.1.0
*
- * @param array $webfont Webfont to be registered.
- * @return string|false The font family slug if successfully registered, else false.
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ * @param string $variation_handle Optional. The variation's handle. When none is provided, the
+ * handle will be dynamically generated.
+ * Default empty string.
+ * @return string|null Variation handle on success. Else null.
*/
- public function register_webfont( array $webfont ) {
- $webfont = $this->validate_webfont( $webfont );
+ public function add_variation( $font_family_handle, array $variation, $variation_handle = '' ) {
+ if ( ! WP_Webfonts_Utils::is_defined( $font_family_handle ) ) {
+ trigger_error( 'Font family handle must be a non-empty string.' );
+ return null;
+ }
- // If not valid, bail out.
- if ( ! $webfont ) {
- return false;
+ if ( '' !== $variation_handle && ! WP_Webfonts_Utils::is_defined( $variation_handle ) ) {
+ trigger_error( 'Variant handle must be a non-empty string.' );
+ return null;
+ }
+
+ // Register the font family when it does not yet exist.
+ if ( ! isset( $this->registered[ $font_family_handle ] ) ) {
+ if ( ! $this->add( $font_family_handle, false ) ) {
+ return null;
+ }
}
- $slug = $this->get_font_slug( $webfont );
+ $variation = $this->validate_variation( $font_family_handle, $variation );
- // Initialize a new font-family collection.
- if ( ! isset( $this->registered_webfonts[ $slug ] ) ) {
- $this->registered_webfonts[ $slug ] = array();
+ // Variation validation failed.
+ if ( ! $variation ) {
+ return null;
}
- $this->registered_webfonts[ $slug ][] = $webfont;
- return $slug;
- }
+ if ( '' === $variation_handle ) {
+ $variation_handle = WP_Webfonts_Utils::convert_variation_into_handle( $font_family_handle, $variation );
+ if ( is_null( $variation_handle ) ) {
+ return null;
+ }
+ }
- /**
- * Enqueue a font-family that has been already registered.
- *
- * @param string $font_family_name The font family name to be enqueued.
- * @return bool True if successfully enqueued, else false.
- */
- public function enqueue_webfont( $font_family_name ) {
- $slug = $this->get_font_slug( $font_family_name );
+ // Bail out if the variant is already registered.
+ if ( $this->is_variation_registered( $font_family_handle, $variation_handle ) ) {
+ return $variation_handle;
+ }
+
+ if ( array_key_exists( 'src', $variation ) ) {
+ $result = $this->add( $variation_handle, $variation['src'] );
+ } else {
+ $result = $this->add( $variation_handle, false );
+ }
- if ( isset( $this->enqueued_webfonts[ $slug ] ) ) {
- return true;
+ // Bail out if the registration failed.
+ if ( ! $result ) {
+ return null;
}
- if ( ! isset( $this->registered_webfonts[ $slug ] ) ) {
- /* translators: %s unique slug to identify the font family of the webfont */
- _doing_it_wrong( __METHOD__, sprintf( __( 'The "%s" font family is not registered.', 'gutenberg' ), $slug ), '6.0.0' );
+ $this->add_data( $variation_handle, 'font-properties', $variation );
- return false;
+ // Add the font variation as a dependency to the registered font family.
+ $this->add_dependency( $font_family_handle, $variation_handle );
+
+ $this->providers[ $variation['provider'] ]['fonts'][] = $variation_handle;
+
+ return $variation_handle;
+ }
+
+ /**
+ * Checks if the variation is registered.
+ *
+ * @since 6.1.0
+ *
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param string $variant_handle Variation's handle.
+ * @return bool
+ */
+ private function is_variation_registered( $font_family_handle, $variant_handle ) {
+ if ( ! isset( $this->registered[ $font_family_handle ] ) ) {
+ return array();
}
- $this->enqueued_webfonts[ $slug ] = $this->registered_webfonts[ $slug ];
- unset( $this->registered_webfonts[ $slug ] );
- return true;
+ return in_array( $variant_handle, $this->registered[ $font_family_handle ]->deps );
}
/**
- * Get the font slug.
+ * Removes a font variation.
*
- * @since 6.0.0
+ * @since 6.1.0
*
- * @param array|string $to_convert The value to convert into a slug. Expected as the web font's array
- * or a font-family as a string.
- * @return string|false The font slug on success, or false if the font-family cannot be determined.
+ * @param string $font_family_handle The font family for this variation.
+ * @param string $variation_handle The variation's handle to remove.
*/
- public static function get_font_slug( $to_convert ) {
- if ( is_array( $to_convert ) ) {
- if ( isset( $to_convert['font-family'] ) ) {
- $to_convert = $to_convert['font-family'];
- } elseif ( isset( $to_convert['fontFamily'] ) ) {
- $to_convert = $to_convert['fontFamily'];
- } else {
- _doing_it_wrong( __METHOD__, __( 'Could not determine the font family name.', 'gutenberg' ), '6.0.0' );
- return false;
- }
+ public function remove_variation( $font_family_handle, $variation_handle ) {
+ $this->remove( $font_family_handle );
+
+ if ( ! isset( $this->registered[ $font_family_handle ] ) ) {
+ return;
}
- return sanitize_title( $to_convert );
+ // Remove the variation as a dependency.
+ $this->registered[ $font_family_handle ]->deps = array_values(
+ array_diff(
+ $this->registered[ $font_family_handle ]->deps,
+ array( $variation_handle )
+ )
+ );
}
/**
- * Validate a webfont.
+ * Adds a variation as a dependency to the given font family.
*
- * @since 6.0.0
+ * @since 6.1.0
+ *
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param string $variation_handle The variation's handle.
+ */
+ private function add_dependency( $font_family_handle, $variation_handle ) {
+ $this->registered[ $font_family_handle ]->deps[] = $variation_handle;
+ }
+
+ /**
+ * Validates and sanitizes a variation.
*
- * @param array $webfont The webfont arguments.
+ * @since 6.1.0
*
- * @return array|false The validated webfont arguments, or false if the webfont is invalid.
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ * @return array|false|object
*/
- public function validate_webfont( $webfont ) {
- $webfont = wp_parse_args(
- $webfont,
- array(
- 'provider' => 'local',
- 'font-family' => '',
- 'font-style' => 'normal',
- 'font-weight' => '400',
- 'font-display' => 'fallback',
- )
+ private function validate_variation( $font_family_handle, $variation ) {
+ $defaults = array(
+ 'provider' => 'local',
+ 'font-style' => 'normal',
+ 'font-weight' => '400',
+ 'font-display' => 'fallback',
);
- // Check the font-family.
- if ( empty( $webfont['font-family'] ) || ! is_string( $webfont['font-family'] ) ) {
- trigger_error( __( 'Webfont font family must be a non-empty string.', 'gutenberg' ) );
- return false;
- }
+ $defaults = apply_filters( 'wp_webfont_variation_defaults', $defaults );
+
+ $defaults['font-family'] = $font_family_handle;
+ $variation = wp_parse_args( $variation, $defaults );
// Local fonts need a "src".
- if ( 'local' === $webfont['provider'] ) {
+ if ( 'local' === $variation['provider'] ) {
// Make sure that local fonts have 'src' defined.
- if ( empty( $webfont['src'] ) || ( ! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] ) ) ) {
+ if ( empty( $variation['src'] ) || ( ! is_string( $variation['src'] ) && ! is_array( $variation['src'] ) ) ) {
trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.', 'gutenberg' ) );
return false;
}
+ } elseif ( ! class_exists( $variation['provider'] ) ) {
+ trigger_error( __( 'The provider class specified does not exist.', 'gutenberg' ) );
+ return false;
}
// Validate the 'src' property.
- if ( ! empty( $webfont['src'] ) ) {
- foreach ( (array) $webfont['src'] as $src ) {
+ if ( ! empty( $variation['src'] ) ) {
+ foreach ( (array) $variation['src'] as $src ) {
if ( empty( $src ) || ! is_string( $src ) ) {
trigger_error( __( 'Each webfont src must be a non-empty string.', 'gutenberg' ) );
return false;
@@ -238,14 +282,14 @@ public function validate_webfont( $webfont ) {
}
// Check the font-weight.
- if ( ! is_string( $webfont['font-weight'] ) && ! is_int( $webfont['font-weight'] ) ) {
- trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.', 'gutenberg' ) );
+ if ( ! is_string( $variation['font-weight'] ) && ! is_int( $variation['font-weight'] ) ) {
+ trigger_error( __( 'Webfont font-weight must be a properly formatted string or integer.', 'gutenberg' ) );
return false;
}
// Check the font-display.
- if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'swap' ), true ) ) {
- $webfont['font-display'] = 'fallback';
+ if ( ! in_array( $variation['font-display'], array( 'auto', 'block', 'fallback', 'swap' ), true ) ) {
+ $variation['font-display'] = 'fallback';
}
$valid_props = array(
@@ -268,150 +312,172 @@ public function validate_webfont( $webfont ) {
'provider',
);
- foreach ( $webfont as $prop => $value ) {
+ foreach ( $variation as $prop => $value ) {
if ( ! in_array( $prop, $valid_props, true ) ) {
- unset( $webfont[ $prop ] );
+ unset( $variation[ $prop ] );
}
}
- return $webfont;
+ return $variation;
}
/**
- * Register a provider.
+ * Processes the items and dependencies.
*
- * @since 6.0.0
+ * Processes the items passed to it or the queue, and their dependencies.
*
- * @param string $provider The provider name.
- * @param string $class The provider class name.
- * @return bool True if successfully registered, else false.
+ * @since 6.1.0
+ *
+ * @param string|string[]|false $handles Optional. Items to be processed: queue (false),
+ * single item (string), or multiple items (array of strings).
+ * Default false.
+ * @param int|false $group Optional. Group level: level (int), no group (false).
+ *
+ * @return array|string[] Array of web font handles that have been processed.
+ * An empty array if none were processed.
*/
- public function register_provider( $provider, $class ) {
- if ( empty( $provider ) || empty( $class ) ) {
- return false;
+ public function do_items( $handles = false, $group = false ) {
+ /*
+ * If nothing is passed, print the queue. If a string is passed,
+ * print that item. If an array is passed, print those items.
+ */
+ $handles = false === $handles ? $this->queue : (array) $handles;
+ $this->all_deps( $handles );
+
+ $this->to_do_keyed_handles = array_flip( $this->to_do );
+
+ foreach ( $this->get_providers() as $provider_id => $provider ) {
+ // Bail out if the provider class does not exist.
+ if ( ! class_exists( $provider['class'] ) ) {
+ /* translators: %s is the provider name. */
+ trigger_error( sprintf( __( 'Webfont provider "%s" is not registered.', 'gutenberg' ), $provider_id ) );
+ continue;
+ }
+
+ $this->do_item( $provider_id, $group );
}
- $this->providers[ $provider ] = $class;
- return true;
+
+ return $this->done;
}
/**
- * Generate and enqueue webfonts styles.
+ * Invokes each provider to process and print its styles.
+ *
+ * @since 6.1.0
+ *
+ * @see WP_Dependencies::do_item()
*
- * @since 6.0.0
+ * @param string $provider_id The font family to process.
+ * @param int|false $group Not used.
+ * @return bool
*/
- public function generate_and_enqueue_styles() {
- // Generate the styles.
- $webfonts = $this->get_webfonts_by_provider( $this->get_enqueued_webfonts() );
- $styles = $this->generate_styles( $webfonts );
+ public function do_item( $provider_id, $group = false ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
+ // Bail out if the provider is not registered.
+ if ( ! isset( $this->providers[ $provider_id ] ) ) {
+ return false;
+ }
- // Bail out if there are no styles to enqueue.
- if ( '' === $styles ) {
- return;
+ $fonts = $this->get_enqueued_fonts_for_provider( $provider_id );
+ // If there are no web fonts for this provider, skip it.
+ if ( empty( $fonts ) ) {
+ return false;
+ }
+
+ $provider_fonts = array();
+
+ foreach ( $fonts as $font_handle ) {
+ $provider_fonts[ $font_handle ] = $this->get_data( $font_handle, 'font-properties' );
}
- // Enqueue the stylesheet.
- wp_register_style( $this->stylesheet_handle, '' );
- wp_enqueue_style( $this->stylesheet_handle );
+ $provider = new $this->providers[ $provider_id ]['class']();
+ $provider->set_webfonts( $provider_fonts );
+ $provider->print_styles();
- // Add the styles to the stylesheet.
- wp_add_inline_style( $this->stylesheet_handle, $styles );
+ foreach ( $fonts as $font_handle ) {
+ $this->done[] = $font_handle;
+ unset(
+ $this->to_do[ $this->to_do_keyed_handles[ $font_handle ] ],
+ $this->to_do_keyed_handles[ $font_handle ]
+ );
+ }
+
+ return true;
}
/**
- * Generate and enqueue editor styles.
+ * Register a provider.
+ *
+ * @since 6.1.0
*
- * @since 6.0.0
+ * @param string $provider The provider name.
+ * @param string $class The provider class name.
+ * @return bool True if successfully registered, else false.
*/
- public function generate_and_enqueue_editor_styles() {
- // Generate the styles.
- $webfonts = $this->get_webfonts_by_provider( $this->get_all_webfonts() );
- $styles = $this->generate_styles( $webfonts );
-
- // Bail out if there are no styles to enqueue.
- if ( '' === $styles ) {
- return;
+ public function register_provider( $provider, $class ) {
+ if ( empty( $provider ) || empty( $class ) || ! class_exists( $class ) ) {
+ return false;
}
- wp_enqueue_style( 'wp-block-library' );
- wp_add_inline_style( 'wp-block-library', $styles );
+ $this->providers[ $provider ] = array(
+ 'class' => $class,
+ 'fonts' => array(),
+ );
+ return true;
}
/**
- * Generate styles for webfonts.
+ * Get the list of providers.
*
- * @since 6.0.0
+ * @since 6.1.0
*
- * @param array[] $webfonts_by_provider Webfonts organized by provider.
- * @return string $styles Generated styles.
+ * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID.
*/
- private function generate_styles( array $webfonts_by_provider ) {
- $styles = '';
- $providers = $this->get_providers();
-
- /*
- * Loop through each of the providers to get the CSS for their respective webfonts
- * to incrementally generate the collective styles for all of them.
- */
- foreach ( $providers as $provider_id => $provider_class ) {
-
- // Bail out if the provider class does not exist.
- if ( ! class_exists( $provider_class ) ) {
- /* translators: %s is the provider name. */
- trigger_error( sprintf( __( 'Webfont provider "%s" is not registered.', 'gutenberg' ), $provider_id ) );
- continue;
- }
-
- $provider_webfonts = isset( $webfonts_by_provider[ $provider_id ] )
- ? $webfonts_by_provider[ $provider_id ]
- : array();
+ public function get_providers() {
+ return $this->providers;
+ }
- // If there are no registered webfonts for this provider, skip it.
- if ( empty( $provider_webfonts ) ) {
- continue;
- }
+ /**
+ * Retrieves a list of enqueued web font variations for a provider.
+ *
+ * @since 6.1.0
+ *
+ * @param string $provider_id Provider's unique ID.
+ * @return array[] Webfonts organized by providers.
+ */
+ private function get_enqueued_fonts_for_provider( $provider_id ) {
+ $providers = $this->get_providers();
- /*
- * Process the webfonts by first passing them to the provider via `set_webfonts()`
- * and then getting the CSS from the provider.
- */
- $provider = new $provider_class();
- $provider->set_webfonts( $provider_webfonts );
- $styles .= $provider->get_css();
+ if ( empty( $providers[ $provider_id ] ) ) {
+ return array();
}
- return $styles;
+ return array_intersect(
+ $providers[ $provider_id ]['fonts'],
+ $this->to_do
+ );
}
-
/**
- * Reorganizes webfonts grouped by font-family into grouped by provider.
+ * Get the font slug.
*
- * @param array[] $font_families Font families and each of their webfonts.
- * @return array[] Webfonts organized by providers.
+ * @since X.X.X
+ * @deprecated Use WP_Webfonts_Utils::convert_font_family_into_handle()
+ *
+ * @param array|string $to_convert The value to convert into a slug. Expected as the web font's array
+ * or a font-family as a string.
+ * @return string|false The font slug on success, or false if the font-family cannot be determined.
*/
- private function get_webfonts_by_provider( array $font_families ) {
- $providers = $this->get_providers();
- $webfonts_by_provider = array();
-
- foreach ( $font_families as $webfonts ) {
- foreach ( $webfonts as $webfont ) {
- $provider = $webfont['provider'];
-
- // Skip if the provider is not registered.
- if ( ! isset( $providers[ $provider ] ) ) {
- /* translators: %s is the provider name. */
- trigger_error( sprintf( __( 'Webfont provider "%s" is not registered.', 'gutenberg' ), $provider ) );
- continue;
- }
+ public static function get_font_slug( $to_convert ) {
+ _deprecated_function(
+ __METHOD__,
+ 'X.X.X', // Gutenberg version, not Core as this method will not be backported to Core.
+ 'Use WP_Webfonts_Utils::get_font_family_from_variation() to get the font family from an array and WP_Webfonts_Utils::convert_font_family_into_handle() to get the handle'
+ );
- // Initialize a new provider collection.
- if ( ! isset( $webfonts_by_provider[ $provider ] ) ) {
- $webfonts_by_provider[ $provider ] = array();
- }
- $webfonts_by_provider[ $provider ][] = $webfont;
- }
- }
+ $font_family = is_array( $to_convert )
+ ? WP_Webfonts_Utils::get_font_family_from_variation( $to_convert )
+ : $to_convert;
- return $webfonts_by_provider;
+ return WP_Webfonts_Utils::convert_font_family_into_handle( $font_family );
}
}
diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php
index f0a37677eb0637..d0281708bbf137 100644
--- a/lib/experimental/register-webfonts-from-theme-json.php
+++ b/lib/experimental/register-webfonts-from-theme-json.php
@@ -5,173 +5,182 @@
* @package gutenberg
*/
-/**
- * Register webfonts defined in theme.json.
- */
-function gutenberg_register_webfonts_from_theme_json() {
- // Get settings.
- $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings();
-
- // If in the editor, add webfonts defined in variations.
- if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
- $variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations();
-
- foreach ( $variations as $variation ) {
-
- // Sanity check: Skip if fontFamilies are not defined in the variation.
- if (
- empty( $variation['settings'] ) ||
- empty( $variation['settings']['typography'] ) ||
- empty( $variation['settings']['typography']['fontFamilies'] )
- ) {
- continue;
- }
+if ( ! function_exists( 'gutenberg_register_webfonts_from_theme_json' ) ) {
+ /**
+ * Register webfonts defined in theme.json.
+ */
+ function gutenberg_register_webfonts_from_theme_json() {
+ // Get settings.
+ $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings();
- // Merge the variation settings with the global settings.
- $settings['typography'] = empty( $settings['typography'] ) ? array() : $settings['typography'];
- $settings['typography']['fontFamilies'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies'];
- $settings['typography']['fontFamilies']['theme'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']['theme'];
- $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] );
+ // If in the editor, add webfonts defined in variations.
+ if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
+ $variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations();
- // Make sure there are no duplicates.
- $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] );
- }
- }
+ foreach ( $variations as $variation ) {
- // Bail out early if there are no settings for webfonts.
- if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) {
- return;
- }
-
- $webfonts = array();
+ // Sanity check: Skip if fontFamilies are not defined in the variation.
+ if ( empty( $variation['settings'] ) || empty( $variation['settings']['typography'] ) || empty( $variation['settings']['typography']['fontFamilies'] ) ) {
+ continue;
+ }
- // Look for fontFamilies.
- foreach ( $settings['typography']['fontFamilies'] as $font_families ) {
- foreach ( $font_families as $font_family ) {
+ // Merge the variation settings with the global settings.
+ $settings['typography'] = empty( $settings['typography'] ) ? array() : $settings['typography'];
+ $settings['typography']['fontFamilies'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies'];
+ $settings['typography']['fontFamilies']['theme'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']['theme'];
+ $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] );
- // Skip if fontFace is not defined.
- if ( empty( $font_family['fontFace'] ) ) {
- continue;
+ // Make sure there are no duplicates.
+ $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] );
}
+ }
- $font_family['fontFace'] = (array) $font_family['fontFace'];
+ // Bail out early if there are no settings for webfonts.
+ if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) {
+ return;
+ }
- foreach ( $font_family['fontFace'] as $font_face ) {
- // Skip if the webfont was registered through the Webfonts API.
- if ( isset( $font_face['origin'] ) && 'gutenberg_wp_webfonts_api' === $font_face['origin'] ) {
+ $webfonts = array();
+ $handles = array();
+
+ // Look for fontFamilies.
+ foreach ( $settings['typography']['fontFamilies'] as $font_families ) {
+ foreach ( $font_families as $font_family ) {
+
+ // Skip if fontFace is not defined.
+ if ( empty( $font_family['fontFace'] ) ) {
continue;
}
- // Check if webfonts have a "src" param, and if they do account for the use of "file:./".
- if ( ! empty( $font_face['src'] ) ) {
- $font_face['src'] = (array) $font_face['src'];
+ $font_family['fontFace'] = (array) $font_family['fontFace'];
+
+ foreach ( $font_family['fontFace'] as $font_face ) {
+ // Skip if the webfont was registered through the Webfonts API.
+ if ( isset( $font_face['origin'] ) && 'gutenberg_wp_webfonts_api' === $font_face['origin'] ) {
+ continue;
+ }
+
+ // Check if webfonts have a "src" param, and if they do account for the use of "file:./".
+ if ( ! empty( $font_face['src'] ) ) {
+ $font_face['src'] = (array) $font_face['src'];
- foreach ( $font_face['src'] as $src_key => $url ) {
- // Tweak the URL to be relative to the theme root.
- if ( ! str_starts_with( $url, 'file:./' ) ) {
- continue;
+ foreach ( $font_face['src'] as $src_key => $url ) {
+ // Tweak the URL to be relative to the theme root.
+ if ( ! str_starts_with( $url, 'file:./' ) ) {
+ continue;
+ }
+ $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) );
}
- $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) );
}
- }
- // Convert keys to kebab-case.
- foreach ( $font_face as $property => $value ) {
- $kebab_case = _wp_to_kebab_case( $property );
- $font_face[ $kebab_case ] = $value;
- if ( $kebab_case !== $property ) {
- unset( $font_face[ $property ] );
+ // Convert keys to kebab-case.
+ foreach ( $font_face as $property => $value ) {
+ $kebab_case = _wp_to_kebab_case( $property );
+ $font_face[ $kebab_case ] = $value;
+ if ( $kebab_case !== $property ) {
+ unset( $font_face[ $property ] );
+ }
+ }
+
+ $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $font_face );
+ if ( empty( $font_family_handle ) ) {
+ $font_family = $font_family['slug'];
+ }
+ $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family );
+ if ( is_null( $font_family_handle ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Font family not defined in the variation or "slug".', 'gutenberg' ), '6.1.0' );
+ }
+
+ $handles[] = $font_family_handle;
+ if ( ! array_key_exists( $font_family_handle, $webfonts ) ) {
+ $webfonts[ $font_family_handle ] = array();
}
- }
- $webfonts[] = $font_face;
+ $webfonts[ $font_family_handle ][] = $font_face;
+ }
}
}
- }
- foreach ( $webfonts as $webfont ) {
- wp_webfonts()->register_webfont( $webfont );
- }
- foreach ( $webfonts as $webfont ) {
- wp_webfonts()->enqueue_webfont( $webfont['font-family'] );
- }
-}
-/**
- * Add missing fonts data to the global styles.
- *
- * @param array $data The global styles.
- * @return array The global styles with missing fonts data.
- */
-function gutenberg_add_registered_webfonts_to_theme_json( $data ) {
- $font_families_registered = wp_webfonts()->get_all_webfonts();
- $font_families_from_theme = array();
- if ( ! empty( $data['settings'] ) && ! empty( $data['settings']['typography'] ) && ! empty( $data['settings']['typography']['fontFamilies'] ) ) {
- $font_families_from_theme = $data['settings']['typography']['fontFamilies'];
+ wp_register_webfonts( $webfonts );
+ wp_enqueue_webfont( $handles );
}
+}
+if ( ! function_exists( 'gutenberg_add_registered_webfonts_to_theme_json' ) ) {
/**
- * Helper to get an array of the font-families.
+ * Add missing fonts data to the global styles.
*
- * @param array $families_data The font-families data.
- * @return array The font-families array.
+ * @param array $data The global styles.
+ * @return array The global styles with missing fonts data.
*/
- $get_families = static function( $families_data ) {
- $families = array();
- foreach ( $families_data as $family ) {
- $families[] = WP_Webfonts::get_font_slug( $family );
+ function gutenberg_add_registered_webfonts_to_theme_json( $data ) {
+ $font_families_registered = wp_webfonts()->get_registered();
+ $font_families_from_theme = array();
+ if ( ! empty( $data['settings'] ) && ! empty( $data['settings']['typography'] ) && ! empty( $data['settings']['typography']['fontFamilies'] ) ) {
+ $font_families_from_theme = $data['settings']['typography']['fontFamilies'];
}
- // Micro-optimization: Use array_flip( array_flip( $array ) )
- // instead of array_unique( $array ) because it's faster.
- // The result is the same.
- return array_flip( array_flip( $families ) );
- };
+ /**
+ * Helper to get an array of the font-families.
+ *
+ * @param array $families_data The font-families data.
+ * @return array The font-families array.
+ */
+ $get_families = static function ( $families_data ) {
+ $families = array();
+ foreach ( $families_data as $family ) {
+ $families[] = WP_Webfonts::get_font_slug( $family );
+ }
- // Diff the arrays to find the missing fonts.
- $to_add = array_diff(
- array_keys( $font_families_registered ),
- $get_families( $font_families_from_theme )
- );
+ // Micro-optimization: Use array_flip( array_flip( $array ) )
+ // instead of array_unique( $array ) because it's faster.
+ // The result is the same.
+ return array_flip( array_flip( $families ) );
+ };
- // Bail out early if there are no missing fonts.
- if ( empty( $to_add ) ) {
- return $data;
- }
+ // Diff the arrays to find the missing fonts.
+ $to_add = array_diff( array_keys( $font_families_registered ), $get_families( $font_families_from_theme ) );
- // Make sure the path to settings.typography.fontFamilies.theme exists
- // before adding missing fonts.
- if ( empty( $data['settings'] ) ) {
- $data['settings'] = array();
- }
- if ( empty( $data['settings']['typography'] ) ) {
- $data['settings']['typography'] = array();
- }
- if ( empty( $data['settings']['typography']['fontFamilies'] ) ) {
- $data['settings']['typography']['fontFamilies'] = array();
- }
+ // Bail out early if there are no missing fonts.
+ if ( empty( $to_add ) ) {
+ return $data;
+ }
+
+ // Make sure the path to settings.typography.fontFamilies.theme exists
+ // before adding missing fonts.
+ if ( empty( $data['settings'] ) ) {
+ $data['settings'] = array();
+ }
+ if ( empty( $data['settings']['typography'] ) ) {
+ $data['settings']['typography'] = array();
+ }
+ if ( empty( $data['settings']['typography']['fontFamilies'] ) ) {
+ $data['settings']['typography']['fontFamilies'] = array();
+ }
- foreach ( $to_add as $slug ) {
- $font_faces_for_family = $font_families_registered[ $slug ];
- $family_name = $font_faces_for_family[0]['font-family'];
- $font_faces = array();
+ foreach ( $to_add as $slug ) {
+ $font_faces_for_family = $font_families_registered[ $slug ];
+ $family_name = $font_faces_for_family[0]['font-family'];
+ $font_faces = array();
- foreach ( $font_faces_for_family as $font_face ) {
- $camel_cased = array( 'origin' => 'gutenberg_wp_webfonts_api' );
- foreach ( $font_face as $key => $value ) {
- $camel_cased[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value;
+ foreach ( $font_faces_for_family as $font_face ) {
+ $camel_cased = array( 'origin' => 'gutenberg_wp_webfonts_api' );
+ foreach ( $font_face as $key => $value ) {
+ $camel_cased[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value;
+ }
+ $font_faces[] = $camel_cased;
}
- $font_faces[] = $camel_cased;
+
+ $data['settings']['typography']['fontFamilies'][] = array(
+ 'fontFamily' => str_contains( $family_name, ' ' ) ? "'{$family_name}'" : $family_name,
+ 'name' => $family_name,
+ 'slug' => $slug,
+ 'fontFace' => $font_faces,
+ );
}
- $data['settings']['typography']['fontFamilies'][] = array(
- 'fontFamily' => str_contains( $family_name, ' ' ) ? "'{$family_name}'" : $family_name,
- 'name' => $family_name,
- 'slug' => $slug,
- 'fontFace' => $font_faces,
- );
+ return $data;
}
-
- return $data;
}
// `gutenberg_register_webfonts_from_theme_json()` calls `WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()`, which instantiates `WP_Theme_JSON_Gutenberg()`;
diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php
index 201101d1d7093e..81057b95b02bc7 100644
--- a/lib/experimental/webfonts.php
+++ b/lib/experimental/webfonts.php
@@ -9,152 +9,203 @@
if ( ! function_exists( 'wp_webfonts' ) ) {
/**
- * Instantiates the webfonts controller, if not already set, and returns it.
+ * Initialize $wp_webfonts if it has not been set.
*
- * @since 6.0.0
+ * @since 6.1.0
+ *
+ * @global WP_Webfonts $wp_webfonts
*
- * @return WP_Webfonts Instance of the controller.
+ * @return WP_Webfonts WP_Webfonts instance.
*/
function wp_webfonts() {
global $wp_webfonts;
- if ( ! $wp_webfonts instanceof WP_Webfonts ) {
+ if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) {
$wp_webfonts = new WP_Webfonts();
- $wp_webfonts->init();
+ $wp_webfonts->register_provider( 'local', 'WP_Webfonts_Provider_Local' );
}
return $wp_webfonts;
}
}
+if ( ! function_exists( 'wp_register_font_family' ) ) {
+ /**
+ * Registers a font family.
+ *
+ * @since 6.1.0
+ *
+ * @param string $font_family The font family's name or handle to register.
+ * @return string|null The font family handle when successfully registered. Else null.
+ */
+ function wp_register_font_family( $font_family ) {
+ $handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family );
+ if ( ! $handle ) {
+ return null;
+ }
+
+ $result = wp_webfonts()->add( $handle, false ) ? $handle : null;
+ return $result ? $handle : null;
+ }
+}
+
+if ( ! function_exists( 'wp_register_webfont_variation' ) ) {
+ /**
+ * Registers a variation to the given font family.
+ *
+ * @since 6.1.0
+ *
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ * @param string $variation_handle Optional. The variation's handle. When none is provided, the
+ * handle will be dynamically generated.
+ * Default empty string.
+ * @return string|null Variation handle on success. Else null.
+ */
+ function wp_register_webfont_variation( $font_family_handle, array $variation, $variation_handle = '' ) {
+ return wp_webfonts()->add_variation( $font_family_handle, $variation, $variation_handle );
+ }
+}
+
if ( ! function_exists( 'wp_register_webfonts' ) ) {
/**
- * Registers a collection of webfonts.
- *
- * Example of how to register Source Serif Pro font with font-weight range of 200-900
- * and font-style of normal and italic:
- *
- * If the font files are contained within the theme:
- *
- * wp_register_webfonts(
- * array(
- * array(
- * 'provider' => 'local',
- * 'font-family' => 'Source Serif Pro',
- * 'font-weight' => '200 900',
- * 'font-style' => 'normal',
- * 'src' => get_theme_file_uri( 'assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2' ),
- * ),
- * array(
- * 'provider' => 'local',
- * 'font-family' => 'Source Serif Pro',
- * 'font-weight' => '200 900',
- * 'font-style' => 'italic',
- * 'src' => get_theme_file_uri( 'assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2' ),
- * ),
- * )
- * );
- *
- *
- * Webfonts should be registered in the `after_setup_theme` hook.
+ * Registers a list of web fonts and variations.
*
- * @since 6.0.0
+ * @since 6.1.0
*
- * @param array[] $webfonts Webfonts to be registered.
- * This contains an array of webfonts to be registered.
- * Each webfont is an array.
- * @return string[] The font family slug of the registered webfonts.
+ * @param array[] $webfonts Web fonts to be registered.
+ * @return string[] The font family handle of the registered web fonts.
*/
function wp_register_webfonts( array $webfonts ) {
- $registered_webfont_slugs = array();
+ $registered = array();
- foreach ( $webfonts as $webfont ) {
- $slug = wp_register_webfont( $webfont );
+ foreach ( $webfonts as $font_family => $variations ) {
+ /*
+ * Handle the deprecated web font's structure but alert developers
+ * to modify their web font structure to group and key by font family.
+ *
+ * Note: This code block will not be backported to Core.
+ */
+ if ( ! WP_Webfonts_Utils::is_defined( $font_family ) ) {
+ _doing_it_wrong(
+ __FUNCTION__,
+ __( 'Variations must be grouped and keyed by their font family.', 'gutenberg' ),
+ '6.1.0'
+ );
+ $font_family_handle = wp_register_webfont( $variations );
+ if ( ! $font_family_handle ) {
+ continue;
+ }
+ $registered[ $font_family_handle ] = true;
+ continue;
+ } // end of code block for deprecated web fonts structure.
+
+ $font_family_handle = wp_register_font_family( $font_family );
+ if ( ! $font_family_handle ) {
+ continue;
+ }
- if ( is_string( $slug ) ) {
- $registered_webfont_slugs[ $slug ] = true;
+ // Register each of the variations for this font family.
+ foreach ( $variations as $handle => $variation ) {
+ wp_register_webfont(
+ $variation,
+ $font_family_handle,
+ WP_Webfonts_Utils::is_defined( $handle ) ? $handle : ''
+ );
}
+
+ $registered[] = $font_family_handle;
}
- return array_keys( $registered_webfont_slugs );
+ return $registered;
}
}
if ( ! function_exists( 'wp_register_webfont' ) ) {
/**
- * Registers a single webfont.
- *
- * Example of how to register Source Serif Pro font with font-weight range of 200-900:
- *
- * If the font file is contained within the theme:
- *
- *
- * wp_register_webfont(
- * array(
- * 'provider' => 'local',
- * 'font-family' => 'Source Serif Pro',
- * 'font-weight' => '200 900',
- * 'font-style' => 'normal',
- * 'src' => get_theme_file_uri( 'assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2' ),
- * )
- * );
- *
+ * Registers a single web font.
*
- * @since 6.0.0
+ * @since 6.1.0
*
- * @param array $webfont Webfont to be registered.
- * @return string|false The font family slug if successfully registered, else false.
+ * @param array $variation Array of variation properties to be registered.
+ * @param string $font_family_handle Optional. Font family handle for the given variation.
+ * Default empty string.
+ * @param string $variation_handle Optional. Handle for the variation to register.
+ * @return string|null The font family slug if successfully registered. Else null.
*/
- function wp_register_webfont( array $webfont ) {
- return wp_webfonts()->register_webfont( $webfont );
+ function wp_register_webfont( array $variation, $font_family_handle = '', $variation_handle = '' ) {
+ // When font family's handle is not passed, attempt to get it from the variation.
+ if ( ! WP_Webfonts_Utils::is_defined( $font_family_handle ) ) {
+ $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $variation );
+ if ( $font_family ) {
+ $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family );
+ }
+ }
+
+ if ( empty( $font_family_handle ) ) {
+ trigger_error( 'Font family handle must be a non-empty string.' );
+ return null;
+ }
+
+ return wp_webfonts()->add_variation( $font_family_handle, $variation, $variation_handle )
+ ? $font_family_handle
+ : null;
}
}
-if ( ! function_exists( 'wp_enqueue_webfonts' ) ) {
+if ( ! function_exists( 'wp_enqueue_webfont' ) ) {
/**
- * Enqueues a collection of font families.
- *
- * Example of how to enqueue Source Serif Pro and Roboto font families, both registered beforehand.
+ * Enqueues one or more font family and all of its variations.
*
- *
- * wp_enqueue_webfonts(
- * 'Roboto',
- * 'Sans Serif Pro'
- * );
- *
- *
- * Font families should be enqueued from the `init` hook or later.
+ * @param string|string[] $font_family Font family handle (string) or handles (array of strings).
+ */
+ function wp_enqueue_webfont( $font_family ) {
+ wp_webfonts()->enqueue( $font_family );
+ }
+}
+
+if ( ! function_exists( 'wp_enqueue_webfont_variations' ) ) {
+ /**
+ * Enqueues a given set of web font variations.
*
- * @since 6.0.0
+ * @TODO Is this needed?
*
- * @param string[] $webfonts Font families to be enqueued.
+ * @param string[] $variations Font variations.
*/
- function wp_enqueue_webfonts( array $webfonts ) {
- foreach ( $webfonts as $webfont ) {
- wp_enqueue_webfont( $webfont );
+ function wp_enqueue_webfont_variations( $variations ) {
+ $wp_webfonts = wp_webfonts();
+
+ // Looking to enqueue all variations of a font family.
+ foreach ( $variations as $variation ) {
+ $wp_webfonts->enqueue( $variation );
}
}
}
-if ( ! function_exists( 'wp_enqueue_webfont' ) ) {
+if ( ! function_exists( 'wp_deregister_font_family' ) ) {
/**
- * Enqueue a single font family that has been registered beforehand.
- *
- * Example of how to enqueue Source Serif Pro font:
+ * Deregisters a font family and all registered variations.
*
- *
- * wp_enqueue_webfont( 'Source Serif Pro' );
- *
+ * @since 6.1.0
*
- * Font families should be enqueued from the `init` hook or later.
+ * @param string $font_family_handle The font family to remove.
+ */
+ function wp_deregister_font_family( $font_family_handle ) {
+ wp_webfonts()->remove_font_family( $font_family_handle );
+ }
+}
+
+if ( ! function_exists( 'wp_deregister_webfont_variation' ) ) {
+ /**
+ * Deregisters a font variation.
*
- * @since 6.0.0
+ * @since 6.1.0
*
- * @param string $font_family_name The font family name to be enqueued.
- * @return bool True if successfully enqueued, else false.
+ * @param string $font_family_handle The font family for this variation.
+ * @param string $variation_handle The variation's handle to remove.
*/
- function wp_enqueue_webfont( $font_family_name ) {
- return wp_webfonts()->enqueue_webfont( $font_family_name );
+ function wp_deregister_webfont_variation( $font_family_handle, $variation_handle ) {
+ wp_webfonts()->remove_variation( $font_family_handle, $variation_handle );
}
}
@@ -211,6 +262,40 @@ function wp_get_webfont_providers() {
}
}
+if ( ! function_exists( 'wp_print_webfonts' ) ) {
+ /**
+ * Invokes each provider to process and print its styles.
+ *
+ * @since 6.1.0
+ *
+ * @param string|string[]|false $handles Optional. Items to be processed: queue (false),
+ * single item (string), or multiple items (array of strings).
+ * Default false.
+ * @return array|string[] Array of web font handles that have been processed.
+ * An empty array if none were processed.
+ */
+ function wp_print_webfonts( $handles = false ) {
+ global $wp_webfonts;
+
+ if ( '' === $handles ) { // For 'wp_head'.
+ $handles = false;
+ }
+
+ _wp_scripts_maybe_doing_it_wrong( __FUNCTION__ );
+
+ if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) {
+ if ( ! $handles ) {
+ return array(); // No need to instantiate if nothing is there.
+ }
+ }
+
+ return wp_webfonts()->do_items( $handles );
+ }
+}
+
+add_action( 'admin_print_styles', 'wp_print_webfonts' );
+add_action( 'wp_head', 'wp_print_webfonts' );
+
/**
* Add webfonts mime types.
*/
diff --git a/lib/load.php b/lib/load.php
index 9600d3100d3b7e..9f274ab9dc2eb3 100644
--- a/lib/load.php
+++ b/lib/load.php
@@ -96,6 +96,7 @@ function gutenberg_is_experiment_enabled( $name ) {
// Experimental features.
remove_action( 'plugins_loaded', '_wp_theme_json_webfonts_handler' ); // Turns off WP 6.0's stopgap handler for Webfonts API.
require __DIR__ . '/experimental/block-editor-settings-mobile.php';
+require __DIR__ . '/experimental/class-wp-webfonts-utils.php';
require __DIR__ . '/experimental/register-webfonts-from-theme-json.php';
require __DIR__ . '/experimental/class-wp-theme-json-gutenberg.php';
require __DIR__ . '/experimental/class-wp-theme-json-resolver-gutenberg.php';
diff --git a/packages/style-engine/class-wp-style-engine.php b/packages/style-engine/class-wp-style-engine.php
index 33533fc872f699..f518c4f442bd01 100644
--- a/packages/style-engine/class-wp-style-engine.php
+++ b/packages/style-engine/class-wp-style-engine.php
@@ -491,6 +491,11 @@ protected static function get_css_declarations( $style_value, $style_definition,
// If the input contains an array, assume box model-like properties
// for styles such as margins and padding.
if ( is_array( $style_value ) ) {
+ // Bail out early if the `'individual'` property is not defined.
+ if ( ! isset( $style_property_keys['individual'] ) ) {
+ return $css_declarations;
+ }
+
foreach ( $style_value as $key => $value ) {
if ( is_string( $value ) && strpos( $value, 'var:' ) !== false && ! $should_skip_css_vars && ! empty( $style_definition['css_vars'] ) ) {
$value = static::get_css_var_value( $value, $style_definition['css_vars'] );
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index ce2c3a67a6a423..59c87341f6eb29 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -87,5 +87,14 @@
./packages/block-serialization-default-parser/parser.php
+ /phpunit/*
+
+
+
+
+ /phpunit/*
+
+
+ /phpunit/*
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 65ef5a17e8b9d5..2f6e997b45b086 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -5,6 +5,7 @@
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
+ convertDeprecationsToExceptions="true"
>
diff --git a/phpunit/blocks/render-last-posts-test.php b/phpunit/blocks/render-last-posts-test.php
index 49734adb515fdc..a20b6f717a4fa3 100644
--- a/phpunit/blocks/render-last-posts-test.php
+++ b/phpunit/blocks/render-last-posts-test.php
@@ -24,6 +24,10 @@ class Tests_Blocks_RenderLastPosts extends WP_UnitTestCase {
* @var array
*/
protected static $attachment_ids;
+ /**
+ * @var array|null
+ */
+ private $original_block_supports;
public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
self::$sticky_post = $factory->post->create_and_get(
@@ -49,6 +53,21 @@ public static function wpTearDownAfterClass() {
}
}
+ public function set_up() {
+ parent::set_up();
+
+ $this->original_block_supports = WP_Block_Supports::$block_to_render;
+ WP_Block_Supports::$block_to_render = array(
+ 'attrs' => array(),
+ 'blockName' => '',
+ );
+ }
+
+ public function tear_down() {
+ WP_Block_Supports::$block_to_render = $this->original_block_supports;
+ parent::tear_down();
+ }
+
/**
* @covers ::render_block_core_latest_posts
*/
@@ -56,10 +75,13 @@ public function test_render_block_core_latest_posts() {
$action = new MockAction();
add_filter( 'update_post_metadata_cache', array( $action, 'filter' ), 10, 2 );
$attributes = array(
- 'displayFeaturedImage' => true,
- 'postsToShow' => 5,
- 'orderBy' => 'date',
- 'order' => 'DESC',
+ 'displayFeaturedImage' => true,
+ 'postsToShow' => 5,
+ 'orderBy' => 'date',
+ 'order' => 'DESC',
+ 'excerptLength' => 0,
+ 'featuredImageSizeSlug' => '',
+ 'addLinkToFeaturedImage' => false,
);
gutenberg_render_block_core_latest_posts( $attributes );
@@ -75,10 +97,13 @@ public function test_render_block_core_latest_posts_no_priming() {
$action = new MockAction();
add_filter( 'update_post_metadata_cache', array( $action, 'filter' ), 10, 2 );
$attributes = array(
- 'displayFeaturedImage' => false,
- 'postsToShow' => 5,
- 'orderBy' => 'date',
- 'order' => 'DESC',
+ 'displayFeaturedImage' => false,
+ 'postsToShow' => 5,
+ 'orderBy' => 'date',
+ 'order' => 'DESC',
+ 'excerptLength' => 0,
+ 'featuredImageSizeSlug' => '',
+ 'addLinkToFeaturedImage' => false,
);
gutenberg_render_block_core_latest_posts( $attributes );
diff --git a/phpunit/bootstrap.php b/phpunit/bootstrap.php
index 9423c5a1efc5c3..fac777864200a8 100644
--- a/phpunit/bootstrap.php
+++ b/phpunit/bootstrap.php
@@ -5,6 +5,23 @@
* @package Gutenberg
*/
+// Debug settings for parity with WordPress Core's PHPUnit tests.
+if ( ! defined( 'WP_DEBUG' ) ) {
+ define( 'WP_DEBUG', true );
+}
+if ( ! defined( 'LOCAL_WP_DEBUG_LOG' ) ) {
+ define( 'LOCAL_WP_DEBUG_LOG', true );
+}
+if ( ! defined( 'LOCAL_WP_DEBUG_DISPLAY' ) ) {
+ define( 'LOCAL_WP_DEBUG_DISPLAY', true );
+}
+if ( ! defined( 'LOCAL_SCRIPT_DEBUG' ) ) {
+ define( 'LOCAL_SCRIPT_DEBUG', true );
+}
+if ( ! defined( 'LOCAL_WP_ENVIRONMENT_TYPE' ) ) {
+ define( 'LOCAL_WP_ENVIRONMENT_TYPE', 'local' );
+}
+
// Require composer dependencies.
require_once dirname( __DIR__ ) . '/vendor/autoload.php';
diff --git a/phpunit/class-block-library-navigation-link-test.php b/phpunit/class-block-library-navigation-link-test.php
index 982ed393ea0b2e..7b91742ec22724 100644
--- a/phpunit/class-block-library-navigation-link-test.php
+++ b/phpunit/class-block-library-navigation-link-test.php
@@ -18,6 +18,10 @@ class Block_Library_Navigation_Link_Test extends WP_UnitTestCase {
private static $pages;
private static $terms;
+ /**
+ * @var array|null
+ */
+ private $original_block_supports;
public static function wpSetUpBeforeClass() {
@@ -90,6 +94,21 @@ public static function wpTearDownAfterClass() {
}
}
+ public function set_up() {
+ parent::set_up();
+
+ $this->original_block_supports = WP_Block_Supports::$block_to_render;
+ WP_Block_Supports::$block_to_render = array(
+ 'attrs' => array(),
+ 'blockName' => '',
+ );
+ }
+
+ public function tear_down() {
+ WP_Block_Supports::$block_to_render = $this->original_block_supports;
+ parent::tear_down();
+ }
+
function test_returns_link_when_post_is_published() {
$page_id = self::$page->ID;
diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php
index 34d9905743c61e..593b66374e6321 100644
--- a/phpunit/class-wp-theme-json-test.php
+++ b/phpunit/class-wp-theme-json-test.php
@@ -736,66 +736,7 @@ function test_set_spacing_sizes( $spacing_scale, $expected_output ) {
*/
function data_generate_spacing_scale_fixtures() {
return array(
- 'empty_spacing_scale' => array(
- 'spacing_scale' => array(),
- 'expected_output' => null,
- ),
-
- 'invalid_spacing_scale_values_missing_operator' => array(
- 'spacingScale' => array(
- 'operator' => '',
- 'increment' => 1.5,
- 'steps' => 1,
- 'mediumStep' => 4,
- 'unit' => 'rem',
- ),
- 'expected_output' => null,
- ),
-
- 'invalid_spacing_scale_values_non_numeric_increment' => array(
- 'spacingScale' => array(
- 'operator' => '+',
- 'increment' => 'add two to previous value',
- 'steps' => 1,
- 'mediumStep' => 4,
- 'unit' => 'rem',
- ),
- 'expected_output' => null,
- ),
-
- 'invalid_spacing_scale_values_non_numeric_steps' => array(
- 'spacingScale' => array(
- 'operator' => '+',
- 'increment' => 1.5,
- 'steps' => 'spiral staircase preferred',
- 'mediumStep' => 4,
- 'unit' => 'rem',
- ),
- 'expected_output' => null,
- ),
-
- 'invalid_spacing_scale_values_non_numeric_medium_step' => array(
- 'spacingScale' => array(
- 'operator' => '+',
- 'increment' => 1.5,
- 'steps' => 5,
- 'mediumStep' => 'That which is just right',
- 'unit' => 'rem',
- ),
- 'expected_output' => null,
- ),
-
- 'invalid_spacing_scale_values_missing_unit' => array(
- 'spacingScale' => array(
- 'operator' => '+',
- 'increment' => 1.5,
- 'steps' => 5,
- 'mediumStep' => 4,
- ),
- 'expected_output' => null,
- ),
-
- 'one_step_spacing_scale' => array(
+ 'one_step_spacing_scale' => array(
'spacingScale' => array(
'operator' => '+',
'increment' => 1.5,
@@ -1006,6 +947,94 @@ function data_generate_spacing_scale_fixtures() {
);
}
+ /**
+ * Tests generating the spacing presets array based on the spacing scale provided.
+ *
+ * @dataProvider data_set_spacing_sizes_when_invalid
+ */
+ public function test_set_spacing_sizes_when_invalid( $spacing_scale, $expected_output ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( 'Some of the theme.json settings.spacing.spacingScale values are invalid' );
+
+ $theme_json = new WP_Theme_JSON_Gutenberg(
+ array(
+ 'version' => 2,
+ 'settings' => array(
+ 'spacing' => array(
+ 'spacingScale' => $spacing_scale,
+ ),
+ ),
+ )
+ );
+
+ $theme_json->set_spacing_sizes();
+ $this->assertSame( $expected_output, _wp_array_get( $theme_json->get_raw_data(), array( 'settings', 'spacing', 'spacingSizes', 'default' ) ) );
+ }
+
+ /**
+ * Data provider for spacing scale tests.
+ *
+ * @return array
+ */
+ function data_set_spacing_sizes_when_invalid() {
+ return array(
+
+ 'invalid_spacing_scale_values_missing_operator' => array(
+ 'spacingScale' => array(
+ 'operator' => '',
+ 'increment' => 1.5,
+ 'steps' => 1,
+ 'mediumStep' => 4,
+ 'unit' => 'rem',
+ ),
+ 'expected_output' => null,
+ ),
+
+ 'invalid_spacing_scale_values_non_numeric_increment' => array(
+ 'spacingScale' => array(
+ 'operator' => '+',
+ 'increment' => 'add two to previous value',
+ 'steps' => 1,
+ 'mediumStep' => 4,
+ 'unit' => 'rem',
+ ),
+ 'expected_output' => null,
+ ),
+
+ 'invalid_spacing_scale_values_non_numeric_steps' => array(
+ 'spacingScale' => array(
+ 'operator' => '+',
+ 'increment' => 1.5,
+ 'steps' => 'spiral staircase preferred',
+ 'mediumStep' => 4,
+ 'unit' => 'rem',
+ ),
+ 'expected_output' => null,
+ ),
+
+ 'invalid_spacing_scale_values_non_numeric_medium_step' => array(
+ 'spacingScale' => array(
+ 'operator' => '+',
+ 'increment' => 1.5,
+ 'steps' => 5,
+ 'mediumStep' => 'That which is just right',
+ 'unit' => 'rem',
+ ),
+ 'expected_output' => null,
+ ),
+
+ 'invalid_spacing_scale_values_missing_unit' => array(
+ 'spacingScale' => array(
+ 'operator' => '+',
+ 'increment' => 1.5,
+ 'steps' => 5,
+ 'mediumStep' => 4,
+ ),
+ 'expected_output' => null,
+ ),
+ );
+ }
+
function test_get_styles_for_block_with_padding_aware_alignments() {
$theme_json = new WP_Theme_JSON_Gutenberg(
array(
diff --git a/phpunit/class-wp-webfonts-test.php b/phpunit/class-wp-webfonts-test.php
deleted file mode 100644
index 97e2762df4b568..00000000000000
--- a/phpunit/class-wp-webfonts-test.php
+++ /dev/null
@@ -1,451 +0,0 @@
-old_wp_webfonts = $wp_webfonts;
-
- $wp_webfonts = null;
- }
-
- public function tear_down() {
- global $wp_webfonts;
-
- $wp_webfonts = $this->old_wp_webfonts;
- parent::tear_down();
- }
-
- /**
- * Test wp_register_webfonts() bulk register webfonts.
- *
- * @covers wp_register_webfonts
- * @covers WP_Webfonts::register_font
- * @covers WP_Webfonts::get_registered_fonts
- * @covers WP_Webfonts::get_enqueued_fonts
- */
- public function test_wp_register_webfonts() {
- $font_family_name = 'Source Serif Pro';
-
- $fonts = array(
- array(
- 'provider' => 'local',
- 'font-family' => $font_family_name,
- 'font-style' => 'normal',
- 'font-weight' => '200 900',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
- 'font-display' => 'fallback',
- ),
- array(
- 'provider' => 'local',
- 'font-family' => $font_family_name,
- 'font-style' => 'italic',
- 'font-weight' => '200 900',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2',
- 'font-display' => 'fallback',
- ),
- );
-
- $expected = array(
- wp_webfonts()->get_font_slug( $font_family_name ) => $fonts,
- );
-
- wp_register_webfonts( $fonts );
- $this->assertEquals( $expected, wp_webfonts()->get_registered_webfonts() );
- $this->assertEquals( array(), wp_webfonts()->get_enqueued_webfonts() );
- }
-
- /**
- * Test wp_register_webfont() register a single webfont.
- *
- * @covers wp_register_webfont
- * @covers WP_Webfonts::register_font
- * @covers WP_Webfonts::get_registered_fonts
- * @covers WP_Webfonts::get_enqueued_fonts
- */
- public function test_wp_register_webfont() {
- $font_family_name = 'Source Serif Pro';
-
- $font = array(
- 'provider' => 'local',
- 'font-family' => $font_family_name,
- 'font-style' => 'normal',
- 'font-weight' => '200 900',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
- 'font-display' => 'fallback',
- );
-
- $expected = array(
- wp_webfonts()->get_font_slug( $font_family_name ) => array( $font ),
- );
-
- wp_register_webfont( $font );
- $this->assertEquals( $expected, wp_webfonts()->get_registered_webfonts() );
- $this->assertEquals( array(), wp_webfonts()->get_enqueued_webfonts() );
- }
-
- /**
- * Test wp_register_webfont() does not enqueue the webfont on registration.
- *
- * @covers wp_register_webfont
- * @covers WP_Webfonts::register_font
- * @covers WP_Webfonts::get_registered_fonts
- * @covers WP_Webfonts::get_enqueued_fonts
- */
- public function test_wp_register_webfont_does_not_enqueue_on_registration() {
- $font_family_name = 'Source Serif Pro';
-
- $font = array(
- 'provider' => 'local',
- 'font-family' => $font_family_name,
- 'font-style' => 'normal',
- 'font-weight' => '200 900',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
- 'font-display' => 'fallback',
- );
-
- $expected = array(
- wp_webfonts()->get_font_slug( $font_family_name ) => array( $font ),
- );
-
- wp_register_webfont( $font );
- $this->assertEquals( $expected, wp_webfonts()->get_registered_webfonts() );
- $this->assertEquals( array(), wp_webfonts()->get_enqueued_webfonts() );
- }
-
- /**
- * Test wp_enqueue_webfonts() bulk enqueue webfonts.
- *
- * @covers wp_enqueue_webfonts
- * @covers WP_Webfonts::enqueue_font
- * @covers WP_Webfonts::get_enqueued_fonts
- * @covers WP_Webfonts::get_registered_fonts
- */
- public function test_wp_enqueue_webfonts() {
- $source_serif_pro = array(
- 'provider' => 'local',
- 'font-family' => 'Source Serif Pro',
- 'font-style' => 'normal',
- 'font-weight' => '200 900',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
- 'font-display' => 'fallback',
- );
-
- wp_register_webfont( $source_serif_pro );
-
- $roboto = array(
- 'provider' => 'local',
- 'font-family' => 'Roboto',
- 'font-style' => 'normal',
- 'font-weight' => '400',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/roboto/Roboto.ttf.woff2',
- 'font-display' => 'fallback',
- );
-
- wp_register_webfont( $roboto );
-
- $expected = array(
- wp_webfonts()->get_font_slug( $source_serif_pro['font-family'] ) => array( $source_serif_pro ),
- wp_webfonts()->get_font_slug( $roboto['font-family'] ) => array( $roboto ),
- );
-
- wp_enqueue_webfonts(
- array(
- $source_serif_pro['font-family'],
- $roboto['font-family'],
- )
- );
-
- $this->assertEquals( $expected, wp_webfonts()->get_enqueued_webfonts() );
- $this->assertEquals( array(), wp_webfonts()->get_registered_webfonts() );
- }
-
- /**
- * Test wp_enqueue_font() enqueues a registered webfont.
- *
- * @covers wp_enqueue_webfont
- * @covers WP_Webfonts::enqueued_font
- * @covers WP_Webfonts::get_enqueued_fonts
- * @covers WP_Webfonts::get_registered_fonts
- */
- public function test_wp_enqueue_webfont_enqueues_registered_webfont() {
- $font_family_name = 'Source Serif Pro';
-
- $font = array(
- 'provider' => 'local',
- 'font-family' => $font_family_name,
- 'font-style' => 'normal',
- 'font-weight' => '200 900',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
- 'font-display' => 'fallback',
- );
-
- $expected = array(
- wp_webfonts()->get_font_slug( $font_family_name ) => array( $font ),
- );
-
- wp_register_webfont( $font );
- wp_enqueue_webfont( $font_family_name );
-
- $this->assertEquals( array(), wp_webfonts()->get_registered_webfonts() );
- $this->assertEquals( $expected, wp_webfonts()->get_enqueued_webfonts() );
- }
-
- /**
- * Test wp_enqueue_font() does not enqueue a webfont that was not registered.
- *
- * @covers wp_enqueue_webfont
- * @covers WP_Webfonts::enqueued_font
- * @covers WP_Webfonts::get_enqueued_fonts
- * @covers WP_Webfonts::get_registered_fonts
- *
- * @expectedIncorrectUsage WP_Webfonts::enqueue_webfont
- */
- public function test_wp_enqueue_webfont_does_not_enqueue_unregistered_webfont() {
- $font_family_name = 'Source Serif Pro';
-
- wp_enqueue_webfont( $font_family_name );
-
- $this->assertSame( array(), wp_webfonts()->get_registered_webfonts(), 'WP_Webfonts::get_registered_webfonts should return an empty array' );
- $this->assertSame( array(), wp_webfonts()->get_enqueued_webfonts(), 'WP_Webfonts::get_enqueued_webfonts should return an empty array' );
- }
-
- /**
- * @covers wp_register_webfont
- * @covers WP_Webfonts::register_provider
- * @covers WP_Webfonts::get_providers
- */
- public function test_get_providers() {
- wp_register_webfont_provider( 'test-provider', 'Test_Provider' );
- $this->assertEquals(
- array(
- 'local' => 'WP_Webfonts_Provider_Local',
- 'test-provider' => 'Test_Provider',
- ),
- wp_get_webfont_providers()
- );
- }
-
- /**
- * @dataProvider data_get_font_slug_when_cannot_determine_fontfamily
- * @covers WP_Webfonts::get_font_slug
- *
- * @expectedIncorrectUsage WP_Webfonts::get_font_slug
- */
- public function test_get_font_slug_when_cannot_determine_fontfamily( $to_convert ) {
- $this->assertFalse( wp_webfonts()->get_font_slug( $to_convert ) );
- }
-
- /**
- * Data provider.
- *
- * @return array[]
- */
- public function data_get_font_slug_when_cannot_determine_fontfamily() {
- return array(
- 'empty array' => array( array() ),
- 'array without a font-family key' => array(
- array(
- 'provider' => 'local',
- 'font-style' => 'normal',
- 'font-weight' => '200 900',
- 'font-display' => 'fallback',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
- ),
- ),
- "array with 'font family' key" => array(
- array( 'font family' => 'Source Serif Pro' ),
- ),
- "array with 'Font-Family' key" => array(
- array( 'Font-Family' => 'Source Serif Pro' ),
- ),
- "array with 'FontFamily' key" => array(
- array( 'FontFamily' => 'Source Serif Pro' ),
- ),
- );
- }
-
- /**
- * @dataProvider data_get_font_slug
- * @covers WP_Webfonts::get_font_slug
- */
- public function test_get_font_slug( $to_convert, $expected ) {
- $this->assertSame( $expected, wp_webfonts()->get_font_slug( $to_convert ) );
- }
-
- /**
- * Data provider.
- *
- * @return array[]
- */
- public function data_get_font_slug() {
- return array(
- "array using 'fontFamily' format" => array(
- 'to_convert' => array( 'fontFamily' => 'Source Serif Pro' ),
- 'expected' => 'source-serif-pro',
- ),
- "array using 'font-family' format" => array(
- 'to_convert' => array( 'font-family' => 'Source Serif Pro' ),
- 'expected' => 'source-serif-pro',
- ),
- 'string with font family name' => array(
- 'to_convert' => 'Source Serif Pro',
- 'expected' => 'source-serif-pro',
- ),
- 'empty string' => array(
- 'to_convert' => '',
- 'expected' => '',
- ),
- );
- }
-
- /**
- * @covers WP_Webfonts::validate_webfont
- */
- public function test_validate_webfont() {
- // Test empty array.
- $this->assertFalse( wp_webfonts()->validate_webfont( array() ) );
-
- $font = array(
- 'font-family' => 'Test Font 1',
- 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
- );
-
- // Test missing provider fallback to local.
- $this->assertEquals( 'local', wp_webfonts()->validate_webfont( $font )['provider'] );
-
- // Test missing font-weight fallback to 400.
- $this->assertEquals( '400', wp_webfonts()->validate_webfont( $font )['font-weight'] );
-
- // Test missing font-style fallback to normal.
- $this->assertEquals( 'normal', wp_webfonts()->validate_webfont( $font )['font-style'] );
-
- // Test missing font-display fallback to fallback.
- $this->assertEquals( 'fallback', wp_webfonts()->validate_webfont( $font )['font-display'] );
-
- // Test local font with missing "src".
- $this->assertFalse( wp_webfonts()->validate_webfont( array( 'font-family' => 'Test Font 2' ) ) );
-
- // Test valid src URL, without a protocol.
- $font['src'] = '//example.com/SourceSerif4Variable-Roman.ttf.woff2';
- $this->assertEquals( wp_webfonts()->validate_webfont( $font )['src'], $font['src'] );
-
- // Test font-weight.
- $font_weights = array( 100, '100', '100 900', 'normal' );
- foreach ( $font_weights as $value ) {
- $font['font-weight'] = $value;
- $this->assertEquals( wp_webfonts()->validate_webfont( $font )['font-weight'], $value );
- }
-
- // Test that invalid keys get removed from the font.
- $font['invalid-key'] = 'invalid';
- $this->assertArrayNotHasKey( 'invalid-key', wp_webfonts()->validate_webfont( $font ) );
- }
-
- /**
- * Test generate_and_enqueue_styles outputs only enqueued webfonts.
- *
- * @covers WP_Webfonts::generate_and_enqueue_styles
- */
- public function test_generate_and_enqueue_styles() {
- wp_register_webfonts(
- array(
- array(
- 'provider' => 'local',
- 'font-family' => 'Roboto',
- 'font-style' => 'normal',
- 'font-weight' => '400',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/roboto/Roboto-Regular.ttf',
- 'font-display' => 'fallback',
- ),
- array(
- 'provider' => 'local',
- 'font-family' => 'Source Serif Pro',
- 'font-style' => 'normal',
- 'font-weight' => '200 900',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
- 'font-display' => 'fallback',
- ),
- )
- );
-
- wp_enqueue_webfont( 'Source Serif Pro' );
-
- wp_webfonts()->generate_and_enqueue_styles();
-
- $expected = <<assertStringContainsString(
- $expected,
- get_echo( 'wp_print_styles' )
- );
- }
-
- /**
- * Test generate_and_enqueue_editor_styles outputs registered and enqueued webfonts.
- * Both are necessary so the editor correctly loads webfonts picked while in the editor.
- *
- * @covers WP_Webfonts::generate_and_enqueue_editor_styles
- */
- public function test_generate_and_enqueue_editor_styles() {
- wp_register_webfonts(
- array(
- array(
- 'provider' => 'local',
- 'font-family' => 'Roboto',
- 'font-style' => 'normal',
- 'font-weight' => '400',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/roboto/Roboto-Regular.ttf',
- 'font-display' => 'fallback',
- ),
- array(
- 'provider' => 'local',
- 'font-family' => 'Source Serif Pro',
- 'font-style' => 'normal',
- 'font-weight' => '200 900',
- 'font-stretch' => 'normal',
- 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
- 'font-display' => 'fallback',
- ),
- )
- );
-
- wp_enqueue_webfont( 'Source Serif Pro' );
-
- wp_webfonts()->generate_and_enqueue_editor_styles();
-
- $expected = <<assertStringContainsString(
- $expected,
- get_echo( 'wp_print_styles' )
- );
- }
-}
diff --git a/phpunit/fixtures/mock-provider.php b/phpunit/fixtures/mock-provider.php
new file mode 100644
index 00000000000000..152badb1ce266c
--- /dev/null
+++ b/phpunit/fixtures/mock-provider.php
@@ -0,0 +1,21 @@
+';
+
+ public function get_css() {
+ return $this->css;
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts-testcase.php b/phpunit/webfonts/wp-webfonts-testcase.php
new file mode 100644
index 00000000000000..495ef996a7e51b
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts-testcase.php
@@ -0,0 +1,137 @@
+old_wp_webfonts = $GLOBALS['wp_webfonts'];
+ $GLOBALS['wp_webfonts'] = null;
+ }
+
+ public function tear_down() {
+ $GLOBALS['wp_webfonts'] = $this->old_wp_webfonts;
+ parent::tear_down();
+ }
+
+ protected function set_up_mock( $method ) {
+ if ( is_string( $method ) ) {
+ $method = array( $method );
+ }
+ $mock = $this->getMockBuilder( WP_Webfonts::class )->setMethods( $method )->getMock();
+
+ // Set the global.
+ $GLOBALS['wp_webfonts'] = $mock;
+
+ return $mock;
+ }
+
+ protected function get_registered_handles() {
+ return array_keys( $this->get_registered() );
+ }
+
+ protected function get_registered() {
+ return wp_webfonts()->registered;
+ }
+
+ protected function get_variations( $font_family, $wp_webfonts = null ) {
+ if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) {
+ $wp_webfonts = wp_webfonts();
+ }
+ return $wp_webfonts->registered[ $font_family ]->deps;
+ }
+
+ protected function get_enqueued_handles() {
+ return wp_webfonts()->queue;
+ }
+
+ protected function get_queued_before_register( $wp_webfonts = null ) {
+ return $this->get_property_value( 'queued_before_register', WP_Dependencies::class, $wp_webfonts );
+ }
+
+ protected function get_property_value( $property_name, $class, $wp_webfonts = null ) {
+ $property = new ReflectionProperty( $class, $property_name );
+ $property->setAccessible( true );
+
+ if ( ! $wp_webfonts ) {
+ $wp_webfonts = wp_webfonts();
+ }
+ return $property->getValue( $wp_webfonts );
+ }
+
+ /**
+ * Sets up multiple font family and variation mocks.
+ *
+ * @param array $inputs Array of array( font-family => variations ) to setup.
+ * @param WP_Webfonts $wp_webfonts Instance of WP_Webfonts.
+ * @return stdClass[] Array of registered mocks.
+ */
+ protected function setup_registration_mocks( array $inputs, WP_Webfonts $wp_webfonts ) {
+ $mocks = array();
+
+ $build_mock = function( $handle ) use ( &$mocks, $wp_webfonts ) {
+ $mock = new stdClass();
+ $mock->deps = array();
+ // Add to each queue.
+ $mocks[ $handle ] = $mock;
+ $wp_webfonts->registered[ $handle ] = $mock;
+
+ return $mock;
+ };
+
+ foreach ( $inputs as $font_family => $variations ) {
+ $font_mock = $build_mock( $font_family );
+
+ foreach ( $variations as $variation_handle => $variation ) {
+ if ( ! is_string( $variation_handle ) ) {
+ $variation_handle = $variation;
+ }
+ $build_mock( $variation_handle );
+ $font_mock->deps[] = $variation_handle;
+ }
+ }
+
+ return $mocks;
+ }
+
+ /**
+ * Register one or more font-family and its variations to set up a test.
+ *
+ * @param string $font_family Font family to test.
+ * @param array $variations Variations.
+ * @param WP_Webfonts|null $wp_webfonts Optional. Instance of the WP_Webfonts.
+ */
+ protected function setup_register( $font_family, $variations, $wp_webfonts = null ) {
+ if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) {
+ $wp_webfonts = wp_webfonts();
+ }
+
+ $wp_webfonts->add( $font_family, false );
+
+ foreach ( $variations as $variation_handle => $variation ) {
+ if ( ! is_string( $variation_handle ) ) {
+ $variation_handle = '';
+ }
+ $wp_webfonts->add_variation( $font_family, $variation, $variation_handle );
+ }
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php
new file mode 100644
index 00000000000000..33de17c13580ff
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php
@@ -0,0 +1,513 @@
+ array(
+ 'expected' => 'lato-400-normal',
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2',
+ ),
+ ),
+
+ 'font-weight and font-style not defined; with variation handle' => array(
+ 'expected' => 'my-custom-handle',
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2',
+ ),
+ 'variation_handle' => 'my-custom-handle',
+ ),
+
+ 'font-weight defined; without variation handle' => array(
+ 'expected' => 'source-serif-pro-200-900-normal',
+ 'font_family_handle' => 'source-serif-pro',
+ 'variation' => array(
+ 'font-family' => 'Source Serif Pro',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ ),
+ ),
+
+ 'font-weight defined; with variation handle' => array(
+ 'expected' => 'my_custom_handle',
+ 'font_family_handle' => 'source-serif-pro',
+ 'variation' => array(
+ 'font-family' => 'Source Serif Pro',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ ),
+ 'variation_handle' => 'my_custom_handle',
+ ),
+
+ 'font-weight defined; without variation handle' => array(
+ 'expected' => 'source-serif-pro-200-900-normal',
+ 'font_family_handle' => 'source-serif-pro',
+ 'variation' => array(
+ 'font-family' => 'Source Serif Pro',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ ),
+ ),
+
+ 'font-weight defined; with variation handle' => array(
+ 'expected' => 'my_custom_handle',
+ 'font_family_handle' => 'source-serif-pro',
+ 'variation' => array(
+ 'font-family' => 'Source Serif Pro',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ ),
+ 'variation_handle' => 'my_custom_handle',
+ ),
+
+ 'font-weight defined; without variation handle' => array(
+ 'expected' => 'source-serif-pro-200-900-normal',
+ 'font_family_handle' => 'source-serif-pro',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Source Serif Pro',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ ),
+
+ 'more variation properties; with variation handle' => array(
+ 'expected' => 'my-custom-handle',
+ 'font_family_handle' => 'source-serif-pro',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Source Serif Pro',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'variation_handle' => 'my-custom-handle',
+ ),
+ );
+ }
+
+ /**
+ * Data provider for testing registration of variations where the font family is not defined.
+ *
+ * @return array
+ */
+ public function data_font_family_not_define_in_variation() {
+ return array(
+ 'empty string font family handle' => array(
+ 'font_family_handle' => '',
+ 'variation' => array(
+ 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2',
+ ),
+ 'expected_message' => 'Font family handle must be a non-empty string',
+ ),
+ 'empty string font family handle with font-family defined in variant' => array(
+ 'font_family_handle' => '',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Lato',
+ 'font-weight' => '200',
+ 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2',
+ ),
+ 'expected_message' => 'Font family handle must be a non-empty string',
+ ),
+ 'non string font family handle' => array(
+ 'font_family_handle' => 10,
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Source Serif Pro',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected_message' => 'Font family handle must be a non-empty string',
+ ),
+ );
+ }
+
+ /**
+ * Data provider for testing when the variation's handle can't be determine from the given input.
+ *
+ * @return array
+ */
+ public function data_unable_determine_variation_handle() {
+ return array(
+ 'integer values' => array(
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'font-weight' => 400,
+ 'font-style' => 0,
+ 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2',
+ ),
+ 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require',
+ ),
+ 'with empty string font-weight and font-style' => array(
+ 'font_family_handle' => 'merriweather',
+ 'variation' => array(
+ 'font-weight' => '',
+ 'font-style' => '',
+ 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2',
+ ),
+ 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require',
+ ),
+ 'integer font-weight, empty string font-style' => array(
+ 'font_family' => 'merriweather',
+ 'variation' => array(
+ 'font-weight' => 400,
+ 'font-style' => '',
+ 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2',
+ ),
+ 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require',
+ ),
+ 'empty string font-weight, integer font-style' => array(
+ 'font_family' => 'lato',
+ 'variation' => array(
+ 'font-weight' => '',
+ 'font-style' => 400,
+ 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2',
+ ),
+ 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require',
+ ),
+ );
+ }
+
+ /**
+ * Data provider for testing an invalid variation.
+ *
+ * @return array
+ */
+ public function data_invalid_variation() {
+ return array(
+ 'src: undefined' => array(
+ 'expected' => 'Webfont src must be a non-empty string or an array of strings.',
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Some font',
+ 'font-weight' => '200',
+ ),
+ ),
+ 'src: null' => array(
+ 'expected' => 'Webfont src must be a non-empty string or an array of strings.',
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Some font',
+ 'font-weight' => '200',
+ 'src' => null,
+ ),
+ ),
+ 'src: empty string' => array(
+ 'expected' => 'Webfont src must be a non-empty string or an array of strings.',
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Some font',
+ 'font-weight' => '200',
+ 'src' => '',
+ ),
+ ),
+ 'src: empty array' => array(
+ 'expected' => 'Webfont src must be a non-empty string or an array of strings.',
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-weight' => '200',
+ 'src' => array(),
+ ),
+ ),
+ 'src: array of an empty string' => array(
+ 'expected' => 'Each webfont src must be a non-empty string.',
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-weight' => '200',
+ 'src' => array( '' ),
+ ),
+ ),
+ 'src: array of a non-string' => array(
+ 'expected' => 'Each webfont src must be a non-empty string.',
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-weight' => '200',
+ 'src' => array( null ),
+ ),
+ ),
+ 'src: array with an empty string' => array(
+ 'expected' => 'Each webfont src must be a non-empty string.',
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-weight' => '200',
+ 'src' => array(
+ 'https://example.com/assets/fonts/merriweather.ttf.woff2',
+ '',
+ 'https://example.com/assets/fonts/lato.ttf.woff2',
+ ),
+ ),
+ ),
+ 'src: array with a non-string' => array(
+ 'expected' => 'Each webfont src must be a non-empty string.',
+ 'font_family_handle' => 'lato',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-weight' => '200',
+ 'src' => array(
+ 'https://example.com/assets/fonts/merriweather.ttf.woff2',
+ null,
+ 'https://example.com/assets/fonts/lato.ttf.woff2',
+ ),
+ ),
+ ),
+ 'provider does not exist' => array(
+ 'expected' => 'The provider class specified does not exist.',
+ 'font_family_handle' => 'merriweather',
+ 'variation' => array(
+ 'provider' => 'doesnotexit',
+ 'font-weight' => '200 900',
+ ),
+ ),
+ 'font-weight: null' => array(
+ 'expected' => 'Webfont font-weight must be a properly formatted string or integer.',
+ 'font_family_handle' => 'merriweather',
+ 'variation' => array(
+ 'font-weight' => null,
+ 'font-style' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2',
+ ),
+ ),
+ );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_deregister() {
+ return array(
+ 'one family family no variations' => array(
+ 'font_family' => 'lato',
+ 'inputs' => array(
+ 'lato' => array(),
+ ),
+ 'handles' => array( 'lato' ),
+ 'expected' => array(),
+ ),
+ 'one family family with 1 variation' => array(
+ 'font_family' => 'merriweather',
+ 'inputs' => array(
+ 'merriweather' => array(
+ 'merriweather-200-900-normal' => array(
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2',
+ ),
+ ),
+ ),
+ 'handles' => array( 'merriweather', 'merriweather-200-900-normal' ),
+ 'expected' => array(),
+ ),
+ 'font family with multiple variations' => array(
+ 'font_family' => 'Source Serif Pro',
+ 'inputs' => array(
+ 'Source Serif Pro' => array(
+ 'Source Serif Pro-300-normal' => array(
+ 'provider' => 'local',
+ 'font-style' => 'normal',
+ 'font-weight' => '300',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'Source Serif Pro-900-italic' => array(
+ 'provider' => 'local',
+ 'font-style' => 'italic',
+ 'font-weight' => '900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ ),
+ ),
+ 'handles' => array( 'Source Serif Pro', 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic' ),
+ 'expected' => array(),
+ ),
+ 'multiple font families without variations' => array(
+ 'font_family' => 'Source Serif Pro',
+ 'inputs' => array(
+ 'lato' => array(),
+ 'my-font' => array(),
+ 'Source Serif Pro' => array(),
+ 'some other font' => array(),
+ ),
+ 'handles' => array( 'lato', 'my-font', 'Source Serif Pro', 'some other font' ),
+ 'expected' => array( 'lato', 'my-font', 'some other font' ),
+ ),
+ 'multiple font families with variations' => array(
+ 'font_family' => 'my-font',
+ 'inputs' => array(
+ 'merriweather' => array(
+ 'merriweather-200-900-normal' => array(
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2',
+ ),
+ ),
+ 'Source Serif Pro' => array(
+ 'Source Serif Pro-300-normal' => array(
+ 'provider' => 'local',
+ 'font-style' => 'normal',
+ 'font-weight' => '300',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'Source Serif Pro-900-italic' => array(
+ 'provider' => 'local',
+ 'font-style' => 'italic',
+ 'font-weight' => '900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ ),
+ 'my-font' => array(
+ 'my-font-300-italic' => array(
+ 'font-weight' => '300',
+ 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2',
+ ),
+ ),
+ ),
+ 'handles' => array(
+ 'merriweather',
+ 'merriweather-200-900-normal',
+ 'Source Serif Pro',
+ 'Source Serif Pro-300-normal',
+ 'Source Serif Pro-900-italic',
+ 'my-font',
+ 'my-font-300-italic',
+ ),
+ 'expected' => array(
+ 'merriweather',
+ 'merriweather-200-900-normal',
+ 'Source Serif Pro',
+ 'Source Serif Pro-300-normal',
+ 'Source Serif Pro-900-italic',
+ ),
+ ),
+ );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_font_family_handles() {
+ return array(
+ 'single word handle' => array( 'lato' ),
+ 'multiple word handle' => array( 'source-sans-pro' ),
+ 'single word name' => array( 'Merriweather' ),
+ 'multiple word name' => array( 'My Cool Font' ),
+ );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_enqueue() {
+ return array(
+ '1 font-family' => array(
+ 'font_family' => 'lato',
+ 'expected_queue' => array( 'lato' ),
+ 'expected_queued_before_register' => array(
+ 'lato' => null,
+ ),
+ ),
+ '2 font families' => array(
+ 'font_family' => array( 'merriweather', 'my-font' ),
+ 'expected_queue' => array( 'merriweather', 'my-font' ),
+ 'expected_queued_before_register' => array(
+ 'merriweather' => null,
+ 'my-font' => null,
+ ),
+ ),
+ '3 font families' => array(
+ 'font_family' => array( 'merriweather', 'my-font', 'Source Serif Pro' ),
+ 'expected_queue' => array( 'merriweather', 'my-font', 'Source Serif Pro' ),
+ 'expected_queued_before_register' => array(
+ 'merriweather' => null,
+ 'my-font' => null,
+ 'Source Serif Pro' => null,
+ ),
+ ),
+ );
+ }
+
+ protected function get_data_registry() {
+ return array(
+ 'lato' => array(),
+ 'merriweather' => array(
+ 'merriweather-200-900-normal' => array(
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2',
+ ),
+ ),
+ 'Source Serif Pro' => array(
+ 'Source Serif Pro-300-normal' => array(
+ 'provider' => 'local',
+ 'font-style' => 'normal',
+ 'font-weight' => '300',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'Source Serif Pro-900-italic' => array(
+ 'provider' => 'local',
+ 'font-style' => 'italic',
+ 'font-weight' => '900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ ),
+ 'my-font' => array(
+ 'my-font-300-normal' => array(
+ 'font-weight' => '300',
+ 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2',
+ ),
+ 'my-font-300-italic' => array(
+ 'font-weight' => '300',
+ 'font-style' => 'italic',
+ 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2',
+ ),
+ 'my-font-900-normal' => array(
+ 'font-weight' => '900',
+ 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2',
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts/add-test.php b/phpunit/webfonts/wp-webfonts/add-test.php
new file mode 100644
index 00000000000000..91c79bf1542a6f
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts/add-test.php
@@ -0,0 +1,45 @@
+assertTrue( $wp_webfonts->add( $handle, false ), 'Registering a handle should return true' );
+ $this->assertCount( 1, $wp_webfonts->registered );
+ $this->assertArrayHasKey( $handle, $wp_webfonts->registered, 'Font family handle should be in the registry after registration' );
+
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_handles() {
+ return array(
+ 'name: multiple' => array( 'Source Serif Pro' ),
+ 'handle: multiple' => array( 'source-serif-pro' ),
+ 'name: single' => array( 'Merriweather' ),
+ 'handle: single' => array( 'merriweather' ),
+ 'handle: variation' => array( 'my-custom-font-200-900-normal' ),
+ );
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts/addData-test.php b/phpunit/webfonts/wp-webfonts/addData-test.php
new file mode 100644
index 00000000000000..d188cf75912278
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts/addData-test.php
@@ -0,0 +1,20 @@
+add( $font_family_handle, false );
+
+ $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle );
+ $this->assertSame( $expected, $variation_handle, 'Registering a variation should return its handle' );
+ $this->assertArrayHasKey( $variation_handle, $wp_webfonts->registered, 'Variation handle should be in the registry after registration' );
+ $this->assertSame( array( $expected ), $this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should be registered to font family' );
+ }
+
+ /**
+ * @dataProvider data_valid_variation
+ *
+ * @param string|bool $expected Expected results.
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ * @param string $variation_handle Optional. The variation's handle.
+ */
+ public function test_add_variation_when_already_registered( $expected, $font_family_handle, array $variation, $variation_handle = '' ) {
+ $wp_webfonts = new WP_Webfonts();
+ $wp_webfonts->add( $font_family_handle, false );
+
+ // Set up the test.
+ $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle );
+
+ // Run the test.
+ $variant_handle_on_reregister = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle );
+ $this->assertSame( $expected, $variant_handle_on_reregister, 'Variation should be registered to font family' );
+ $this->assertSame( $variation_handle, $variant_handle_on_reregister, 'Variation should return the previously registered variant handle' );
+ $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should only be registered once' );
+
+ $this->assertCount( 2, $wp_webfonts->registered );
+ $this->assertArrayHasKey( $variation_handle, $wp_webfonts->registered, 'Variation handle should be in the registry after registration' );
+ }
+
+ /**
+ * @dataProvider data_valid_variation
+ *
+ * @param string|bool $expected Expected results.
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ * @param string $variation_handle Optional. The variation's handle.
+ */
+ public function test_add_variation_registers_font_family( $expected, $font_family_handle, array $variation, $variation_handle = '' ) {
+ $wp_webfonts = new WP_Webfonts();
+
+ $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle );
+ $this->assertSame( $expected, $variation_handle, 'Variation should return its registered handle' );
+
+ // Extra checks to ensure both are registered.
+ $this->assertCount( 2, $wp_webfonts->registered );
+ $this->assertArrayHasKey( $font_family_handle, $wp_webfonts->registered, 'Font family handle should be in the registry after registration' );
+ $this->assertArrayHasKey( $variation_handle, $wp_webfonts->registered, 'Variation handle should be in the registry after registration' );
+ $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should be registered to the font family' );
+ }
+
+ /**
+ * @dataProvider data_font_family_not_define_in_variation
+ *
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ */
+ public function test_add_variation_should_not_register_font_family_or_variant( $font_family_handle, array $variation ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( 'Font family handle must be a non-empty string.' );
+
+ $wp_webfonts = new WP_Webfonts();
+ $wp_webfonts->add_variation( $font_family_handle, $variation );
+
+ $this->assertEmpty( $wp_webfonts->registered, 'Registered queue should be empty' );
+ $this->assertEmpty( $this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should not be registered to the font family' );
+ }
+
+ /**
+ * @dataProvider data_font_family_not_define_in_variation
+ * @dataProvider data_unable_determine_variation_handle
+ *
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ * @param string $expected_message Expected notice message.
+ */
+ public function test_add_variation_should_not_register_variation_when_font_family_not_defined( $font_family_handle, array $variation, $expected_message ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( $expected_message );
+
+ $wp_webfonts = new WP_Webfonts();
+ $this->assertNull( $wp_webfonts->add_variation( $font_family_handle, $variation ) );
+ }
+
+ /**
+ * @dataProvider data_unable_determine_variation_handle
+ *
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ */
+ public function test_add_variation_should_register_font_family_when_variant_fails_to_register( $font_family_handle, array $variation ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' );
+
+ $wp_webfonts = new WP_Webfonts();
+ $wp_webfonts->add_variation( $font_family_handle, $variation );
+
+ $this->assertCount( 1, $wp_webfonts->registered );
+ $this->assertArrayHasKey( $font_family_handle, $wp_webfonts->registered );
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts/allDeps-test.php b/phpunit/webfonts/wp-webfonts/allDeps-test.php
new file mode 100644
index 00000000000000..7babaf9f7e8997
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts/allDeps-test.php
@@ -0,0 +1,20 @@
+enqueue( $font_family );
+
+ $this->assertSame( $expected, $this->get_queued_before_register( $wp_webfonts ), 'Font family(ies) should be added to before registered queue' );
+ $this->assertEmpty( $this->queue, 'Font family(ies) should not be added to the enqueue queue when not registered' );
+ }
+
+ /**
+ * Integration test for enqueuing a font family and all of its variations.
+ *
+ * @dataProvider data_enqueue
+ *
+ * @param string|string[] $font_family Font family to test.
+ * @param array $expected Expected queue.
+ */
+ public function test_after_registration( $font_family, array $expected ) {
+ $wp_webfonts = new WP_Webfonts();
+ foreach ( $this->get_data_registry() as $handle => $variations ) {
+ $this->setup_register( $handle, $variations, $wp_webfonts );
+ }
+
+ $wp_webfonts->enqueue( $font_family );
+
+ $this->assertEmpty( $this->get_queued_before_register( $wp_webfonts ), '"queued_before_register" queue should be empty' );
+ $this->assertSame( $expected, $wp_webfonts->queue, 'Queue should contain the given font family(ies)' );
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts/getData-test.php b/phpunit/webfonts/wp-webfonts/getData-test.php
new file mode 100644
index 00000000000000..ff0922063d6895
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts/getData-test.php
@@ -0,0 +1,20 @@
+assertEmpty( $wp_webfonts->get_enqueued() );
+ }
+
+ /**
+ * Unit test for when font families are enqueued.
+ *
+ * @dataProvider data_enqueue
+ *
+ * @param string|string[] $not_used Not used.
+ * @param array $expected Expected queue.
+ */
+ public function test_when_font_families_are_enqueued( $not_used, array $expected ) {
+ $wp_webfonts = new WP_Webfonts();
+ $wp_webfonts->queue = $expected;
+
+ $this->assertSame( $expected, $wp_webfonts->get_enqueued() );
+ }
+
+ /**
+ * Full integration test that registers and enqueues the queue
+ * is properly wired for "get_enqueued()".
+ *
+ * @dataProvider data_enqueue
+ *
+ * @param string|string[] $font_family Font family to test.
+ * @param array $expected Expected queue.
+ */
+ public function test_integration( $font_family, array $expected ) {
+ $wp_webfonts = new WP_Webfonts();
+
+ // Register and enqueue.
+ foreach ( $this->get_data_registry() as $handle => $variations ) {
+ $this->setup_register( $handle, $variations, $wp_webfonts );
+ }
+ $wp_webfonts->enqueue( $font_family );
+
+ $this->assertSame( $expected, $wp_webfonts->get_enqueued() );
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts/getProviders-test.php b/phpunit/webfonts/wp-webfonts/getProviders-test.php
new file mode 100644
index 00000000000000..db33e34e276b31
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts/getProviders-test.php
@@ -0,0 +1,100 @@
+wp_webfonts = new WP_Webfonts();
+
+ $this->providers_property = new ReflectionProperty( WP_Webfonts::class, 'providers' );
+ $this->providers_property->setAccessible( true );
+ }
+
+ public function test_should_be_empty() {
+ $actual = $this->wp_webfonts->get_providers();
+ $this->assertIsArray( $actual, 'Should return an empty array' );
+ $this->assertEmpty( $actual, 'Should return an empty array when no providers are registered' );
+ }
+
+ /**
+ * @dataProvider data_get_providers
+ *
+ * @param array $providers Array of providers to test.
+ * @param array $expected Expected results.
+ */
+ public function test_get_providers( array $providers, array $expected ) {
+ $this->setup_providers( $providers );
+ $this->assertSame( $expected, $this->wp_webfonts->get_providers() );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_get_providers() {
+ $local = array(
+ 'local' => array(
+ 'class' => WP_Webfonts_Provider_Local::class,
+ 'fonts' => array(),
+ ),
+ );
+ $mock = array(
+ 'mock' => array(
+ 'class' => Mock_Provider::class,
+ 'fonts' => array(),
+ ),
+ );
+
+ return array(
+ 'local provider' => array(
+ 'providers' => array(
+ 'local' => WP_Webfonts_Provider_Local::class,
+ ),
+ 'expected' => $local,
+ ),
+ 'mock provider' => array(
+ 'providers' => array(
+ 'mock' => Mock_Provider::class,
+ ),
+ 'expected' => $mock,
+ ),
+ 'local and mock providers' => array(
+ 'providers' => array(
+ 'local' => WP_Webfonts_Provider_Local::class,
+ 'mock' => Mock_Provider::class,
+ ),
+ 'expected' => array_merge( $local, $mock ),
+ ),
+ );
+ }
+
+ private function setup_providers( array $providers ) {
+ $data = array();
+
+ foreach ( $providers as $provider_id => $class ) {
+ $data[ $provider_id ] = array(
+ 'class' => $class,
+ 'fonts' => array(),
+ );
+ }
+
+ $this->providers_property->setValue( $this->wp_webfonts, $data );
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts/getRegistered-test.php b/phpunit/webfonts/wp-webfonts/getRegistered-test.php
new file mode 100644
index 00000000000000..69e28e7885cd8b
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts/getRegistered-test.php
@@ -0,0 +1,65 @@
+assertEmpty( $wp_webfonts->get_registered() );
+ }
+
+ /**
+ * @dataProvider data_get_registered
+ */
+ public function test_get_registered( $inputs ) {
+ $wp_webfonts = new WP_Webfonts();
+ $mocks = $this->setup_registration_mocks( $inputs, $wp_webfonts );
+ $expected = array_keys( $mocks );
+
+ $this->assertSame( $expected, $wp_webfonts->get_registered() );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_get_registered() {
+ return array(
+ 'no variations' => array(
+ 'inputs' => array(
+ 'lato' => array(),
+ ),
+ ),
+ 'with 1 variation' => array(
+ 'inputs' => array(
+ 'Source Serif Pro' => array( 'variation-1' ),
+ ),
+ ),
+ 'with 2 variations' => array(
+ 'inputs' => array(
+ 'my-cool-font' => array( 'cool-1', 'cool-2' ),
+ ),
+ ),
+ 'when multiple font families registered' => array(
+ 'inputs' => array(
+ 'font-family-1' => array( 'variation-11', 'variation-12' ),
+ 'font-family-2' => array( 'variation-21', 'variation-22' ),
+ 'font-family-3' => array( 'variation-31', 'variation-32' ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts/getVariations-test.php b/phpunit/webfonts/wp-webfonts/getVariations-test.php
new file mode 100644
index 00000000000000..f73b51b369c767
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts/getVariations-test.php
@@ -0,0 +1,108 @@
+setup_registration_mocks( $inputs, $wp_webfonts );
+
+ $actual = $wp_webfonts->get_variations( $handle );
+ $this->assertIsArray( $actual, 'WP_Webfonts::get_variations() should return an array' );
+ $this->assertEmpty( $actual, 'WP_Webfonts::get_variations() should return an empty array' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_get_variations_when_font_family_not_registered() {
+ return array(
+ 'Integer font family' => array( 0 ),
+ 'Font family not registered' => array( 'font-not-registered' ),
+ 'Other font families registered' => array(
+ 'handle' => 'font-family-4',
+ 'inputs' => array(
+ 'font-family-1' => array( 'variation-1', 'variation-2' ),
+ 'font-family-2' => array( 'variation-21', 'variation-22' ),
+ 'font-family-3' => array( 'variation-31', 'variation-32' ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_get_variations
+ *
+ * @param string $font_family The font family to test.
+ * @param array $inputs Array of array( font-family => variations ).
+ * @param array $expected Expected result.
+ */
+ public function test_get_variations( $font_family, array $inputs, array $expected ) {
+ $wp_webfonts = new WP_Webfonts();
+ $this->setup_registration_mocks( $inputs, $wp_webfonts );
+
+ $actual = $wp_webfonts->get_variations( $font_family );
+ $this->assertIsArray( $actual, 'WP_Webfonts::get_variations() should return an array' );
+ $this->assertSame( $expected, $actual, 'WP_Webfonts::get_variations() should return the expected array of variations' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_get_variations() {
+ return array(
+ 'no variations' => array(
+ 'font_family' => 'lato',
+ 'inputs' => array(
+ 'lato' => array(),
+ ),
+ 'expected' => array(),
+ ),
+ 'with 1 variation' => array(
+ 'font_family' => 'Source Serif Pro',
+ 'inputs' => array(
+ 'Source Serif Pro' => array( 'variation-1' ),
+ ),
+ 'expected' => array( 'variation-1' ),
+ ),
+ 'with 2 variations' => array(
+ 'font_family' => 'my-cool-font',
+ 'inputs' => array(
+ 'my-cool-font' => array( 'cool-1', 'cool-2' ),
+ ),
+ 'expected' => array( 'cool-1', 'cool-2' ),
+ ),
+ 'when multiple font families registered' => array(
+ 'font_family' => 'font-family-2',
+ 'inputs' => array(
+ 'font-family-1' => array( 'variation-1', 'variation-2' ),
+ 'font-family-2' => array( 'variation-21', 'variation-22' ),
+ 'font-family-3' => array( 'variation-1', 'variation-2' ),
+ ),
+ 'expected' => array( 'variation-21', 'variation-22' ),
+ ),
+ );
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts/query-test.php b/phpunit/webfonts/wp-webfonts/query-test.php
new file mode 100644
index 00000000000000..b0eb23debe8be1
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts/query-test.php
@@ -0,0 +1,20 @@
+setup_registration_mocks( $inputs, $wp_webfonts );
+ // Test the before state, just to make sure.
+ $this->assertArrayHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should contain the font family before remove' );
+ $this->assertSame( $registered_handles, array_keys( $wp_webfonts->registered ), 'Font family and variations should be registered before remove' );
+
+ $wp_webfonts->remove_font_family( $font_family );
+
+ $this->assertArrayNotHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should not contain the font family' );
+ $this->assertSame( $expected, array_keys( $wp_webfonts->registered ), 'Registered queue should match after removing font family' );
+ }
+
+ /**
+ * @dataProvider data_deregister
+ *
+ * @param string $font_family Font family to test.
+ * @param array $inputs Font family(ies) and variations to pre-register.
+ * @param array $registered_handles Expected handles after registering.
+ * @param array $expected Array of expected handles.
+ */
+ public function test_when_not_registered( $font_family, array $inputs, array $registered_handles, array $expected ) {
+ $wp_webfonts = new WP_Webfonts();
+ unset( $inputs[ $font_family ] );
+ $this->setup_registration_mocks( $inputs, $wp_webfonts );
+
+ $wp_webfonts->remove_font_family( $font_family );
+
+ $this->assertArrayNotHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should not contain the font family' );
+ $this->assertSame( $expected, array_keys( $wp_webfonts->registered ), 'Registered queue should match after removing font family' );
+ }
+
+ /**
+ * Full integration test for removing a font family and all of its variation when font family is registered.
+ *
+ * @dataProvider data_deregister
+ *
+ * @param string $font_family Font family to test.
+ * @param array $inputs Font family(ies) and variations to pre-register.
+ * @param array $registered_handles Expected handles after registering.
+ * @param array $expected Array of expected handles.
+ */
+ public function test_integration_when_registered( $font_family, array $inputs, array $registered_handles, array $expected ) {
+ $wp_webfonts = new WP_Webfonts();
+ // Register all font families and their variations.
+ foreach ( $inputs as $handle => $variations ) {
+ $wp_webfonts->add( $handle, false );
+ foreach ( $variations as $variation_handle => $variation ) {
+ if ( ! is_string( $variation_handle ) ) {
+ $variation_handle = '';
+ }
+ $wp_webfonts->add_variation( $handle, $variation, $variation_handle );
+ }
+ }
+ // Test the before state, just to make sure.
+ $this->assertArrayHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should contain the font family before remove' );
+ $this->assertSame( $registered_handles, array_keys( $wp_webfonts->registered ), 'Font family and variations should be registered before remove' );
+
+ $wp_webfonts->remove_font_family( $font_family );
+
+ $this->assertArrayNotHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should not contain the font family' );
+ $this->assertSame( $expected, array_keys( $wp_webfonts->registered ), 'Registered queue should match after removing font family' );
+ }
+}
diff --git a/phpunit/webfonts/wp-webfonts/removeVariation-test.php b/phpunit/webfonts/wp-webfonts/removeVariation-test.php
new file mode 100644
index 00000000000000..f774dedb74e7f6
--- /dev/null
+++ b/phpunit/webfonts/wp-webfonts/removeVariation-test.php
@@ -0,0 +1,20 @@
+set_up_mock( 'remove_font_family' );
+ $mock->expects( $this->once() )
+ ->method( 'remove_font_family' )
+ ->with(
+ $this->identicalTo( $font_family_handle )
+ );
+
+ wp_deregister_font_family( $font_family_handle );
+ }
+
+ /**
+ * Integration test for enqueuing before registering a font family and all of its variations.
+ *
+ * @dataProvider data_font_family_handles
+ *
+ * @param string $font_family Font family to test.
+ */
+ public function test_deregister_before_registration( $font_family ) {
+ wp_deregister_font_family( $font_family );
+
+ $this->assertIsArray( $this->get_registered(), 'Registration queue should be an array' );
+ $this->assertEmpty( $this->get_registered(), 'Registration queue should be empty after deregistering' );
+ }
+
+ /**
+ * Integration test for deregistering a font family and all of its variations.
+ *
+ * @dataProvider data_deregister
+ *
+ * @param string $font_family Font family to test.
+ * @param array $inputs Font family(ies) and variations to pre-register.
+ * @param array $registered_handles Expected handles after registering.
+ * @param array $expected Array of expected handles.
+ */
+ public function test_deregister_after_registration( $font_family, array $inputs, array $registered_handles, array $expected ) {
+ foreach ( $inputs as $handle => $variations ) {
+ $this->setup_register( $handle, $variations );
+ }
+ // Test the before state, just to make sure.
+ $this->assertSame( $registered_handles, $this->get_registered_handles(), 'Font family and variations should be registered before deregistering' );
+
+ wp_deregister_font_family( $font_family );
+
+ // Test after deregistering.
+ $this->assertIsArray( $this->get_registered_handles(), 'Registration queue should be an array' );
+ $this->assertSame( $expected, $this->get_registered_handles(), 'Registration queue should match after deregistering' );
+ }
+}
diff --git a/phpunit/webfonts/wpEnqueueWebfont-test.php b/phpunit/webfonts/wpEnqueueWebfont-test.php
new file mode 100644
index 00000000000000..323fe51c5e8a68
--- /dev/null
+++ b/phpunit/webfonts/wpEnqueueWebfont-test.php
@@ -0,0 +1,69 @@
+set_up_mock( 'enqueue' );
+ $mock->expects( $this->once() )
+ ->method( 'enqueue' )
+ ->with(
+ $this->identicalTo( $font_family )
+ );
+
+ wp_enqueue_webfont( $font_family );
+ }
+
+ /**
+ * Integration test for enqueuing a font family and all of its variations.
+ *
+ * @dataProvider data_enqueue
+ *
+ * @param string|string[] $font_family Font family to test.
+ * @param array $expected Expected queue.
+ */
+ public function test_enqueue_after_registration( $font_family, array $expected ) {
+ foreach ( $this->get_data_registry() as $handle => $variations ) {
+ $this->setup_register( $handle, $variations );
+ }
+
+ wp_enqueue_webfont( $font_family );
+ $this->assertEmpty( $this->get_queued_before_register(), '"queued_before_register" queue should be empty' );
+ $this->assertSame( $expected, $this->get_enqueued_handles(), 'Queue should contain the given font family(ies)' );
+ }
+
+ /**
+ * Integration test for enqueuing before registering a font family and all of its variations.
+ *
+ * @dataProvider data_enqueue
+ *
+ * @param string|string[] $font_family Font family to test.
+ * @param array $not_used Not used.
+ * @param array $expected Expected "queued_before_register" queue.
+ */
+ public function test_enqueue_before_registration( $font_family, array $not_used, array $expected ) {
+ wp_enqueue_webfont( $font_family );
+
+ $this->assertSame( $expected, $this->get_queued_before_register(), '"queued_before_register" queue should contain the given font family(ies)' );
+ $this->assertEmpty( $this->get_enqueued_handles(), 'Queue should be empty' );
+ }
+}
diff --git a/phpunit/webfonts/wpRegisterFontFamily-test.php b/phpunit/webfonts/wpRegisterFontFamily-test.php
new file mode 100644
index 00000000000000..6064fbac37c761
--- /dev/null
+++ b/phpunit/webfonts/wpRegisterFontFamily-test.php
@@ -0,0 +1,133 @@
+set_up_mock( 'add' );
+ $mock->expects( $this->once() )
+ ->method( 'add' )
+ ->with(
+ $this->identicalTo( $expected_handle ),
+ $this->identicalTo( false )
+ )
+ ->will( $this->returnValue( $expected_handle ) );
+
+ $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family should return true after registering' );
+ }
+
+ /**
+ * Integration test for registering a font family.
+ *
+ * @dataProvider data_font_family
+ *
+ * @covers WP_Webfonts::add
+ *
+ * @param string $font_family Font family to test.
+ * @param string $expected_handle Expected registered handle.
+ */
+ public function test_register( $font_family, $expected_handle ) {
+ $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family should return true after registering' );
+ $this->assertSame( array( $expected_handle ), $this->get_registered_handles(), 'After registering, the registry should contain the font family handle' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_font_family() {
+ return array(
+ 'single word name' => array(
+ 'font_family' => 'Lato',
+ 'expected_handle' => 'lato',
+ ),
+ 'multiple word name' => array(
+ 'font_family' => 'Source Sans Pro',
+ 'expected_handle' => 'source-sans-pro',
+ ),
+ 'handle' => array(
+ 'font_family' => 'source-serif-pro',
+ 'expected_handle' => 'source-serif-pro',
+ ),
+ );
+ }
+
+ /**
+ * Unit test for registering a font-family that mocks WP_Webfonts.
+ *
+ * @dataProvider data_invalid_font_family
+ *
+ * @param string $invalid_input Invalid input to test.
+ */
+ public function test_unit_register_fails( $invalid_input ) {
+ $mock = $this->set_up_mock( 'add' );
+ $mock->expects( $this->never() )->method( 'add' );
+
+ $this->assertNull( wp_register_font_family( $invalid_input ), 'Registering an invalid input should return null' );
+ }
+
+ /**
+ * Integration test for registering a font family.
+ *
+ * @dataProvider data_invalid_font_family
+ *
+ * @covers WP_Webfonts::add
+ *
+ * @param string $invalid_input Invalid input to test.
+ */
+ public function test_register_fails( $invalid_input ) {
+ $this->assertNull( wp_register_font_family( $invalid_input ), 'Registering an invalid input should return null' );
+ $this->assertEmpty( $this->get_registered(), 'Invalid input should not register' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_invalid_font_family() {
+ return array(
+ 'non-string' => array( null ),
+ 'empty string' => array( '' ),
+ );
+ }
+
+ /**
+ * Integration test for attempting to re-register a font family.
+ *
+ * @dataProvider data_font_family
+ *
+ * @covers WP_Webfonts::add
+ *
+ * @param string $font_family Font family to test.
+ * @param string $expected_handle Expected registered handle.
+ */
+ public function test_re_register( $font_family, $expected_handle ) {
+ // Register the font family.
+ wp_register_font_family( $font_family );
+
+ // Attempt to re-register it.
+ $this->assertNull( wp_register_font_family( $font_family ), 'Font family should return true after registering' );
+ $this->assertSame( array( $expected_handle ), $this->get_registered_handles(), 'The font family should only be registered once' );
+ }
+}
diff --git a/phpunit/webfonts/wpRegisterWebfont-test.php b/phpunit/webfonts/wpRegisterWebfont-test.php
new file mode 100644
index 00000000000000..c6445813ef1403
--- /dev/null
+++ b/phpunit/webfonts/wpRegisterWebfont-test.php
@@ -0,0 +1,281 @@
+add( $handle, false );
+ }
+
+ /**
+ * Unit test for registering a variation with a variation handle given.
+ *
+ * @dataProvider data_register
+ *
+ * @param string $font_family_handle Font family for this variation.
+ * @param array $variation Web font to test.
+ * @param array $expected Expected results.
+ */
+ public function test_register_with_mock_when_handle_given( $font_family_handle, array $variation, $expected ) {
+ $mock = $this->set_up_mock( 'add_variation' );
+ $variation_handle = $expected[1];
+
+ $mock->expects( $this->once() )
+ ->method( 'add_variation' )
+ ->with(
+ $this->identicalTo( $font_family_handle ),
+ $this->identicalTo( $variation ),
+ $this->identicalTo( $variation_handle )
+ )
+ ->will( $this->returnValue( $font_family_handle ) );
+
+ $this->assertSame( $font_family_handle, wp_register_webfont( $variation, $font_family_handle, $variation_handle ) );
+ }
+
+ /**
+ * Integration test for registering a variation when the font family was previously registered.
+ *
+ * @dataProvider data_register
+ *
+ * @covers WP_Webfonts::add_variation
+ *
+ * @param string $font_family_handle Font family for this variation.
+ * @param array $variation Web font to test.
+ * @param array $expected Expected results.
+ */
+ public function test_register( $font_family_handle, array $variation, $expected ) {
+ $this->setup_font_family( $font_family_handle );
+
+ $this->assertSame( $font_family_handle, wp_register_webfont( $variation, $font_family_handle ), 'Registering should return the font family handle' );
+ $this->assertSame( $expected, $this->get_registered_handles(), 'Registry should contain the font family and variant handles' );
+ }
+
+ /**
+ * Integration test for testing the font family is registered during the variation registration process.
+ *
+ * @dataProvider data_register_with_deprecated_structure
+ *
+ * @covers WP_Webfonts::add
+ * @covers WP_Webfonts::add_variation
+ *
+ * @param array $variation Web font to test.
+ * @param array $expected Expected results.
+ */
+ public function test_registers_font_family( array $variation, $expected ) {
+ $font_family_handle = $expected[0];
+
+ wp_register_webfont( $variation );
+ $this->assertContains( $font_family_handle, $this->get_registered_handles() );
+ }
+
+ /**
+ * Integration test to ensure registration does not automatically enqueue.
+ *
+ * @dataProvider data_register
+ *
+ * @covers WP_Webfonts::add_variation
+ *
+ * @param string $font_family_handle Font family handle.
+ * @param array $variation Variation.
+ */
+ public function test_does_not_enqueue_when_registering( $font_family_handle, array $variation ) {
+ $this->setup_font_family( $font_family_handle );
+ wp_register_webfont( $variation, $font_family_handle );
+
+ $this->assertEmpty( $this->get_enqueued_handles() );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_register() {
+ return array(
+ 'Source Serif Pro' => array(
+ 'font_family' => 'source-serif-pro',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected' => array(
+ 'source-serif-pro',
+ 'source-serif-pro-200-900-normal',
+ ),
+ ),
+ 'Merriweather' => array(
+ 'font_family' => 'merriweather',
+ 'variation' => array(
+ 'font-style' => 'italic',
+ 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2',
+ ),
+ 'expected' => array(
+ 'merriweather',
+ 'merriweather-400-italic',
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_register_with_deprecated_structure
+ *
+ * @covers WP_Webfonts::add_variation
+ *
+ * @param array $variation Web font to test.
+ * @param array $expected Expected results.
+ */
+ public function test_registers_with_deprecated_structure(
+ array $variation, $expected
+ ) {
+ $font_family_handle = $expected[0];
+ $this->setup_font_family( $font_family_handle );
+
+ $this->assertSame( $font_family_handle, wp_register_webfont( $variation ), 'Registering should return the registered font family handle' );
+ $this->assertSame( $expected, $this->get_registered_handles(), 'Registry should contain the font family and variant handles' );
+ }
+
+ /**
+ * @dataProvider data_register_with_deprecated_structure
+ *
+ * @covers WP_Webfonts::add_variation
+ *
+ * @param array $variation Web font to test.
+ * @param array $expected Expected results.
+ */
+ public function test_registers_font_family_with_deprecated_structure(
+ array $variation, $expected
+ ) {
+ $font_family_handle = $expected[0];
+
+ wp_register_webfont( $variation );
+ $this->assertContains( $font_family_handle, $this->get_registered_handles() );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_register_with_deprecated_structure() {
+ return array(
+ 'font-family as name' => array(
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Source Serif Pro',
+ 'font-weight' => '200 900',
+ 'src' => 'https://example.com/assets/fonts/font.ttf.woff2',
+ ),
+ 'expected' => array(
+ 'source-serif-pro',
+ 'source-serif-pro-200-900-normal',
+ ),
+ ),
+ 'font-family as handle/slug' => array(
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'my-font-family',
+ 'font-style' => 'italic',
+ 'src' => 'https://example.com/assets/fonts/font.ttf.woff2',
+ ),
+ 'expected' => array(
+ 'my-font-family',
+ 'my-font-family-400-italic',
+ ),
+ ),
+ );
+ }
+
+ /**
+ * Integration test for testing when font family registration fails.
+ *
+ * @dataProvider data_invalid_font_family
+ *
+ * @param string $font_family_handle Font family for this variation.
+ * @param array $variation Web font to test.
+ * @param string $expected_meessage Expected notice message.
+ */
+ public function test_font_family_registration_fails( $font_family_handle, array $variation, $expected_meessage ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( $expected_meessage );
+
+ $this->assertNull( wp_register_webfont( $variation, $font_family_handle ), 'Should return null when invalid font family given' );
+ $this->assertEmpty( $this->get_registered_handles(), 'Font family and variation should not be registered' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_invalid_font_family() {
+ return array(
+ 'non-string' => array(
+ 'font_family_handle' => null,
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected_message' => 'Font family not found.',
+ 'font-family' => null,
+ ),
+ 'empty string' => array(
+ 'font_family_handle' => '',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected_message' => 'Font family not found.',
+ ),
+ 'non-string in deprecated structure' => array(
+ 'font_family_handle' => '',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => null,
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected_message' => 'Font family not defined in the variation.',
+ ),
+ 'empty string in deprecated structure' => array(
+ 'font_family_handle' => '',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => '',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected_message' => 'Font family not defined in the variation.',
+ ),
+ );
+ }
+}
diff --git a/phpunit/webfonts/wpRegisterWebfontVariation-test.php b/phpunit/webfonts/wpRegisterWebfontVariation-test.php
new file mode 100644
index 00000000000000..d2445f86fe5f42
--- /dev/null
+++ b/phpunit/webfonts/wpRegisterWebfontVariation-test.php
@@ -0,0 +1,133 @@
+add( $font_family_handle, false );
+
+ $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle );
+ $this->assertSame( $expected, $variation_handle, 'Variation should return handle' );
+ $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should be registered to font family' );
+ }
+
+ /**
+ * @dataProvider data_valid_variation
+ *
+ * @param string|bool $expected Expected results.
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ * @param string $variation_handle Optional. The variation's handle.
+ */
+ public function test_variation_already_registered( $expected, $font_family_handle, array $variation, $variation_handle = '' ) {
+ wp_webfonts()->add( $font_family_handle, false );
+
+ // Set up the test.
+ $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle );
+
+ // Run the test.
+ $variant_handle_on_reregister = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle );
+ $this->assertSame( $expected, $variant_handle_on_reregister, 'Variation should be registered to font family' );
+ $this->assertSame( $variation_handle, $variant_handle_on_reregister, 'Variation should return the previously registered variant handle' );
+ $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should only be registered once' );
+ $expected = array( $font_family_handle, $variation_handle );
+ $this->assertSameSets( $expected, $this->get_registered_handles(), 'Register queue should contain the font family and its one variant' );
+ }
+
+ /**
+ * @dataProvider data_valid_variation
+ *
+ * @param string|bool $expected Expected results.
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ * @param string $variation_handle Optional. The variation's handle.
+ */
+ public function test_register_font_family_and_variation( $expected, $font_family_handle, array $variation, $variation_handle = '' ) {
+ $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle );
+ $this->assertSame( $expected, $variation_handle, 'Variation should return its registered handle' );
+
+ // Extra checks to ensure both are registered.
+ $expected = array( $font_family_handle, $variation_handle );
+ $this->assertSame( $expected, wp_webfonts()->get_registered(), 'Font family and variation should be registered' );
+ $this->assertSame( array( $variation_handle ), wp_webfonts()->get_variations( $font_family_handle ), 'Variation should be registered to the font family' );
+ }
+
+ /**
+ * @dataProvider data_font_family_not_define_in_variation
+ *
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ */
+ public function test_should_not_register_font_family_or_variant( $font_family_handle, array $variation ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( 'Font family handle must be a non-empty string.' );
+
+ wp_register_webfont_variation( $font_family_handle, $variation );
+ $this->assertEmpty( wp_webfonts()->get_registered(), 'Registered queue should be empty' );
+ $this->assertEmpty( wp_webfonts()->get_variations( $font_family_handle ), 'Variation should not be registered to the font family' );
+ }
+
+ /**
+ * @dataProvider data_font_family_not_define_in_variation
+ * @dataProvider data_unable_determine_variation_handle
+ *
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ * @param string $expected_message Expected notice message.
+ */
+ public function test_should_not_register_variation_when_font_family_not_defined( $font_family_handle, array $variation, $expected_message ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( $expected_message );
+
+ $this->assertNull( wp_register_webfont_variation( $font_family_handle, $variation ) );
+ }
+
+ /**
+ * @dataProvider data_unable_determine_variation_handle
+ *
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ */
+ public function test_should_register_font_family_when_variant_fails_to_register( $font_family_handle, array $variation ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' );
+
+ wp_register_webfont_variation( $font_family_handle, $variation );
+ $expected = $font_family_handle;
+ $this->assertContains( $expected, wp_webfonts()->get_registered() );
+ }
+
+ /**
+ * @dataProvider data_invalid_variation
+ *
+ * @param string $expected_message Expected notice message.
+ * @param string $font_family_handle The font family's handle for this variation.
+ * @param array $variation An array of variation properties to add.
+ */
+ public function test_should_not_register_when_variation_fails_validation( $expected_message, $font_family_handle, array $variation ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( $expected_message );
+
+ $this->assertNull( wp_register_webfont_variation( $font_family_handle, $variation ) );
+ }
+}
diff --git a/phpunit/webfonts/wpRegisterWebfonts-test.php b/phpunit/webfonts/wpRegisterWebfonts-test.php
new file mode 100644
index 00000000000000..5a85e746b09217
--- /dev/null
+++ b/phpunit/webfonts/wpRegisterWebfonts-test.php
@@ -0,0 +1,147 @@
+assertSame( $expected['wp_register_webfonts'], wp_register_webfonts( $webfonts ), 'Font family handle(s) should be returned' );
+ $this->assertSame( $expected['get_registered'], $this->get_registered_handles(), 'Web fonts should match registered queue' );
+ }
+
+ /**
+ * @dataProvider data_deprecated_structure
+ *
+ * @expectedIncorrectUsage wp_register_webfonts
+ *
+ * @param array $webfonts Array of webfonts to test.
+ * @param array $expected Expected results.
+ */
+ public function test_register_with_deprecated_structure( array $webfonts, array $expected ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( $expected['message'] );
+
+ $this->assertSame( $expected['wp_register_webfonts'], wp_register_webfonts( $webfonts ), 'Font family handle(s) should be returned' );
+ $this->assertSame( $expected['get_registered'], $this->get_registered_handles(), 'Web fonts should match registered queue' );
+ }
+
+ /**
+ * @dataProvider data_webfonts
+ *
+ * @param array $webfonts Array of webfonts to test.
+ */
+ public function test_web_fonts_do_not_enqueue_on_registration( array $webfonts ) {
+ wp_register_webfonts( $webfonts );
+ $this->assertEmpty( $this->get_enqueued_handles() );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_webfonts() {
+ return array(
+ 'font family keyed with slug' => array(
+ 'webfonts' => array(
+ 'source-serif-pro' => array(
+ array(
+ 'provider' => 'local',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ ),
+ ),
+ 'expected' => array(
+ 'wp_register_webfonts' => array( 'source-serif-pro' ),
+ 'get_registered' => array(
+ 'source-serif-pro',
+ 'source-serif-pro-200-900-normal',
+ ),
+ ),
+ ),
+ 'font family keyed with name' => array(
+ 'webfonts' => array(
+ 'Source Serif Pro' => array(
+ array(
+ 'provider' => 'local',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ array(
+ 'provider' => 'local',
+ 'font-style' => 'italic',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ ),
+ ),
+ 'expected' => array(
+ 'wp_register_webfonts' => array( 'source-serif-pro' ),
+ 'get_registered' => array(
+ 'source-serif-pro',
+ 'source-serif-pro-200-900-normal',
+ 'source-serif-pro-200-900-italic',
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_deprecated_structure() {
+ return array(
+ 'font family not keyed' => array(
+ 'webfonts' => array(
+ array(
+ array(
+ 'provider' => 'local',
+ 'font-family' => 'Source Serif Pro',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ ),
+ ),
+ 'expected' => array(
+ 'wp_register_webfonts' => array(),
+ 'get_registered' => array(),
+ 'message' => 'Font family not found.',
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpunit/webfonts/wpWebfonts-test.php b/phpunit/webfonts/wpWebfonts-test.php
new file mode 100644
index 00000000000000..f12fa060a0f4ef
--- /dev/null
+++ b/phpunit/webfonts/wpWebfonts-test.php
@@ -0,0 +1,38 @@
+assertInstanceOf( WP_Webfonts::class, wp_webfonts() );
+ }
+
+ public function test_global_set() {
+ global $wp_webfonts;
+ $this->assertNull( $wp_webfonts );
+ $instance = wp_webfonts();
+ $this->assertInstanceOf( WP_Webfonts::class, $wp_webfonts );
+ $this->assertSame( $instance, $wp_webfonts );
+ }
+
+ public function test_local_provider_is_automatically_registered() {
+ $expected = array(
+ 'local' => array(
+ 'class' => 'WP_Webfonts_Provider_Local',
+ 'fonts' => array(),
+ ),
+ );
+ $this->assertSame( $expected, wp_webfonts()->get_providers() );
+ }
+}
diff --git a/phpunit/class-wp-webfonts-local-provider-test.php b/phpunit/webfonts/wpWebfontsProviderLocal-test.php
similarity index 95%
rename from phpunit/class-wp-webfonts-local-provider-test.php
rename to phpunit/webfonts/wpWebfontsProviderLocal-test.php
index c9ab3e2cd8b958..8a87c03a8e3ebd 100644
--- a/phpunit/class-wp-webfonts-local-provider-test.php
+++ b/phpunit/webfonts/wpWebfontsProviderLocal-test.php
@@ -2,9 +2,9 @@
/**
* @group webfonts
- * @covers WP_WebfontsLocal_Provider
+ * @covers WP_Webfonts_Provider_Local
*/
-class WP_Webfonts_Provider_Local_Test extends WP_UnitTestCase {
+class Tests_Webfonts_WpWebfontsProviderLocal extends WP_UnitTestCase {
private $provider;
private $theme_root;
private $orig_theme_dir;
@@ -17,27 +17,6 @@ public function set_up() {
$this->set_up_theme();
}
- /**
- * Local `src` paths to need to be relative to the theme. This method sets up the
- * `wp-content/themes/` directory to ensure consistency when running tests.
- */
- private function set_up_theme() {
- $this->theme_root = realpath( DIR_TESTDATA . '/themedir1' );
- $this->orig_theme_dir = $GLOBALS['wp_theme_directories'];
- $GLOBALS['wp_theme_directories'] = array( $this->theme_root );
-
- $theme_root_callback = function () {
- return $this->theme_root;
- };
- add_filter( 'theme_root', $theme_root_callback );
- add_filter( 'stylesheet_root', $theme_root_callback );
- add_filter( 'template_root', $theme_root_callback );
-
- // Clear caches.
- wp_clean_themes_cache();
- unset( $GLOBALS['wp_themes'] );
- }
-
function tear_down() {
// Restore the original theme directory setup.
$GLOBALS['wp_theme_directories'] = $this->orig_theme_dir;
@@ -109,7 +88,10 @@ public function data_get_css() {
),
),
'expected' => <<
@font-face{font-family:"Open Sans";font-style:italic;font-weight:bold;src:local("Open Sans"), url('http://example.org/assets/fonts/OpenSans-Italic-VariableFont_wdth,wght.ttf') format('truetype');}
+
+
CSS
,
),
@@ -133,13 +115,37 @@ public function data_get_css() {
),
),
'expected' => <<
@font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:200 900;font-stretch:normal;src:local("Source Serif Pro"), url('http://example.org/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2') format('woff2');}@font-face{font-family:"Source Serif Pro";font-style:italic;font-weight:200 900;font-stretch:normal;src:local("Source Serif Pro"), url('http://example.org/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2') format('woff2');}
+
+
CSS
,
),
);
}
+ /**
+ * Local `src` paths to need to be relative to the theme. This method sets up the
+ * `wp-content/themes/` directory to ensure consistency when running tests.
+ */
+ private function set_up_theme() {
+ $this->theme_root = realpath( DIR_TESTDATA . '/themedir1' );
+ $this->orig_theme_dir = $GLOBALS['wp_theme_directories'];
+ $GLOBALS['wp_theme_directories'] = array( $this->theme_root );
+
+ $theme_root_callback = function () {
+ return $this->theme_root;
+ };
+ add_filter( 'theme_root', $theme_root_callback );
+ add_filter( 'stylesheet_root', $theme_root_callback );
+ add_filter( 'template_root', $theme_root_callback );
+
+ // Clear caches.
+ wp_clean_themes_cache();
+ unset( $GLOBALS['wp_themes'] );
+ }
+
private function get_webfonts_property() {
$property = new ReflectionProperty( $this->provider, 'webfonts' );
$property->setAccessible( true );
diff --git a/phpunit/webfonts/wpWebfontsUtils-test.php b/phpunit/webfonts/wpWebfontsUtils-test.php
new file mode 100644
index 00000000000000..ce626b9bb60f89
--- /dev/null
+++ b/phpunit/webfonts/wpWebfontsUtils-test.php
@@ -0,0 +1,366 @@
+assertSame( $expected, WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ) );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_convert_font_family_into_handle() {
+ return array(
+ 'font family single word name' => array(
+ 'font_family' => 'Merriweather',
+ 'expected' => 'merriweather',
+ ),
+ 'font family multiword name' => array(
+ 'font_family' => 'Source Sans Pro',
+ 'expected' => 'source-sans-pro',
+ ),
+ 'font family handle delimited by hyphens' => array(
+ 'font_family' => 'source-serif-pro',
+ 'expected' => 'source-serif-pro',
+ ),
+ 'font family handle delimited by underscore' => array(
+ 'font_family' => 'source_serif_pro',
+ 'expected' => 'source_serif_pro',
+ ),
+ 'font family handle delimited by hyphens and underscore' => array(
+ 'font_family' => 'my-custom_font_family',
+ 'expected' => 'my-custom_font_family',
+ ),
+ 'font family handle delimited mixture' => array(
+ 'font_family' => 'My custom_font-family',
+ 'expected' => 'my-custom_font-family',
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_convert_font_family_into_handle_with_invalid_input
+ *
+ * @covers WP_Webfonts_Utils::convert_font_family_into_handle
+ *
+ * @param mixed $invalid_input Invalid input.
+ */
+ public function test_convert_font_family_into_handle_with_invalid_input( $invalid_input ) {
+ $this->assertNull( WP_Webfonts_Utils::convert_font_family_into_handle( $invalid_input ) );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_convert_font_family_into_handle_with_invalid_input() {
+ return array(
+ 'empty string' => array( '' ),
+ 'integer' => array( 10 ),
+ 'font family wrapped in an array' => array( array( 'source-serif-pro' ) ),
+ );
+ }
+
+ /**
+ * @dataProvider data_convert_variation_into_handle
+ *
+ * @covers WP_Webfonts_Utils::convert_variation_into_handle
+ *
+ * @param string $font_family Font family to test.
+ * @param array $variation Variation to test.
+ * @param string $expected Expected results.
+ */
+ public function test_convert_variation_into_handlee( $font_family, array $variation, $expected ) {
+ $this->assertSame( $expected, WP_Webfonts_Utils::convert_variation_into_handle( $font_family, $variation ) );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_convert_variation_into_handle() {
+ return array(
+ 'with only font-weight' => array(
+ 'font_family' => 'merriweather',
+ 'variation' => array(
+ 'font-weight' => '400',
+ ),
+ 'expected' => 'merriweather-400',
+ ),
+ 'with no font-style' => array(
+ 'font_family' => 'source-sans-pro',
+ 'variation' => array(
+ 'font-weight' => '200 900',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'provider' => 'local',
+ ),
+ 'expected' => 'source-sans-pro-200-900',
+ ),
+ 'with font family name and full variant' => array(
+ 'font_family' => 'source-sans-pro',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Source Serif Pro',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected' => 'source-sans-pro-200-900-normal',
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_convert_variation_into_handle_with_invalid_variation
+ *
+ * @covers WP_Webfonts_Utils::convert_variation_into_handle
+ *
+ * @param string $font_family Font family to test.
+ * @param array $invalid_input Variation to test.
+ */
+ public function tests_convert_variation_into_handle_with_invalid_variation( $font_family, $invalid_input ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' );
+
+ $this->assertNull( WP_Webfonts_Utils::convert_variation_into_handle( $font_family, $invalid_input ) );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_convert_variation_into_handle_with_invalid_variation() {
+ return array(
+ 'with no font-weight or font-style' => array(
+ 'font_family' => 'merriweather',
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ ),
+ 'with non-string font-weight' => array(
+ 'font_family' => 'merriweather',
+ 'variation' => array(
+ 'font-weight' => 400,
+ ),
+ ),
+ 'with non-string font-style' => array(
+ 'font_family' => 'merriweather',
+ 'variation' => array(
+ 'font-style' => 0,
+ ),
+ ),
+ 'with empty string font-weight' => array(
+ 'font_family' => 'merriweather',
+ 'variation' => array(
+ 'font-weight' => '',
+ ),
+ ),
+ 'with empty string font-style' => array(
+ 'font_family' => 'merriweather',
+ 'variation' => array(
+ 'font-style' => '',
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_get_font_family_from_variation
+ *
+ * @covers WP_Webfonts_Utils::convert_variation_into_handle
+ *
+ * @param array $variation Variation to test.
+ * @param string $expected Expected results.
+ */
+ public function test_get_font_family_from_variation( array $variation, $expected ) {
+ $this->assertSame( $expected, WP_Webfonts_Utils::get_font_family_from_variation( $variation ) );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_get_font_family_from_variation() {
+ return array(
+ 'keyed by font-family' => array(
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Source Serif Pro',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected' => 'Source Serif Pro',
+ ),
+ 'keyed by fontFamily and as a handle' => array(
+ 'variation' => array(
+ 'fontFamily' => 'source-sans-pro',
+ 'font-weight' => '200 900',
+ 'src' => 'https://example.com/assets/fonts/source-sans-pro/source-sans-pro.ttf.woff2',
+ 'provider' => 'local',
+ ),
+ 'expected' => 'source-sans-pro',
+ ),
+ 'with font family name and full variant' => array(
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => 'Merriweather',
+ 'font-style' => 'normal',
+ 'font-weight' => '400 600',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected' => 'Merriweather',
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_get_font_family_from_variation_with_invalid_input
+ *
+ * @covers WP_Webfonts_Utils::get_font_family_from_variation
+ *
+ * @param array $invalid_variation Variation to test.
+ * @param string $expected_message Expected notice message.
+ */
+ public function test_get_font_family_from_variation_with_invalid_input( array $invalid_variation, $expected_message ) {
+ $this->expectNotice();
+ $this->expectNoticeMessage( $expected_message );
+
+ $this->assertNull( WP_Webfonts_Utils::get_font_family_from_variation( $invalid_variation ) );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_get_font_family_from_variation_with_invalid_input() {
+ return array(
+ 'keyed with underscore' => array(
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font_family' => 'Source Serif Pro',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected_message' => 'Font family not found.',
+ ),
+ 'keyed with space' => array(
+ 'variation' => array(
+ 'font family' => 'Source Sans Pro',
+ 'font-weight' => '200 900',
+ 'src' => 'https://example.com/assets/fonts/source-sans-pro/source-sans-pro.ttf.woff2',
+ 'provider' => 'local',
+ ),
+ 'expected_message' => 'Font family not found.',
+ ),
+ 'fontFamily => empty string' => array(
+ 'variation' => array(
+ 'fontFamily' => '',
+ 'font-weight' => '200 900',
+ 'src' => 'https://example.com/assets/fonts/source-sans-pro/source-sans-pro.ttf.woff2',
+ 'provider' => 'local',
+ ),
+ 'expected_message' => 'Font family not defined in the variation.',
+ ),
+ 'font-family => empty string' => array(
+ 'variation' => array(
+ 'provider' => 'local',
+ 'font-family' => '',
+ 'font-style' => 'normal',
+ 'font-weight' => '200 900',
+ 'font-stretch' => 'normal',
+ 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
+ 'font-display' => 'fallback',
+ ),
+ 'expected_message' => 'Font family not defined in the variation.',
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_is_defined
+ *
+ * @covers WP_Webfonts_Utils::is_defined
+ *
+ * @param mixed $input Input to test.
+ */
+ public function test_is_defined( $input ) {
+ $this->assertTrue( WP_Webfonts_Utils::is_defined( $input ) );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_is_defined() {
+ return array(
+ 'name: non empty string' => array( 'Some Font Family' ),
+ 'handle: non empty string' => array( 'some-font-family' ),
+ );
+ }
+
+ /**
+ * @dataProvider data_is_defined_when_not_defined
+ *
+ * @covers WP_Webfonts_Utils::is_defined
+ *
+ * @param mixed $invalid_input Input to test.
+ */
+ public function test_is_defined_when_not_defined( $invalid_input ) {
+ $this->assertFalse( WP_Webfonts_Utils::is_defined( $invalid_input ) );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_is_defined_when_not_defined() {
+ return array(
+ 'empty string' => array( '' ),
+ 'string 0' => array( '0' ),
+ 'integer' => array( 10 ),
+ 'name wrapped in an array' => array( array( 'Some Font Family' ) ),
+ 'handle wrapped in an array' => array( array( 'some-font-family' ) ),
+ );
+ }
+}