Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message
Agents
nette/schema
claude-code
cursor
config
nette

It is my fervent wish that this file guide every AI coding agent working with code in this repository.

Install
php artisan boost:add-skill nette/schema

Save this content to: AGENTS.md

# To My Agents!

It is my fervent wish that this file guide every AI coding agent working with code in this repository.

## Documentation

Any distilled, agent-facing documentation for this package - how it works
internally and the rationale behind key design decisions - lives in `docs/`.
Consult it before non-trivial changes; it is the source of truth from which the
public manual is distilled.

Small package, one coherent but tricky mechanism (the `Processor` pipeline over
`Elements/*`). Read `docs/internals.md` before editing it - the "phase" model is
subtler than it looks.

`docs/upgrading.md` records, per released version, every change visible to
users of the package (renames, removals, deprecations, signatures, behavior,
configuration), each with its commit hash; internal changes are not in it. It
is the place to look up the history of a public symbol. Do not write to it; it
is extended at release time from the git history.

## Project Overview

**Nette Schema** validates and normalizes data structures (config files, API
inputs) through a fluent `Expect::` builder and a `Processor`.

- **PHP Version**: 8.3 - 8.6
- **Package**: `nette/schema` (dep: `nette/utils`)

## Essential Commands

```bash
# Run all tests
vendor/bin/tester tests/Schema/ -s        # or: composer tester
vendor/bin/tester tests/Schema/Expect.structure.phpt -s

# Static analysis (PHPStan level 8)
composer phpstan
```

## Conventions

- Every file starts with `declare(strict_types=1);`; **tabs**; single quotes;
  `@internal` for implementation details, `@method` for `Expect`'s magic methods;
  Nette Coding Standard.
- Tests are Nette Tester `.phpt` named `Expect.<feature>.phpt`; `checkValidationErrors()`
  asserts the expected error messages of a failing `process()`.

## Working in this repo

- **There is no `validate()` phase.** The `Schema` interface has four operations
  but `Processor` runs only two per call: `process()` = `normalize()` +
  `complete()`; `processMultiple()` = `normalize()` each item, `merge()`
  left-to-right, one `complete()`. **Validation happens inside `complete()`**;
  `merge()` is reached only via `processMultiple`. Don't trust the old "three-phase"
  description.
- **`before()` runs per dataset item; `transform()`/`assert()` run once** on the
  merged result - so a `before` sees one config layer, a `transform` sees the whole.
- **Errors accumulate in `Context`, never thrown mid-validation.** Each element's
  `complete()` is an `$isOk = $context->createChecker(); $isOk() && nextStep()`
  short-circuit chain - thread any new validation step through the checker or it
  runs on already-rejected values.
- **Merging is schema-driven** (2.0): `Schema::merge()` takes a `Context`,
  strategy resolves as `mergeWith(closure)` → `MergeMode` (setter on ArrayType
  and Structure) → recursion **only through item schemas**. Ambiguous merges
  (colliding arrays with no schema guidance) add a `Message::CannotMerge` error,
  never a silent guess. `AnyOf` picks the alternative that the upper layer and
  the trially merged result both match (`Context::isPartial` = validation-only
  completion, bounds unchecked) and delegates to it.
- **`PreventMerging` (`'_prevent_merging'`) was removed** (BC break) —
  `Helpers::rejectPreventMerging()` reports the key as an error where a schema
  processes the items (untyped data are not walked); use
  `mergeMode(MergeMode::Replace)` instead.
- **Defaults are not merged into supplied arrays** (`ArrayType::$mergeDefaults
  = false`; `mergeDefaults()` turns it back on, silently in 2.0 for code
  supporting 1.x as well) - a partial input array stays partial.
- **`assert`/`castTo` are sugar over `transform`** - one `$transforms` list running
  in declaration order, so `->assert()->castTo()` differs from `->castTo()->assert()`.
- **`default` null is not `nullable`** (`nullable()` prepends `'null|'` to the type
  string); a `null` value becomes the default when the default is an array and the
  type is not nullable, as an empty block in NEON is no key. **`Structure` is required-by-default and casts to `object`, so
  `default()` throws on it.**
- **`AnyOf` tries variants in order in a throwaway `Context` clone** - losing
  variants' side effects (including transforms) are discarded. `DynamicParameter`
  values get **deferred** validation (recorded in `Context::dynamics` for DI) -
  don't validate them eagerly.
- **`Expect::type()` classifies the type expression once** (`TypeExpression::parse()`)
  into `StringType`/`NumberType`/`ArrayType`, an `AnyOf` for a union of different
  kinds, or a plain `Type` (an `EnumType` comes only from `Expect::enum()` and
  `Expect::from()`, a `DateTimeType` only from `Expect::dateTime()` and
  `Expect::date()`, which unlike any other element converts its `default()`).
  Since 2.0 `Type` validates by itself
  (`matches()`); `Validators::is()` serves only string formats and the
  deprecated legacy notation (expression ranges, `numeric` & co.), which works
  with a notice until 2.1 refuses it. `describe()`, `Kind` and `TypeExpression`
  are `@internal`, `JsonSchema::export()` is the only public way out - keep it
  that way.
- User-facing how-to (the `Expect::` API, castTo/`Expect::from` object mapping,
  building complex schemas) is manual material and lives in the public web docs.

To My Agents!

It is my fervent wish that this file guide every AI coding agent working with code in this repository.

Documentation

Any distilled, agent-facing documentation for this package - how it works internally and the rationale behind key design decisions - lives in docs/. Consult it before non-trivial changes; it is the source of truth from which the public manual is distilled.

Small package, one coherent but tricky mechanism (the Processor pipeline over Elements/*). Read docs/internals.md before editing it - the "phase" model is subtler than it looks.

docs/upgrading.md records, per released version, every change visible to users of the package (renames, removals, deprecations, signatures, behavior, configuration), each with its commit hash; internal changes are not in it. It is the place to look up the history of a public symbol. Do not write to it; it is extended at release time from the git history.

Project Overview

Nette Schema validates and normalizes data structures (config files, API inputs) through a fluent Expect:: builder and a Processor.

  • PHP Version: 8.3 - 8.6
  • Package: nette/schema (dep: nette/utils)

Essential Commands

# Run all tests
vendor/bin/tester tests/Schema/ -s        # or: composer tester
vendor/bin/tester tests/Schema/Expect.structure.phpt -s

# Static analysis (PHPStan level 8)
composer phpstan

Conventions

  • Every file starts with declare(strict_types=1);; tabs; single quotes; @internal for implementation details, @method for Expect's magic methods; Nette Coding Standard.
  • Tests are Nette Tester .phpt named Expect.<feature>.phpt; checkValidationErrors() asserts the expected error messages of a failing process().

Working in this repo

  • There is no validate() phase. The Schema interface has four operations but Processor runs only two per call: process() = normalize() + complete(); processMultiple() = normalize() each item, merge() left-to-right, one complete(). Validation happens inside complete(); merge() is reached only via processMultiple. Don't trust the old "three-phase" description.
  • before() runs per dataset item; transform()/assert() run once on the merged result - so a before sees one config layer, a transform sees the whole.
  • Errors accumulate in Context, never thrown mid-validation. Each element's complete() is an $isOk = $context->createChecker(); $isOk() && nextStep() short-circuit chain - thread any new validation step through the checker or it runs on already-rejected values.
  • Merging is schema-driven (2.0): Schema::merge() takes a Context, strategy resolves as mergeWith(closure) → MergeMode (setter on ArrayType and Structure) → recursion only through item schemas. Ambiguous merges (colliding arrays with no schema guidance) add a Message::CannotMerge error, never a silent guess. AnyOf picks the alternative that the upper layer and the trially merged result both match (Context::isPartial = validation-only completion, bounds unchecked) and delegates to it.
  • PreventMerging ('_prevent_merging') was removed (BC break) — Helpers::rejectPreventMerging() reports the key as an error where a schema processes the items (untyped data are not walked); use mergeMode(MergeMode::Replace) instead.
  • Defaults are not merged into supplied arrays (ArrayType::$mergeDefaults = false; mergeDefaults() turns it back on, silently in 2.0 for code supporting 1.x as well) - a partial input array stays partial.
  • assert/castTo are sugar over transform - one $transforms list running in declaration order, so ->assert()->castTo() differs from ->castTo()->assert().
  • default null is not nullable (nullable() prepends 'null|' to the type string); a null value becomes the default when the default is an array and the type is not nullable, as an empty block in NEON is no key. Structure is required-by-default and casts to object, so default() throws on it.
  • AnyOf tries variants in order in a throwaway Context clone - losing variants' side effects (including transforms) are discarded. DynamicParameter values get deferred validation (recorded in Context::dynamics for DI) - don't validate them eagerly.
  • Expect::type() classifies the type expression once (TypeExpression::parse()) into StringType/NumberType/ArrayType, an AnyOf for a union of different kinds, or a plain Type (an EnumType comes only from Expect::enum() and Expect::from(), a DateTimeType only from Expect::dateTime() and Expect::date(), which unlike any other element converts its default()). Since 2.0 Type validates by itself (matches()); Validators::is() serves only string formats and the deprecated legacy notation (expression ranges, numeric & co.), which works with a notice until 2.1 refuses it. describe(), Kind and TypeExpression are @internal, JsonSchema::export() is the only public way out - keep it that way.
  • User-facing how-to (the Expect:: API, castTo/Expect::from object mapping, building complex schemas) is manual material and lives in the public web docs.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json