0.4.0
Five new checks ported from credence anti-pattern rules, adapted to integrate with the standard Credo runner (so credo:disable-for-* comments work and the rules participate in mix credo --strict):
ForgeCredoChecks.InconsistentParamNames: flags multi-clause functions where the same positional argument has different base names across clauses (e.g.currentin one clause,previn another). Drift makes readers question correctness. Literal and destructuring patterns at a position cause that position to be skipped.ForgeCredoChecks.NoKernelShadowing: flags=/fn/defbinding sites that shadow commonKernelfunctions (max,min,length,elem,hd,tl,abs,round,trunc,div,rem,tuple_size,map_size,byte_size,bit_size). Calls likemax(max, other)become ambiguous to readers — rename the variable.ForgeCredoChecks.NoUnnecessaryCatchAllRaise: flagsdef/defpclauses where every argument is a wildcard AND the body is exactlyraise(...). Elixir's built-inFunctionClauseErroralready names the function and the failing arguments — a hand-written catch-all that raises a hardcoded message throws that signal away.ForgeCredoChecks.NoCaseTrueFalse: flagscase <bool_expr> do true -> ...; false -> ... end(and variants with_as one clause). Theif/elseform makes the truthy branch obvious without a clause-scan.caseon a plain variable is NOT flagged — that's typically a legitimate tristate match.ForgeCredoChecks.NoKernelOpInPipeline: flagspipeline |> Kernel.<op>(arg)for comparison and boolean operators (==,!=,===,!==,<,>,<=,>=,and,or). Use the operator in infix position. Arithmetic operators (+,-,*,/) are NOT flagged — they have legitimate uses in pipelines.
Auto-fix is NOT implemented for any of these checks; credo doesn't run auto-fixers, and source mutation introduces risk that's better handled by the operator at each call site.
0.3.0
Three new checks codifying conventions for the with macro:
ForgeCredoChecks.WithBareBinding: every clause in awithchain must use<-, never=. Smuggled=bindings bypass the fall-through control flow that giveswithits purpose.ForgeCredoChecks.WithElseClauses: flagswithblocks whoseelseexceeds:max_clauses(default1, configurable). Wideelseblocks become dispatch tables on step-specific error shapes; normalize each step's return in a helper instead.ForgeCredoChecks.WithResultTag: flags<-clauses whose atom-tagged LHS is outside:allowed_atoms(default[:ok, :error], configurable). Codebases that use richer control-flow vocabulary (:found,:retry,:locked) extend the allowlist rather than disabling the check.
Check feedback rewritten for agent readers:
- Messages now lead with "Replace X with Y" instead of passive descriptions like "X is more efficient than Y", so an LLM reading a Credo issue gets a concrete edit instruction.
- Every explanation got a
## Why / ## How to fix / ## What NOT to dostructure with concrete BEFORE/AFTER snippets. - The four
Enum-chain checks (MapReject,MapRejectNil,FilterMap,RejectMap) now recommend comprehensions first,Enum.flat_map/2second (where the transform is naturally 0-or-more), andEnum.reduce/3only as a last resort. Thereduce + reversepattern is explicitly called out as an anti-pattern: paying a second pass just to undo the order an accumulator imposed is exactly the tax comprehensions exist to avoid.
0.2.0
First Hex release.
Adds four checks beyond the original two-pass Enum chain set:
ForgeCredoChecks.MapNewFromInto:Enum.map |> Enum.into(%{}, ...)becomesMap.new/2ForgeCredoChecks.MapNewFromReduce:Enum.reduce(_, %{}, &Map.put(acc, k, v))becomesMap.new/2ForgeCredoChecks.ReverseListFirst:xs |> Enum.reverse() |> List.first()becomesList.last(xs)ForgeCredoChecks.SortListFirst:Enum.sort |> List.firstbecomesEnum.min/Enum.max/*_by
Carried over from 0.1.x:
ForgeCredoChecks.FilterMap:Enum.filter |> Enum.mapForgeCredoChecks.RejectMap:Enum.reject |> Enum.mapForgeCredoChecks.MapReject:Enum.map |> Enum.rejectForgeCredoChecks.MapRejectNil:Enum.map |> Enum.reject(&is_nil/1)