| vite-plugin | by dg | dropped support for Node.js 20, requires Node.js 22+ (BC break) Node.js 20 reached end of life in April 2026. The CI matrix now runs 22 and 24, package.json declares engines >= 22, and the runtime guard around fs.globSync is gone, so glob entries work on every supported version. Also bumped actions/setup-node from v4 to v7. | | | |
| vite-plugin | by dg | readme: rewrote as a full feature overview Documents every plugin option (entry, refresh, host, appUrl, infoFile), the Vite defaults the plugin injects, dev-mode detection via the info file, and the CORS/Docker/proxy/network recipes. | | | |
| vite-plugin | by dg | released version 1.1.0 | | | |
| vite-plugin | by dg | fix: guard glob entries on Node < 22 and de-duplicate exit cleanup Review follow-ups: - fs.globSync exists only on Node 22+, but Vite 6 supports Node 18+; a glob entry on an older runtime threw a cryptic 'not a function'. Throw a clear error from the glob branch instead. - The signal handler removed info files and then called process.exit(0), which re-ran the same cleanup via the 'exit' handler. Let signals just exit; the single 'exit' handler owns cleanup. | | | |
| coding-standard | by dg | output: added summary telling whether any file was actually modified The sniffer's "No violations were found" was printed last and read as the verdict of the whole run, even when PHP CS Fixer had just rewritten files. Neither engine knows what the other did, so run.php now hashes the file list before and after the run and reports the union in a Summary block. Each engine's output is also delimited by a header, and a preset missing from one of the two trees announces the skip instead of doing nothing silently. | | | |
| coding-standard | by dg | fixed import types being mixed together when reordering The stock ordered_imports fixer keeps the original statement prefixes in place and pours the sorted names back into them. Since Nette turns off single_import_per_statement, a comma-separated `use const` sitting above a `use function` came back as `use function c, d, A;`, and a class statement could end up holding a function - valid syntax that silently changes what the names resolve to. Nette/ordered_imports replaces it and regenerates the whole block instead, so a name can never change its import type. It keeps each type's shape, the number of statements and how many names each held, so it only reorders and never merges or splits what the author wrote. A comment anywhere in the block makes the block untouchable, because a rewrite would drop it and reordering around it would reattach it to an import it never described. php80.php enforces `ordered_imports => false` after merging the project overrides; re-enabling the stock fixer would run both at priority -30 in undefined order and corrupt the result again. OptimizeGlobalCallsSniff now anchors a new block to the last statement it may follow instead of the last one in the file, so `use function` lands above an existing `use const`. That matters on its own because the optimize-fn preset has no fixer tree, so running it skips PHP CS Fixer entirely and the sniff cannot lean on the fixer to place its output. | | | |
| coding-standard | by dg | NoLeadingSlashInGlobalNamespaceFixer: added fork respecting imports The PhpCsFixerCustomFixers fixer decides only from the preceding token, so in a file without a namespace declaration it rewrites `new \Foo\Bar` to `new Foo\Bar` even when `use Foo\Foo;` makes Foo an alias. The name then resolves to Foo\Foo\Bar and the code breaks at runtime, silently. Single-segment names are exposed the same way, `use Foo\Exception;` shadows `\Exception`. The fork collects the class imports of the file and keeps the slash when the first segment of the name matches one of them. | | | |
| claude-code | by dg | Released version 1.2.0 | | | |
| claude-code | by dg | skills: added seven skills for areas nothing covered Nette\Security appeared in no skill at all; the same held for sessions, routing, caching, mail, the component tree and the retired-name lookup. The scope of each was set by measuring what models actually produce rather than by the size of the documentation, so they document the traps instead of teaching the topic and are far shorter than a full guide. Every claim was verified against the library source at a named tag, most of them by running the code, and all seven were then re-checked by an independent pass. - nette-security: the Authenticator contract and its error codes, SimpleIdentity against the 2.x names, Passwords as a service with instance methods, logout() keeping the identity, sliding expiration, the Permission ACL including last-parent-wins, IdentityHandler for stale roles - nette-components: factories, signals and where they run, why a form submit is not a signal, what {plink} really is, persistent parameters, redrawControl against the nonexistent invalidateControl, payload.redirect during AJAX, dynamic snippets, the argument-free getComponents() - nette-routing: that route order governs link generation and not only matching, one-way routes, filter order, canonicalization, and that cache: true cannot serialize a closure filter - nette-http: the Sec-Fetch based CSRF protection, that any non-browser client fails it quietly, sessions through set/get/remove, the proxy trap, and the SSRF UrlValidator - nette-caching: Cache::Expire rather than Expiration, remove() rather than the nonexistent forget(), which storages need a journal, and that a closure in Cache::Callbacks is a fatal because the dependency is serialized - nette-mail: setHtmlBody auto-embedding, addEmbeddedFile returning a MimePart that must not be concatenated, SmtpMailer having no default credentials, and the 4.2 additions - nette-upgrading: retired name to current name across all packages, sorted by whether the old name still resolves; the aliases sit in an if (false) branch, so the IDE and PHPStan flag them while nothing fires at runtime | | | |
| claude-code | by dg | skills: documented Latte 3.1 smart HTML attributes Printing an attribute is the most common thing a template does and 3.1 changed how it behaves, so a model trained on older Latte writes 3.0 code. Every example here was produced by running it. Covers the bool, tristate, valued-bool, list, style, data and aria categories, that the handling applies only when the whole value is one {...} expression, that a keyed array item counts only when its value is === true, and the traps: URL attributes are exempt through the internal checkUrl filter, and a real filter stringifies the value and defeats the whole mechanism. Also prefers class={[...]} over n:class and attribute values over n:attr, while saying plainly that neither is deprecated and that n:attr remains the only way to express a dynamic set or name of attributes. Rewriting is not mechanical: n:class de-duplicates the list and the attribute form does not. | | | |
| claude-code | by dg | skills: corrected and extended the existing skills Every claim was checked against the library source, most of it by executing the snippet; several skills were then re-checked by an independent pass. - architecture: the lifecycle had signals inside the action phase; they run after it and after canonicalization. Added afterRender, shutdown, the events, and that parent::startup() is enforced - configuration: only presenters are auto-registered, not components; added generated factories and accessors (implement:) - forms: {form} attributes need a comma, Numeric is a non-negative integer rather than an alias for Integer, corrected the renderer wrapper keys, Nette\Application\UI\Form belongs in a presenter, onValidate must read values with getUntrustedValues(), and CSRF is now Sec-Fetch based - database: array keys in where() are SQL, keywords in fragments must be uppercase, the empty-array trap, transaction() nesting and its return value - utils: Callback::closure() and Type::allowsNull() do not exist, corrected the expected output of isBuiltin(), typeToExtension() and firstLower(); added Process, DateTimeImmutable and the Html escaping contract - tester: annotations, TestCase, helpers and CLI flags; a test with no assertion is an error and exit() counts as a pass; @phpVersion with a three-component version skips the very version it requires - phpstan: the extension reports errors of its own and forces stricter flags on, so some errors exist only because it is installed - assets: a Vite mapper needs an explicit path; documented the plugin options and that refresh, appUrl and host: network are not in the npm release yet - neon: spaces are valid indentation too, tabs are only a convention | | | |
| claude-code | by dg | Released version 1.1.2 | | | |
| claude-code | by dg | skills: fixed examples that fail at runtime Verified against the library sources, several of them by executing the snippet: - utils: Callback::closure() does not exist in Utils 4, Type::allowsNull() either; Json::decode() takes forceArrays (plural), Strings::findPrefix() takes one array, SmartObject needs the @property annotation - utils: corrected expected outputs of isBuiltin(), typeToExtension() and firstLower() - latte: only the first filter argument may follow a colon, the rest are comma-separated, so filter:arg1:arg2 is a CompileException; localDate and the ICU form of number require a locale; #[TemplateVariable] must be public - assets: {asset 'app.js'} renders a plain script element, type="module" only for Vite entry points - schema: Context::addError() requires the $code argument; array defaults are merged into the input, which turns a listOf default into a privilege bug on API input - database: += and -= are ?set key suffixes, not inline SQL operators - fixed two dead documentation links (database/core, best-practices/phpstan-rules) | | | |
| phpstan-rules | by dg | nette/database row type narrowing (table/related/ref/insert) Narrows return types based on a configurable table-to-entity-class mapping (nette.database.mapping.tables), which is not yet part of the nette/database distribution. Kept as the topmost commit so the whole feature can be excluded or rebased independently. Includes: - TableRowTypeResolver shared resolver - Explorer::table() -> Selection<EntityRow> - ActiveRow::related() -> GroupedSelection<EntityRow> - ActiveRow::ref() -> ?EntityRow - Selection::insert() -> mapped EntityRow | | | |
| phpstan-rules | by dg | compatibility with PHPStan 2.2.6 RemoveFailingReturnTypeExtension: DynamicReturnTypeExtensionRegistry is injected directly, the provider layer was removed from PHPStan. Tests: PHPStan reverted decimal-int-string inference for regex groups back to numeric-string. StringsRegexHelper: matchAllShape() passes wasMatched=maybe; matchAll() may return an empty list, and PHPStan now infers non-empty-list for yes. | | | |
| phpstan-rules | by dg | RemoveFailingReturnTypeExtension: strip |false from glob() Claude-Session: https://claude.ai/code/session_01YAusXLYHRUMofgyF5LHxqN | | | |
| phpstan-rules | by dg | interface @property tag support (type resolution + property.notFound suppression) PHPStan core ignores @property/@property-read tags on interfaces: the allowsDynamicProperties() gate skips annotation-based properties there, so e.g. $asset->url on Nette\Assets\Asset reports property.notFound and a custom PropertiesClassReflectionExtension is never consulted. InterfacePropertyTagTypeExtension (ExpressionTypeResolverExtension) gives such reads the annotated type (narrowed expression types and native properties win), InterfacePropertyTagIgnoreExtension suppresses the false property.notFound. Writes are intentionally left unsupported. Claude-Session: https://claude.ai/code/session_01YAusXLYHRUMofgyF5LHxqN | | | |
| phpstan-rules | by dg | suppress false argument.type on Callback::toReflection() Its @param callable is intentionally strict, but the method escalates the validity check to a ReflectionException at runtime, so a value that cannot be statically proven callable (e.g. a [class-string, method] tuple) is valid by design. New IgnoreErrorExtension matched narrowly to that single method. | | | |
| phpstan-rules | by dg | RethrowAbortExceptionRule: don't report a dedicated catch (AbortException) A catch that explicitly names AbortException (or a subtype) is a deliberate swallow, e.g. Presenter::run() ending the lifecycle. Only broad catches (\Throwable, \Exception) that swallow it incidentally are reported now. | | | |
| phpstan-rules | by dg | added AGENTS.md & DOCS | | | |
| coding-standard | by dg | OptimizeGlobalCallsSniff: fixed bogus constant imports for declared names Names declared via `const` or enum `case` were detected as global constant usages, and includedConstants patterns matched case-insensitively, so a class declaring constants like Php_LogicalOr got a nonsensical grouped `use const` import generated from the PHP_* pattern. Declared names are now skipped and constant patterns match case-sensitively (constants are case-sensitive in PHP). | | | |
| coding-standard | by dg | AGENTS.md: described the optimize-fn preset | | | |
| claude-code | by dg | hooks: project tools are searched upwards from the edited file lint-latte, lint-neon and lint-js no longer look only in the session cwd, so monorepos where the session runs above the app directory work too. The shared findUpwards() helper stops one level above the nearest .git root. On Windows, lint-latte runs the extensionless PHP script via PHP_BINARY when no .bat wrapper exists. | | | |
| mcp-inspector | by dg | added Tracy Logger WIP | | | |
| mcp-inspector | by dg | added built-in toolkits [WIP] | | | |
| mcp-inspector | by dg | added built-in DI toolkit | | | |
| mcp-inspector | by dg | added inspector | | | |
| claude-code | by dg | Released version 1.1.1 | | | |
| claude-code | by dg | improved skills fixed YAML frontmatter of three nette-dev skills | | | |
| vite-plugin | by dg | feat: add refresh option for full page reloads on template changes Latte templates and PHP live outside Vite's module graph, so editing them never triggered HMR. refresh accepts globs (e.g. 'app/**/*.latte'); when a matching file changes the plugin sends a full-reload to the browser. Since chokidar v4 dropped glob expansion, each pattern's static base dir is added to the watcher and matching is done with picomatch (new runtime dependency). | | | |
| command-line | by dg | cs | | | |
| command-line | by dg | added Console::getTerminalWidth() | | | |