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

Fab Laravel Package

whatthejeff/fab

A lightweight functional programming library for PHP by Jeff Welch, offering helpers for currying, partial application, and function composition so you can build cleaner, more reusable code with less boilerplate.

Deep Wiki
Context7

Getting Started

Fab is a small, framework-agnostic PHP library that wraps strings in ANSI escape sequences, letting you build styled terminal output with a chainable API. It ships no Laravel service provider, config, or facade — you pull it in with Composer and call it directly.

composer require whatthejeff/fab

A first, minimal use inside an Artisan command:

use function Fab\fab;

class ReportCommand extends Command
{
    protected $signature = 'report:run';

    public function handle()
    {
        $this->line((string) fab('Deploy complete')->white()->bgGreen()->bold());
    }
}

Where to look first, in order:

  1. The README for the canonical entry point — the package exposes both a shorthand function (fab()) and underlying formatter classes, and the docs are thin enough that the README plus src/ is the real reference.
  2. src/ for the modifier methods available (foreground/background colors, bold, underline, blink, reverse, etc.) — there is no generated API reference.
  3. tests/ for expected output shape; it doubles as the most reliable spec of what each modifier emits.

First productive use case: a "status" line in a long-running console command, where you want [ OK ], [WARN ], and [FAIL ] prefixes to be visually scannable and to carry a background color, not just a foreground change.

Implementation Patterns

Wrap the dependency in one helper. Because the API surface is small and the package is lightly maintained, isolating it behind a single class means a future swap (or a fallback to Symfony's OutputFormatter) is a one-file change.

namespace App\Support;

final class Status
{
    public static function ok(string $msg): string
    {
        return (string) fab(" {$msg} ")->black()->bgGreen()->bold();
    }

    public static function fail(string $msg): string
    {
        return (string) fab(" {$msg} ")->white()->bgRed()->bold();
    }
}

Call Status::ok('migrated') from commands instead of chaining fab() inline everywhere.

Chain, then cast once. The fluent object is a value object with __toString(); concatenating it in a larger string works, but explicit (string) casts keep intent obvious and avoid subtle issues when passing to functions typed string.

$line = sprintf('%s %s', Status::ok('OK'), 'cache warmed');
$this->line($line);

Compose with Symfony Console output, don't replace it. Laravel's $this->info() / $this->error() already call into Symfony's styled formatter. Use Fab where you want richer combinations — background colors with foreground contrast, reverse video for headers, multi-style banners — and leave plain verbosity-style messages to Laravel's helpers. Mixing both in one command is fine; they emit the same class of escape codes.

Guard for non-decorated output. Before emitting styled strings, respect the output's own decision about color:

if ($this->output->isDecorated()) {
    $this->line(Status::ok('done'));
} else {
    $this->line('[ OK ] done');
}

This covers --no-ansi, redirection to a file, CI runners with no TTY, and cron.

Testing. Buffer the command output and normalize before asserting:

$output = new BufferedOutput;
Artisan::call('report:run', [], $output);

$plain = preg_replace('/\e\[[0-9;]*m/', '', $output->fetch());
$this->assertStringContainsString('[ OK ]', $plain);

Asserting on the raw escape sequences couples your tests to Fab's exact byte output and to whichever modifiers you happened to chain.

Gotchas and Tips

  • Escape codes leak everywhere unless you guard them. Fab has no idea whether stdout is a terminal. Anything written to a log file, an email, a JSON response, or a piped command will contain raw \e[...m sequences. Always route Fab output through a decorated check as above.
  • NO_COLOR and TERM=dumb conventions. Fab predates widespread adoption of these, so it won't honor them itself. If you wrap it in a helper, check getenv('NO_COLOR') there once and return the plain string.
  • Windows / older terminals. ANSI support is not universal on legacy cmd.exe. Modern Windows Terminal and ConEmu are fine; if you support old Windows CI, fall back to plain text via the same isDecorated() path.
  • Function import is easy to get wrong. If you use the shorthand, it's use function Fab\fab;, not use Fab\fab;. If your autoloader or tooling complains, instantiate the formatter class directly — behavior is identical, and this avoids depending on autoload.files being present.
  • Don't nest styled objects. Applying a background to an already-background-styled string produces stacked, reset-ending sequences that can bleed into subsequent output on some terminals. Style the final plain string once, at the leaf.
  • reset semantics. Every styled string should end with a reset; if you build strings by substr or sprintf with %s truncation, you can cut off the trailing reset and tint the rest of the terminal. Keep styled values as whole lines.
  • Not suited to HTTP output. This is terminal-only. Nothing here belongs in a Blade view, an API response, or a queued job's log channel without stripping.
  • Maintenance risk is real. Low stars and no recent activity mean the class may not track PHP version changes forever. The library is small enough to vendor a copy into app/Support if you'd rather not carry the dependency; the wrapper pattern above makes that swap trivial.
  • Evaluate whether you need it at all. If your needs are foreground colors and bold only, Symfony's <info>/<comment>/<error> tags cover it with zero dependencies. Fab earns its place when you want backgrounds, reverse video, and long modifier chains without writing escape codes by hand.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource