Skip to content

feat: Rename to temp/fnc, curry head and tail, docblocks, phpstan level 8 - #12

Merged
temp merged 10 commits into
mainfrom
feat/curried-head-tail-docblocks-phpstan
Nov 3, 2026
Merged

temp merged 10 commits into
mainfrom
feat/curried-head-tail-docblocks-phpstan

Conversation

@temp

@temp temp commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

Follow-up to 1.0.0; expected release: 1.1.0.

Package renamed to temp/fnc

The package name now matches the Fnc namespace (fn is a PHP keyword). Switch your require from temp/fn to "temp/fnc": "^1.1"; the namespace and all functions stay the same. temp/fnc replaces temp/fn, so Composer never installs both. Versions up to 1.0 remain available as temp/fn only.

Changes

  • ascendWith/descendWith take a comparison function such as strcmp(...); ascend/descend use <=>, which compares numeric strings numerically. Allows migrating strcmp-based usort chains to sortWith() without changing the order.
  • head/tail are curried like all other list functions and also work on strings (byte-based, like last, nth, take, drop, slice). Calls with one array argument behave as before; pipe(pluck('id'), head()) now works without head(...).
  • Docblocks moved above the functions so IDEs and phpstan see them, with a Signature: line for the curried parameters and no @param/@return tags. Missing docblocks added, outdated texts fixed.
  • phpstan level 8 for src and tests. Level 9/max would flag every invocation of a partial call (invoking mixed), which is inherent to the curried API.
  • .gitattributes keeps tests, examples and tooling config out of the installed package; a LICENSE file (MIT, as declared in composer.json) is added.

Things to be aware of

  • remap(): computed keys win over record keys of the same name (with converge(merge(), [applySpec, omit]) the record key won), and an omit() after remap() runs on the result.
  • split('') throws InvalidArgumentException instead of ValueError. Code catching ValueError no longer catches it.
  • all, any, contains, equals, isEmpty, none and not declare mixed instead of bool|callable as return type. No runtime change, but static analysis in dependent projects may report new findings.

🤖 Generated with Claude Code

temp and others added 8 commits November 3, 2026 16:38
head() and tail() were the only list functions that weren't curried, so
they had to be passed as head(...) in pipelines. Both now follow the
usual pattern and, like last() and nth(), also work on strings. Calls
with one array argument behave as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The docblocks of most functions were inside the function body, where
IDEs and phpstan don't see them. They are now regular docblocks with a
"Signature:" line for the curried parameters. @param/@return tags of the
inner closures are dropped, as they don't match the real `mixed ...$args`
signature and a narrower @return would be wrong for partial calls.

Also adds docblocks to the functions that had none and fixes outdated
texts (map, filter, prop, drop, take, always).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Curried functions that returned bool|callable (all, any, contains,
  equals, isEmpty, none, not) now declare mixed like the others; the
  union didn't help callers and made every invocation of a partial call
  an error.
- Internal closures typed as bool no longer return equals()/not() results
  of type bool|callable.
- split() throws InvalidArgumentException for an empty separator instead
  of explode()'s ValueError.
- Tests: typed helper classes, removed an assertion that is always true.

Level 9 and max would flag every call of a curried function's result
(invoking mixed), which is inherent to the curried API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The package name now matches the Fnc namespace. "fn" would have been
nicer, but it's a PHP keyword (`use Fn;` is a syntax error). The
namespace and all functions stay the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also documents that string handling in head, tail, last, nth, take, drop
and slice is byte-based.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
composer.json already declares MIT; the file was missing in the repo and
the package.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both packages autoload src/functions.php with the same Fnc namespace;
installing both would fail with "Cannot redeclare function".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@temp temp changed the title feat: Curry head and tail, docblocks above functions, phpstan level 8 feat: Rename to temp/fnc, curry head and tail, docblocks, phpstan level 8 Nov 3, 2026
@temp
temp force-pushed the feat/curried-head-tail-docblocks-phpstan branch from 4c5c112 to bf9b932 Compare November 3, 2026 15:54
temp and others added 2 commits November 3, 2026 16:57
Feedback from migrating 4wheels-api to 1.0:
- ascend/descend compare with <=>, which compares numeric strings
  numerically ('9999' < '10000'). ascendWith/descendWith take a
  comparison function, e.g. strcmp(...), so strcmp-based usort chains
  can be migrated to sortWith() without changing the order.
- remap: an omit() after remap() runs on the result, and unlike the
  former converge(merge(), [applySpec, omit]) pattern the computed keys
  win over record keys of the same name. Documented in the docblock,
  README and CLAUDE.md.

Examples now also cover all, ascend and descend.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The comparison function's result is normalised with <=> 0, as usort()
accepts any number or a bool; previously the int return type threw a
TypeError. Documents that strcmp(...) needs string values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@temp
temp merged commit 846d111 into main Nov 3, 2026
5 checks passed
@temp
temp deleted the feat/curried-head-tail-docblocks-phpstan branch November 3, 2026 16:00
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 1.1.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant