diff --git a/changelog.txt b/changelog.txt
index 1700450..e1013fc 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,38 +1,5 @@
== Changelog ==
-= 1.2.2 =
-
-_Release date: 2026-08-24_
-
-**Highlights**
-
-* Manager (by ROBOTSTXT) detection now uses the ecosystem presence constant ROBOTSTXT_MANAGER_NOTICED (Manager 1.6.2+), with a plugin-list scan fallback for older Manager versions
-
-**Changed**
-
-* `robotstxt_docmd_is_manager_active()` now checks the ROBOTSTXT_MANAGER_NOTICED presence constant (Manager 1.6.2+) and falls back to scanning the plugin list (get_plugins() + is_plugin_active()) when the constant is absent; same function name and return type, so callers are unaffected
-
-**Security**
-
-* `composer update` (phpstan 2.2.9, nette/schema 1.3.6 — dev tooling only); `composer audit` clean, no known CVEs
-
-**Compatibility**
-
-* WordPress: 4.2 - 7.1 (floor re-verified with WP-Compat; smoke-tested on 7.2-alpha)
-* PHP: 8.0 - 8.5 (floor re-verified with PHPCompatibility 5.6-8.5 full-range scan)
-
-**Translations**
-
-* Spanish (es_ES) and Catalan (ca): verified complete and in sync (156 strings, no changes needed)
-
-**Tests**
-
-* PHP Coding Standards: PHPCS with WordPress-Core, WordPress-Docs, WordPress-Extra — 0 errors
-* PHPStan: level 9, 0 errors
-* PHPCompatibility: PHP 8.0-8.5 validated (full-range scan 5.6-8.5)
-* WP-Compat: WordPress 4.2 floor validated
-* PHPUnit: 23 tests pass (17 plugin header tests + 6 new Manager-detection tests covering both detection paths)
-
= 1.2.1 =
_Release date: 2026-08-17_
diff --git a/readme.txt b/readme.txt
index ac59063..5c061f8 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,7 +4,7 @@ Tags: github, documentation, markdown, sync, automation
Requires at least: 4.2
Tested up to: 7.1
Requires PHP: 8.0
-Stable tag: 1.2.2
+Stable tag: 1.2.1
License: GPLv3 or later
License URI: https://www.gnu.org/licenses/gpl-3.0.html
@@ -189,22 +189,6 @@ Then go to Documentation → Settings, and you'll see a "Debug Tools" section at
For the complete changelog, see [changelog.txt](https://www.robotstxt.software/plugins/robotstxt-documentation-markdown/).
-= 1.2.2 - 2026-08-24 =
-
-**Changed**
-
-* Manager (by ROBOTSTXT) detection now uses the ecosystem presence constant `ROBOTSTXT_MANAGER_NOTICED` (Manager 1.6.2+), falling back to a plugin-list scan for older Manager versions — same function name and behavior for callers
-* New unit tests for both detection paths (constant defined / plugin-list fallback)
-
-**Compatibility**
-
-* WordPress: 4.2 - 7.1 (floor re-verified with WP-Compat; smoke-tested on 7.2-alpha)
-* PHP: 8.0 - 8.5 (floor re-verified with PHPCompatibility 5.6-8.5 full-range scan)
-
-**Translations**
-
-* Spanish (es_ES) and Catalan (ca): verified complete and in sync (156 strings, no changes needed)
-
= 1.2.1 - 2026-08-17 =
**Changed**
@@ -254,10 +238,41 @@ For the complete changelog, see [changelog.txt](https://www.robotstxt.software/p
* Inline `onclick` confirm on Delete replaced with a `data-confirm` attribute + delegated handler (CSP-friendlier, less fragile)
* Add Mapping "existing content" dropdown now queries only public post types (excludes attachments and the internal mapping CPT) with `no_found_rows` for better performance on large sites
-== Upgrade Notice ==
+**Compatibility**
-= 1.2.2 =
-Manager (by ROBOTSTXT) detection updated: now uses the ROBOTSTXT_MANAGER_NOTICED presence constant (Manager 1.6.2+) with a fallback for older Manager versions.
+* Minimum WordPress raised to 6.8 (latest stable + two previous majors)
+* Verified compatible with WordPress 7.1
+* Declared PHP minimum made consistent across `readme.txt`, `composer.json`, `phpstan.neon`, and the PHPCompatibility scan range — real minimum remains 8.0
+
+= 1.1.1 - 2026-06-08 =
+
+**Security**
+
+* CommonMark: disabled raw HTML passthrough (`html_input: strip`, `allow_unsafe_links: false`) — prevents stored XSS via a compromised upstream repository
+* Settings option now stored with `autoload = false` — encrypted GitHub token no longer loaded on every WordPress request
+* Replaced `serialize()` with `wp_json_encode()` in updater HMAC cache signature
+* Added strict base64 length validation before IV extraction in token decryption
+* Added `base64_decode()` return-value check in GitHub file content fetch
+
+**Fixed**
+
+* Admin notices now display results for all operations: mapping created, updated, deleted, sync complete, and errors — previously only "Settings saved" was shown
+* `wp_update_post()` return value now checked during sync — silent failures no longer reported as success
+* Wrong textdomain in updater class (`'robotstxt-smtp'` → `'robotstxt-documentation-markdown'`)
+
+**Changed**
+
+* Renamed `robotstxt-updater.php` → `class-robotstxt-updater.php` (WordPress file naming convention)
+* Minimum PHP version corrected to 8.0 (real minimum confirmed by PHPCompatibility scan — no PHP 8.1 or 8.2 specific features used)
+
+**Developer**
+
+* Added full tooling: `composer.json`, `phpstan.neon` (level 9), `.phpcs.xml`, `bin/deploy.sh`, `phpunit.xml.dist`
+* PHPCompatibility updated to 10.0.0-alpha2 (PHP 8.x feature detection)
+* PHPUnit: 17 plugin header tests added
+* PHPCS, PHPStan level 9, PHPUnit all pass with 0 errors
+
+== Upgrade Notice ==
= 1.2.1 =
Automatic updates now require the Manager (by ROBOTSTXT) plugin. A notice with the download link is shown on the Plugins and Settings pages.
diff --git a/robotstxt-documentation-markdown.php b/robotstxt-documentation-markdown.php
index a6430a2..e52d538 100644
--- a/robotstxt-documentation-markdown.php
+++ b/robotstxt-documentation-markdown.php
@@ -3,7 +3,7 @@
* Plugin Name: Documentation Markdown (by ROBOTSTXT)
* Plugin URI: https://www.robotstxt.software/plugins/robotstxt-documentation-markdown/
* Description: Synchronizes Markdown documentation from GitHub repositories to WordPress pages and posts automatically.
- * Version: 1.2.2
+ * Version: 1.2.1
* Requires at least: 4.2
* Requires PHP: 8.0
* Security: robotstxt@robotstxt.es
@@ -25,7 +25,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
// Define plugin constants.
-define( 'ROBOTSTXT_DOCMD_VERSION', '1.2.2' );
+define( 'ROBOTSTXT_DOCMD_VERSION', '1.2.1' );
define( 'ROBOTSTXT_DOCMD_PLUGIN_FILE', __FILE__ );
define( 'ROBOTSTXT_DOCMD_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'ROBOTSTXT_DOCMD_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
@@ -1676,41 +1676,17 @@ function robotstxt_docmd_debug_fix_crons() {
}
/**
- * Check whether the Manager (by ROBOTSTXT) plugin is installed and active
+ * Check whether the Manager (by ROBOTSTXT) plugin is active
*
* Updates for this plugin are delivered through the Manager plugin. This
- * helper detects whether it is installed and active: it uses the ecosystem
- * presence constant (Manager 1.6.2+) and falls back to a plugin-list scan
- * for older Manager versions.
+ * helper detects whether it is installed and active.
*
* @since 1.2.1
- * @since 1.2.2 Switched to the ROBOTSTXT_MANAGER_NOTICED presence constant
- * with a plugin-list scan fallback for Manager < 1.6.2.
*
* @return bool True if Manager (by ROBOTSTXT) is active, false otherwise.
*/
function robotstxt_docmd_is_manager_active(): bool {
- if ( defined( 'ROBOTSTXT_MANAGER_NOTICED' ) && ROBOTSTXT_MANAGER_NOTICED ) {
- return true;
- }
-
- if ( ! function_exists( 'get_plugins' ) ) {
- require_once ABSPATH . 'wp-admin/includes/plugin.php';
- }
-
- foreach ( get_plugins() as $file => $data ) {
- $slug = dirname( $file );
-
- if ( '.' === $slug ) {
- $slug = basename( $file, '.php' );
- }
-
- if ( 'robotstxt-manager' === $slug ) {
- return is_plugin_active( $file );
- }
- }
-
- return false;
+ return defined( 'ROBOTSTXT_MANAGER_VERSION' );
}
/**
diff --git a/update.json b/update.json
new file mode 100644
index 0000000..4fa49e4
--- /dev/null
+++ b/update.json
@@ -0,0 +1,27 @@
+{
+ "name": "Documentation Markdown (by ROBOTSTXT)",
+ "slug": "robotstxt-documentation-markdown",
+ "version": "1.2.1",
+ "download_url": "https://git.robotstxt.es/ROBOTSTXT/robotstxt-documentation-markdown/releases/download/1.2.1/robotstxt-documentation-markdown-1.2.1.zip",
+ "requires": "6.8",
+ "requires_php": "8.0",
+ "tested": "7.1",
+ "last_updated": "2026-08-07",
+ "author": "ROBOTSTXT",
+ "author_profile": "https://www.robotstxt.es/",
+ "homepage": "https://git.robotstxt.es/ROBOTSTXT/robotstxt-documentation-markdown",
+ "description": "Synchronizes Markdown documentation from GitHub repositories to WordPress pages and posts automatically. Perfect for maintaining technical documentation, API references, knowledge bases, and more with version control.",
+ "changelog": "",
+ "sections": {
+ "description": "
Documentation Markdown is a powerful WordPress plugin that enables seamless synchronization of Markdown documentation files from GitHub repositories into your WordPress site.
Key Features
- Automatic Synchronization: Schedule automatic syncs via WordPress Cron (hourly, twice daily, daily)
- Markdown to HTML: Convert GitHub Flavored Markdown to clean HTML using CommonMark
- Flexible Mapping: Map individual MD files to specific WordPress posts or pages
- Title from H1: Post titles are derived from the first Markdown H1 heading
- Link & Image Translation: Repo-relative links are rewritten to permalinks; images are sideloaded into the Media Library
- Secure: Encrypted GitHub token storage (HKDF-SHA256), full input validation & output escaping
- Translatable: Full internationalization support (i18n/l10n ready)
- Multi-Repository: Sync from multiple GitHub repos simultaneously
- Manual Sync: On-demand synchronization from admin interface
- Debug Tools: Built-in debugging tools (visible when WP_DEBUG is enabled)
Use Cases
- API Documentation - Keep your API docs in sync between GitHub and WordPress
- Technical Documentation - Maintain version-controlled technical docs
- Knowledge Base - Build a knowledge base powered by GitHub
- Blog Posts - Write blog posts in Markdown with Git workflow
- Product Documentation - Sync product documentation from your repository
Requirements
- PHP 8.0 or higher
- WordPress 6.8 or higher
- GitHub Personal Access Token (free)
",
+ "changelog": ""
+ },
+ "banners": {
+ "low": "",
+ "high": ""
+ },
+ "icons": {
+ "1x": "",
+ "2x": ""
+ }
+}
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 350ecaf..6194647 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -275,17 +275,17 @@
},
{
"name": "nette/schema",
- "version": "v1.3.6",
- "version_normalized": "1.3.6.0",
+ "version": "v1.3.5",
+ "version_normalized": "1.3.5.0",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
- "reference": "c54350438cd6914616f790a49cb424605f421562"
+ "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nette/schema/zipball/c54350438cd6914616f790a49cb424605f421562",
- "reference": "c54350438cd6914616f790a49cb424605f421562",
+ "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002",
+ "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002",
"shasum": ""
},
"require": {
@@ -299,7 +299,7 @@
"phpstan/phpstan": "^2.1.39@stable",
"tracy/tracy": "^2.8"
},
- "time": "2026-08-16T21:58:41+00:00",
+ "time": "2026-02-23T03:47:12+00:00",
"type": "library",
"extra": {
"branch-alias": {
@@ -339,7 +339,7 @@
],
"support": {
"issues": "https://github.com/nette/schema/issues",
- "source": "https://github.com/nette/schema/tree/v1.3.6"
+ "source": "https://github.com/nette/schema/tree/v1.3.5"
},
"install-path": "../nette/schema"
},
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
index a249c41..dfced0b 100644
--- a/vendor/composer/installed.php
+++ b/vendor/composer/installed.php
@@ -38,9 +38,9 @@
'dev_requirement' => false,
),
'nette/schema' => array(
- 'pretty_version' => 'v1.3.6',
- 'version' => '1.3.6.0',
- 'reference' => 'c54350438cd6914616f790a49cb424605f421562',
+ 'pretty_version' => 'v1.3.5',
+ 'version' => '1.3.5.0',
+ 'reference' => 'f0ab1a3cda782dbc5da270d28545236aa80c4002',
'type' => 'library',
'install_path' => __DIR__ . '/../nette/schema',
'aliases' => array(),
diff --git a/vendor/nette/schema/readme.md b/vendor/nette/schema/readme.md
index 7e52878..ce9d0d1 100644
--- a/vendor/nette/schema/readme.md
+++ b/vendor/nette/schema/readme.md
@@ -126,7 +126,7 @@ Expect::null()
Expect::array($default = [])
```
-And then all types [supported by the Validators](https://doc.nette.org/validators#toc-expected-types) via `Expect::type('scalar')` or abbreviated `Expect::scalar()`. Also class or interface names are accepted, e.g. `Expect::type('AddressEntity')`.
+And then all types [supported by the Validators](https://doc.nette.org/validators#toc-validation-rules) via `Expect::type('scalar')` or abbreviated `Expect::scalar()`. Also class or interface names are accepted, e.g. `Expect::type('AddressEntity')`.
You can also use union notation:
diff --git a/vendor/nette/schema/src/Schema/Context.php b/vendor/nette/schema/src/Schema/Context.php
index b42b1ed..a002d5c 100644
--- a/vendor/nette/schema/src/Schema/Context.php
+++ b/vendor/nette/schema/src/Schema/Context.php
@@ -10,9 +10,6 @@ namespace Nette\Schema;
use function count;
-/**
- * Accumulates errors and warnings during schema validation and tracks the current path.
- */
final class Context
{
public bool $skipDefaults = false;
@@ -47,10 +44,7 @@ final class Context
}
- /**
- * Returns a closure that returns true as long as no new errors have been added since the call.
- * @return \Closure(): bool
- */
+ /** @return \Closure(): bool */
public function createChecker(): \Closure
{
$count = count($this->errors);
diff --git a/vendor/nette/schema/src/Schema/Elements/AnyOf.php b/vendor/nette/schema/src/Schema/Elements/AnyOf.php
index 582cf13..09e21c9 100644
--- a/vendor/nette/schema/src/Schema/Elements/AnyOf.php
+++ b/vendor/nette/schema/src/Schema/Elements/AnyOf.php
@@ -14,9 +14,6 @@ use Nette\Schema\Schema;
use function array_merge, array_unique, implode, is_array;
-/**
- * Schema that accepts any of a fixed set of values or sub-schemas (union type / enumeration).
- */
final class AnyOf implements Schema
{
use Base;
@@ -35,9 +32,6 @@ final class AnyOf implements Schema
}
- /**
- * Sets the first variant as the default value (instead of null).
- */
public function firstIsDefault(): self
{
$this->default = $this->set[0];
@@ -45,9 +39,6 @@ final class AnyOf implements Schema
}
- /**
- * Allows null as an accepted value in addition to the defined variants.
- */
public function nullable(): self
{
$this->set[] = null;
@@ -55,9 +46,6 @@ final class AnyOf implements Schema
}
- /**
- * Allows the value to be a DynamicParameter as an accepted variant.
- */
public function dynamic(): self
{
$this->set[] = new Type(Nette\Schema\DynamicParameter::class);
@@ -100,13 +88,10 @@ final class AnyOf implements Schema
foreach ($this->set as $item) {
if ($item instanceof Schema) {
$dolly = new Context;
- $dolly->skipDefaults = $context->skipDefaults;
- $dolly->isKey = $context->isKey;
$dolly->path = $context->path;
$res = $item->complete($item->normalize($value, $dolly), $dolly);
if (!$dolly->errors) {
$context->warnings = array_merge($context->warnings, $dolly->warnings);
- $context->dynamics = array_merge($context->dynamics, $dolly->dynamics);
return $res;
}
diff --git a/vendor/nette/schema/src/Schema/Elements/Base.php b/vendor/nette/schema/src/Schema/Elements/Base.php
index c4e3dd6..6e83eb7 100644
--- a/vendor/nette/schema/src/Schema/Elements/Base.php
+++ b/vendor/nette/schema/src/Schema/Elements/Base.php
@@ -43,10 +43,7 @@ trait Base
}
- /**
- * Sets a pre-normalization callback applied to the raw input value before any validation.
- * @param callable(mixed): mixed $handler
- */
+ /** @param callable(mixed): mixed $handler */
public function before(callable $handler): self
{
$this->before = $handler(...);
@@ -54,19 +51,13 @@ trait Base
}
- /**
- * Casts the validated value to a built-in type or instantiates the given class.
- */
public function castTo(string $type): self
{
return $this->transform(Helpers::getCastStrategy($type));
}
- /**
- * Adds a post-validation transformation callback. The handler may also report errors via Context.
- * @param callable(mixed, Context): mixed $handler
- */
+ /** @param callable(mixed, Context): mixed $handler */
public function transform(callable $handler): self
{
$this->transforms[] = $handler(...);
@@ -74,10 +65,7 @@ trait Base
}
- /**
- * Adds a custom validation assertion; optionally describe it for error messages.
- * @param callable(mixed): bool $handler
- */
+ /** @param callable(mixed): bool $handler */
public function assert(callable $handler, ?string $description = null): self
{
$expected = $description ?? (is_string($handler) ? "$handler()" : '#' . count($this->transforms));
@@ -90,14 +78,11 @@ trait Base
Nette\Schema\Message::FailedAssertion,
['value' => $value, 'assertion' => $expected],
);
- return null;
});
}
- /**
- * Marks the item as deprecated; emits a warning with the given message when the item is used.
- */
+ /** Marks as deprecated */
public function deprecated(string $message = 'The item %path% is deprecated.'): self
{
$this->deprecated = $message;
@@ -153,7 +138,7 @@ trait Base
}
- /** @deprecated use Nette\Schema\Helpers::validateType() */
+ /** @deprecated use Nette\Schema\Validators::validateType() */
private function doValidate(mixed $value, string $expected, Context $context): bool
{
$isOk = $context->createChecker();
@@ -163,7 +148,7 @@ trait Base
/**
- * @deprecated use Nette\Schema\Helpers::validateRange()
+ * @deprecated use Nette\Schema\Validators::validateRange()
* @param array{?float, ?float} $range
*/
private static function doValidateRange(mixed $value, array $range, Context $context, string $types = ''): bool
diff --git a/vendor/nette/schema/src/Schema/Elements/Structure.php b/vendor/nette/schema/src/Schema/Elements/Structure.php
index a6cf02d..1abf49f 100644
--- a/vendor/nette/schema/src/Schema/Elements/Structure.php
+++ b/vendor/nette/schema/src/Schema/Elements/Structure.php
@@ -39,9 +39,6 @@ final class Structure implements Schema
}
- /**
- * Not supported for structures; always throws.
- */
public function default(mixed $value): self
{
throw new Nette\InvalidStateException('Structure cannot have default value.');
@@ -62,9 +59,6 @@ final class Structure implements Schema
}
- /**
- * Allows extra keys not defined in the shape, validating their values against the given type.
- */
public function otherItems(string|Schema $type = 'mixed'): self
{
$this->otherItems = $type instanceof Schema ? $type : new Type($type);
@@ -72,9 +66,6 @@ final class Structure implements Schema
}
- /**
- * When enabled, properties whose value equals the default are omitted from the output.
- */
public function skipDefaults(bool $state = true): self
{
$this->skipDefaults = $state;
@@ -82,10 +73,7 @@ final class Structure implements Schema
}
- /**
- * Creates a new structure by merging this shape with additional properties.
- * @param Schema[]|self $shape
- */
+ /** @param Schema[]|self $shape */
public function extend(array|self $shape): self
{
$shape = $shape instanceof self ? $shape->items : $shape;
@@ -215,17 +203,8 @@ final class Structure implements Schema
public function completeDefault(Context $context): mixed
{
- if (!$this->required) {
- return null;
- }
-
- // the item is missing in the input, do not report it as used deprecated
- $deprecated = $this->deprecated;
- $this->deprecated = null;
- try {
- return $this->complete([], $context);
- } finally {
- $this->deprecated = $deprecated;
- }
+ return $this->required
+ ? $this->complete([], $context)
+ : null;
}
}
diff --git a/vendor/nette/schema/src/Schema/Elements/Type.php b/vendor/nette/schema/src/Schema/Elements/Type.php
index 880f4bb..4413f69 100644
--- a/vendor/nette/schema/src/Schema/Elements/Type.php
+++ b/vendor/nette/schema/src/Schema/Elements/Type.php
@@ -11,7 +11,6 @@ use Nette\Schema\Context;
use Nette\Schema\DynamicParameter;
use Nette\Schema\Helpers;
use Nette\Schema\Schema;
-use Nette\Utils\Validators;
use function array_key_exists, array_pop, implode, is_array, str_replace, strpos;
@@ -37,9 +36,6 @@ final class Type implements Schema
}
- /**
- * Allows the value to be null in addition to the declared type.
- */
public function nullable(): self
{
$this->type = 'null|' . $this->type;
@@ -47,9 +43,6 @@ final class Type implements Schema
}
- /**
- * Controls whether the default value is merged with the input array (enabled by default).
- */
public function mergeDefaults(bool $state = true): self
{
$this->merge = $state;
@@ -57,9 +50,6 @@ final class Type implements Schema
}
- /**
- * Allows the value to be a DynamicParameter, which is recorded for deferred validation.
- */
public function dynamic(): self
{
$this->type = DynamicParameter::class . '|' . $this->type;
@@ -96,9 +86,6 @@ final class Type implements Schema
}
- /**
- * Sets a regex pattern the string value must match entirely (anchored to start and end).
- */
public function pattern(?string $pattern): self
{
$this->pattern = $pattern;
@@ -175,7 +162,7 @@ final class Type implements Schema
$merge = false;
}
- if ($value === null && is_array($this->default) && !Validators::is(null, $this->type)) {
+ if ($value === null && is_array($this->default)) {
$value = []; // is unable to distinguish null from array in NEON
}
@@ -186,13 +173,13 @@ final class Type implements Schema
$isOk() && Helpers::validateRange($value, $this->range, $context, $this->type);
$isOk() && $value !== null && $this->pattern !== null && Helpers::validatePattern($value, $this->pattern, $context);
$isOk() && is_array($value) && $this->validateItems($value, $context);
- $isOk() && $merge && $value !== null && $value = Helpers::merge($value, $this->default);
+ $isOk() && $merge && $value = Helpers::merge($value, $this->default);
$isOk() && $value = $this->doTransform($value, $context);
if (!$isOk()) {
return null;
}
- if ($value instanceof DynamicParameter && $this->type !== DynamicParameter::class) {
+ if ($value instanceof DynamicParameter) {
$expected = $this->type . ($this->range === [null, null] ? '' : ':' . implode('..', $this->range));
$context->dynamics[] = [$value, str_replace(DynamicParameter::class . '|', '', $expected), $context->path];
}
@@ -203,7 +190,7 @@ final class Type implements Schema
/** @param array $value */
private function validateItems(array &$value, Context $context): void
{
- if (!($itemsValue = $this->itemsValue)) {
+ if (!$this->itemsValue) {
return;
}
@@ -211,15 +198,9 @@ final class Type implements Schema
foreach ($value as $key => $val) {
$context->path[] = $key;
$context->isKey = true;
- $isKeyOk = $context->createChecker();
$key = $this->itemsKey ? $this->itemsKey->complete($key, $context) : $key;
$context->isKey = false;
- $keyOk = $isKeyOk();
- $val = $itemsValue->complete($val, $context);
- if ($keyOk) {
- $res[$key] = $val;
- }
-
+ $res[$key ?? ''] = $this->itemsValue->complete($val, $context);
array_pop($context->path);
}
$value = $res;
diff --git a/vendor/nette/schema/src/Schema/Expect.php b/vendor/nette/schema/src/Schema/Expect.php
index 44cf25b..64e31f2 100644
--- a/vendor/nette/schema/src/Schema/Expect.php
+++ b/vendor/nette/schema/src/Schema/Expect.php
@@ -42,38 +42,26 @@ final class Expect
}
- /**
- * Creates a schema for a custom type expression (e.g., 'int|string', 'null|float').
- */
public static function type(string $type): Type
{
return new Type($type);
}
- /**
- * Creates a union schema that accepts any of the given values or sub-schemas.
- */
public static function anyOf(mixed ...$set): AnyOf
{
return new AnyOf(...$set);
}
- /**
- * Creates a structure schema with defined properties; output is stdClass.
- * @param Schema[] $shape
- */
+ /** @param Schema[] $shape */
public static function structure(array $shape): Structure
{
return new Structure($shape);
}
- /**
- * Generates a structure schema from a class instance by reflecting its properties or constructor parameters.
- * @param array $items Optional overrides for specific properties.
- */
+ /** @param array $items */
public static function from(object $object, array $items = []): Structure
{
$ro = new \ReflectionObject($object);
@@ -107,8 +95,6 @@ final class Expect
/**
- * Creates an array schema. When passed Schema elements, behaves like structure() but outputs an array.
- * Without Schema elements, creates a plain array type with the given default value.
* @param mixed[] $shape
*/
public static function array(?array $shape = []): Structure|Type
@@ -120,18 +106,12 @@ final class Expect
}
- /**
- * Creates an associative or indexed array schema where every value matches the given type.
- */
public static function arrayOf(string|Schema $valueType, string|Schema|null $keyType = null): Type
{
return (new Type('array'))->items($valueType, $keyType);
}
- /**
- * Creates a list schema (sequentially indexed from 0) where every element matches the given type.
- */
public static function listOf(string|Schema $type): Type
{
return (new Type('list'))->items($type);
diff --git a/vendor/nette/schema/src/Schema/Helpers.php b/vendor/nette/schema/src/Schema/Helpers.php
index e15bf50..79a4a3c 100644
--- a/vendor/nette/schema/src/Schema/Helpers.php
+++ b/vendor/nette/schema/src/Schema/Helpers.php
@@ -9,7 +9,7 @@ namespace Nette\Schema;
use Nette;
use Nette\Utils\Reflection;
-use function array_map, count, explode, get_debug_type, implode, in_array, is_array, is_float, is_int, is_object, is_scalar, is_string, is_subclass_of, method_exists, preg_match, preg_quote, preg_replace, preg_replace_callback, settype, str_replace, strlen, trim, var_export;
+use function count, explode, get_debug_type, implode, in_array, is_array, is_float, is_int, is_object, is_scalar, is_string, method_exists, preg_match, preg_quote, preg_replace, preg_replace_callback, settype, str_replace, strlen, trim, var_export;
/**
@@ -54,9 +54,6 @@ final class Helpers
}
- /**
- * Returns the type of a property or parameter as a string, or null if not determinable.
- */
public static function getPropertyType(\ReflectionProperty|\ReflectionParameter $prop): ?string
{
if ($type = Nette\Utils\Type::fromReflection($prop)) {
@@ -92,9 +89,6 @@ final class Helpers
}
- /**
- * Formats a value for use in error messages (e.g., 'hello', true, object stdClass).
- */
public static function formatValue(mixed $value): string
{
if ($value instanceof DynamicParameter) {
@@ -111,9 +105,6 @@ final class Helpers
}
- /**
- * Adds a TypeMismatch error to the context if the value does not match the expected type.
- */
public static function validateType(mixed $value, string $expected, Context $context): void
{
if (!Nette\Utils\Validators::is($value, $expected)) {
@@ -128,10 +119,7 @@ final class Helpers
}
- /**
- * Adds a range error to the context if the value (or its length for strings/arrays) is outside the given range.
- * @param array{?float, ?float} $range
- */
+ /** @param array{?float, ?float} $range */
public static function validateRange(mixed $value, array $range, Context $context, string $types = ''): void
{
if (is_array($value) || is_string($value)) {
@@ -158,10 +146,7 @@ final class Helpers
}
- /**
- * Checks whether a value falls within the given [min, max] range (null means no bound).
- * @param array{?float, ?float} $range
- */
+ /** @param array{?float, ?float} $range */
public static function isInRange(mixed $value, array $range): bool
{
return ($range[0] === null || $value >= $range[0])
@@ -169,9 +154,6 @@ final class Helpers
}
- /**
- * Adds a PatternMismatch error to the context if the value does not match the pattern.
- */
public static function validatePattern(string $value, string $pattern, Context $context): void
{
if (!preg_match("\x01^(?:$pattern)$\x01Du", $value)) {
@@ -184,10 +166,7 @@ final class Helpers
}
- /**
- * Returns a closure that casts a value to the given type (built-in, backed enum, class with constructor, or plain class).
- * @return \Closure(mixed, Context): mixed
- */
+ /** @return \Closure(mixed): mixed */
public static function getCastStrategy(string $type): \Closure
{
if (Nette\Utils\Validators::isBuiltinType($type)) {
@@ -195,37 +174,12 @@ final class Helpers
settype($value, $type);
return $value;
};
-
- } elseif (is_subclass_of($type, \BackedEnum::class)) {
- return static function ($value, Context $context) use ($type) {
- try {
- return $type::from($value);
- } catch (\TypeError | \ValueError) {
- $context->addError(
- 'The %label% %path% expects to be %expected%, %value% given.',
- Message::TypeMismatch,
- ['value' => $value, 'expected' => implode('|', array_map(fn(\BackedEnum $case) => self::formatValue($case->value), $type::cases()))],
- );
- return null;
- }
- };
-
- } elseif (is_subclass_of($type, \UnitEnum::class)) {
- throw new Nette\InvalidStateException("Cannot cast value to pure enum $type.");
- }
-
- $factory = method_exists($type, '__construct')
- ? static fn($value) => is_array($value) || $value instanceof \stdClass
+ } elseif (method_exists($type, '__construct')) {
+ return static fn($value) => is_array($value) || $value instanceof \stdClass
? new $type(...(array) $value)
- : new $type($value)
- : static fn($value) => Nette\Utils\Arrays::toObject((array) $value, new $type);
-
- return static function ($value) use ($factory, $type) {
- try {
- return $factory($value);
- } catch (\Error $e) {
- throw new Nette\InvalidStateException("Unable to cast value to $type: " . $e->getMessage(), 0, $e);
- }
- };
+ : new $type($value);
+ } else {
+ return static fn($value) => Nette\Utils\Arrays::toObject((array) $value, new $type);
+ }
}
}
diff --git a/vendor/nette/schema/src/Schema/Message.php b/vendor/nette/schema/src/Schema/Message.php
index f06f172..4923f14 100644
--- a/vendor/nette/schema/src/Schema/Message.php
+++ b/vendor/nette/schema/src/Schema/Message.php
@@ -7,12 +7,9 @@
namespace Nette\Schema;
-use function array_key_exists, implode, preg_replace_callback;
+use function implode, preg_replace_callback;
-/**
- * Represents a single validation error or warning with a message template, error code, path, and variables.
- */
final class Message
{
/** variables: {value: mixed, expected: string} */
@@ -75,9 +72,6 @@ final class Message
}
- /**
- * Formats the message template by substituting %variable% placeholders with their values.
- */
public function toString(): string
{
$vars = $this->variables;
@@ -89,9 +83,7 @@ final class Message
return preg_replace_callback('~( ?)%(\w+)%~', function ($m) use ($vars) {
[, $space, $key] = $m;
- return array_key_exists($key, $vars)
- ? ($vars[$key] === null ? '' : $space . $vars[$key])
- : $m[0];
+ return $vars[$key] === null ? '' : $space . $vars[$key];
}, $this->message);
}
}
diff --git a/vendor/nette/schema/src/Schema/Processor.php b/vendor/nette/schema/src/Schema/Processor.php
index 3ce576a..4a2ef7b 100644
--- a/vendor/nette/schema/src/Schema/Processor.php
+++ b/vendor/nette/schema/src/Schema/Processor.php
@@ -21,9 +21,6 @@ final class Processor
private bool $skipDefaults = false;
- /**
- * When enabled, properties with default values are omitted from the output.
- */
public function skipDefaults(bool $value = true): void
{
$this->skipDefaults = $value;
@@ -38,9 +35,9 @@ final class Processor
{
$this->createContext();
$data = $schema->normalize($data, $this->context);
- $this->throwErrors();
+ $this->throwsErrors();
$data = $schema->complete($data, $this->context);
- $this->throwErrors();
+ $this->throwsErrors();
return $data;
}
@@ -57,35 +54,30 @@ final class Processor
$first = true;
foreach ($dataset as $data) {
$data = $schema->normalize($data, $this->context);
- $this->throwErrors();
+ $this->throwsErrors();
$flatten = $first ? $data : $schema->merge($data, $flatten);
$first = false;
}
$data = $schema->complete($flatten, $this->context);
- $this->throwErrors();
+ $this->throwsErrors();
return $data;
}
- /**
- * Returns all deprecation warnings collected during the last processing run.
- * @return list
- */
+ /** @return list */
public function getWarnings(): array
{
$res = [];
- if (isset($this->context)) {
- foreach ($this->context->warnings as $message) {
- $res[] = $message->toString();
- }
+ foreach ($this->context->warnings as $message) {
+ $res[] = $message->toString();
}
return $res;
}
- private function throwErrors(): void
+ private function throwsErrors(): void
{
if ($this->context->errors) {
throw new ValidationException(null, $this->context->errors);
diff --git a/vendor/nette/schema/src/Schema/Schema.php b/vendor/nette/schema/src/Schema/Schema.php
index 619ebcf..1616f64 100644
--- a/vendor/nette/schema/src/Schema/Schema.php
+++ b/vendor/nette/schema/src/Schema/Schema.php
@@ -8,31 +8,27 @@
namespace Nette\Schema;
-/**
- * Defines the contract for schema elements used in data validation and normalization.
- */
interface Schema
{
/**
- * Applies pre-processing transformations to the raw input value (e.g., via before() hooks).
+ * Normalization.
* @return mixed
*/
function normalize(mixed $value, Context $context);
/**
- * Merges two normalized values, with $value taking priority over $base.
+ * Merging.
* @return mixed
*/
function merge(mixed $value, mixed $base);
/**
- * Validates the value and applies defaults, transforms, and assertions.
+ * Validation and finalization.
* @return mixed
*/
function complete(mixed $value, Context $context);
/**
- * Returns the default value, or adds a missing-item error if the field is required.
* @return mixed
*/
function completeDefault(Context $context);
diff --git a/vendor/nette/schema/src/Schema/ValidationException.php b/vendor/nette/schema/src/Schema/ValidationException.php
index cefca43..396320f 100644
--- a/vendor/nette/schema/src/Schema/ValidationException.php
+++ b/vendor/nette/schema/src/Schema/ValidationException.php
@@ -18,16 +18,13 @@ class ValidationException extends Nette\InvalidStateException
public function __construct(
?string $message,
/** @var list */
- private readonly array $messages = [],
+ private array $messages = [],
) {
parent::__construct($message ?? $messages[0]->toString());
}
- /**
- * Returns all validation error messages as formatted strings.
- * @return list
- */
+ /** @return list */
public function getMessages(): array
{
$res = [];
@@ -39,10 +36,7 @@ class ValidationException extends Nette\InvalidStateException
}
- /**
- * Returns all validation error messages as Message objects.
- * @return list
- */
+ /** @return list */
public function getMessageObjects(): array
{
return $this->messages;