| claude-code | by dg | php-fixer: added the dresscode skill on running and configuring DressCode The skill covers DressCode run on purpose, beyond the edited file the hook fixes: the commands and exit codes, reading the report, risky fixes and what decides them, suppressions, the baseline, CI and Git hooks, and what needs the user's consent. It leans on the tool's own explain, config and catalogue instead of bundling the manual; the configuration and the upgrades to newer PHP and library versions are in its references. php-auto-fixer points to it. | | | |
| command-line | by dg | Prompt: the default choice stands out in white where the console has colors A capital marked the default, which a digit does not have, so in [1/2] the default could not be told. b65ee535-a726-4a86-868b-c52fc150b75b | | | |
| eslint-plugin | by dg | released version 0.4.0 | | | |
| eslint-plugin | by dg | fixed and expanded readme - TypeScript install no longer lists typescript-eslint (it is a direct dependency); only the typescript compiler is needed. - customize() docs now separate the base entry (browser/jsx) from the /typescript entry (which adds typescript). - the Latte example registers the @nette plugin so processor '@nette/latte' resolves. - documented the previously undocumented processor configuration (replacementFunction / removeLatteErrors). | | | |
| eslint-plugin | by dg | fixed suggestions in Latte templates pointing to wrong positions The processor remapped a message's position and its fix, but left the ranges of its suggestions in the coordinates of the processed code, so past the first tag an editor applied them at the wrong place. They are now mapped like the fix, and a suggestion whose fix reaches into a Latte tag is dropped. c68af278-2ee3-4de8-b8a9-b7100137c8ff | | | |
| eslint-plugin | by dg | fixed autofix corrupting Latte tags A fix whose range reached into a Latte tag was mapped onto the original template, but its text had been computed from the placeholder, so it rewrote the Latte code: no-extra-parens turned `({$y})` into `[1]` and no-multiple-empty-lines deleted `{/if}`. Such a fix is now dropped and only the problem is reported. That covers a fix overlapping a placeholder and one touching the position of a removed tag, where it is ambiguous on which side of the tag it belongs. Messages before the first tag were passed through unmapped, so a fix starting there and spanning the tag escaped any mapping; they now take the same path, which leaves their positions as they are. c68af278-2ee3-4de8-b8a9-b7100137c8ff | | | |
| eslint-plugin | by dg | corrected the Latte processor docs AGENTS.md and internals described per-file contexts in a Map and a fix-range end mapped to the end of the tag, neither of which the code does or should do. ESLint calls postprocess right after the preprocess of the same file, so files never interleave, and mapping a fix-range end to the end of the tag would make an insertion right before a tag (space-infix-ops turning `x={$y}` into `x = {$y}`) delete it. AGENTS.md also named configs.latte and configureLatte(), which do not exist; the processor is configured by its configure(). | | | |
| eslint-plugin | by dg | added meta.name to the Latte processor ESLint needs it to serialize a config that passes the processor object itself rather than the '@nette/latte' string, as --cache and --print-config do. | | | |
| eslint-plugin | by dg | added support for Latte comments {* *} in the processor Latte comments were left untouched and broke the extracted JavaScript. They are now stripped (both {* *} and the double-brace {{* *}} form), including comments that contain tag-like content: both tag regexes match a whole comment first, so a tag inside it is never picked up. | | | |
| eslint-plugin | by dg | added docs URLs to rules Both rules point meta.docs.url at their readme sections. | | | |
| eslint-plugin | by dg | renamed rule file to match the rule name no-this-in-arrow-except-nested.js -> no-this-in-arrow-except.js, so the file name matches the `@nette/no-this-in-arrow-except` rule id. The package `exports` map only exposes the two entry points, so deep imports were never part of the public API. | | | |
| eslint-plugin | by dg | fixed no-this-in-arrow-except false positives `this` inside an arrow now correctly resolves through class field initializers, static blocks and object/member methods: - `class Foo { handler = () => this.x }` (bound-method pattern), - `class Foo { static { arr.map(() => this.x) } }`, - `const o = { foo() { arr.map(() => this.x) } }`, - `() => class { x = this.y }`, where `this` is not the arrow's at all. Arrows used as object-literal property values still report, because there `this` is the outer scope, not the object. | | | |
| eslint-plugin | by dg | fixed prefer-line-comments corrupting code The autofix blindly rewrote a block comment to //, which: - swallowed code following the comment on the same line (`a; /* c */ b;` became `a; // c b;`), - broke ESLint directives (`/* eslint-disable */`) and tooling annotations (webpack/vite magic comments, `#__PURE__`, `@license`, preserved-license `/*! */`). Such comments are now left untouched. | | | |
| eslint-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 and package.json declares engines >= 22.13.0, the floor ESLint 10 itself has on the 22 line. Also bumped actions/setup-node from v4 to v7. | | | |
| eslint-plugin | by dg | removed package-lock.json from version control npm never publishes the lock file, so it only ever affected local development and CI, not consumers of the package. Like composer.lock in a PHP library, it now stays on disk but out of git, so CI resolves dependencies the same way a user of the package does and breaking releases surface early. Without the lock file CI installs with `npm install` instead of `npm ci`, and setup-node no longer caches npm, as both need it. | | | |
| 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 | old Nette class names kept as aliases are reflected as the classes they stand for | | | |
| phpstan-rules | by dg | TypeAssert: opcache is switched off before analysis A type test could see *ERROR* in place of a perfectly declared type, and whether it did depended on which other tests happened to run beside it. In nette/http, TypesTest failed under php-cgi on Windows only when run in parallel with a test that touched FileUpload: getImageSize() declared as ?array{int, int} came out as *ERROR*. Alone, with -j 1, under the CLI or with opcache disabled it passed. The cause lies in how PHPStan finds the source of a class. For a class outside the analysed paths, its AutoloadSourceLocator calls the autoloader under FileReadTrapStreamWrapper, a stream wrapper that intercepts the include, records the path and returns empty content, so the file is never executed. Opcache defeats the trap: a script it already has in the cache is served without the file being opened, the wrapper never sees the read and the file really runs. Its class gets defined natively in the middle of the analysis, and any trait or parent it needs is in turn loaded under the trap, which fails (here "Trait Nette\SmartObject not found"), so the reflection breaks and the type becomes *ERROR*. Why it looked random: the CLI usually has opcache off (opcache.enable_cli), while php-cgi has it on by the php.ini. On Windows the opcache memory is shared by the php-cgi processes that run at the same time, so a script is already cached in the test that analyses it exactly when a parallel test has loaded it first. Calling opcache_compile_file() on the file before assertTypes() reproduces it deterministically in a single process. Opcache can be switched off at runtime (only off, never on), and once off the scripts are compiled from the files again, so the trap works. It is done in createContainer(), the common entry of every assertion, before anything is analysed. | | | |
| phpstan-rules | by dg | CI: DressCode checks with the dependencies installed Without vendor/ it knows nothing of the classes of the libraries, so a call of a deprecated method passes unnoticed. | | | |
| command-line | by dg | Runner: added, which runs the program in the process: help, version, usage errors and the exit code It adds --help with -h and, given a version, --version with -V, placed with the options of the program, a flag of that name the program has being answered as it is. A usage error is printed with the help of its command and returns 2 by default. On request it prints the help for an empty line (helpWhenEmpty, before the required arguments are demanded), adds --no-color, read before parsing so that a mistake of the line is plain too (colorFlag), and reports an exception of the handler by its message (errorExitCode). A version may be a closure writing it for the console it goes to. | | | |
| command-line | by dg | CI: DressCode checks with the dependencies installed Without vendor/ it knows nothing of the classes of the libraries, so a call of a deprecated method passes unnoticed. | | | |
| mcp-inspector | by dg | fixed server ending by itself after 13.5 hours without input on Windows PHP on Windows waits for data on a pipe in a loop of 3,200,000 usleep(10) calls, also in non-blocking mode. One call takes about 15 ms there, so fgets() on an idle pipe blocks for about 13.5 hours and then reports a false EOF, which ends the server with exit code 0 and no error. mcp/sdk calls fgets() on an idle pipe, so the transport now reads only after stream_select() reports input. It needs PHP 8.5, as stream_select() on Windows reports an idle pipe as readable before that. The run loop then also runs on an idle connection, and mcp/sdk 0.9 only reads the session there, so the first read past its TTL of an hour deletes it and every later request gets "Session not found or has expired" without an id. A stdio session lasts as long as the process, so the server gives it no TTL. See php/php-src#25204, modelcontextprotocol/php-sdk#671 and modelcontextprotocol/php-sdk#672. | | | |
| mcp-inspector | by dg | uses the Runner of nette/command-line | | | |
| mcp-inspector | by dg | added AGENTS.md | | | |
| mcp-inspector | by dg | added Tracy toolkit: log files by level and exception report summaries | | | |
| mcp-inspector | by dg | added DI container toolkit: services, autowiring, tags, aliases and masked parameters over Container::getServiceDescriptors() | | | |
| mcp-inspector | by dg | added database toolkit: schema introspection and db_query with read-only policy enforced by validation and a read-only transaction | | | |
| mcp-inspector | by dg | added router toolkit: routes, URL matching and link generation | | | |
| mcp-inspector | by dg | added presenters toolkit: the mapping, presenters found on disk with their actions, and presenter details | | | |
| mcp-inspector | by dg | added application toolkit: app_get_info with versions, packages, directories and database driver | | | |
| mcp-inspector | by dg | added installer command The command line is built on nette/command-line 2.0: init and call are real commands, call has its tool and JSON as arguments, an extra word or an unknown command is refused by the parser, --php belongs to init, and the help of each command lists its own options apart from the global ones. What a person reads goes through a Console of the library, one over stdout and one over stderr, so a redirected stdout does not decide the colors of stderr and an error is red where the terminal takes it. Nothing echoes, which is what keeps stdout clean while the MCP protocol runs over it, and the help draws into the same console instead of building one of its own. | | | |
| mcp-inspector | by dg | added inspector core: own DI container, live-reloading AppContainer, Server Server::call() passes stdClass when a tool has no arguments, as SchemaValidator of mcp/sdk validates an empty array as a JSON array, which an input schema of type object rejects. | | | |