CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-listr2

Terminal task list library for creating beautiful, interactive CLI interfaces with task management, rendering options, and error handling.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

renderers.mddocs/

Renderers

Multiple built-in renderers for different environments and use cases, with customizable options, TTY detection, and fallback mechanisms for various output scenarios.

Capabilities

Renderer Selection

Configure primary and fallback renderers with automatic selection based on environment conditions.

/**
 * Valid renderer specification values
 */
type ListrRendererValue = 
  | 'default' 
  | 'simple' 
  | 'verbose' 
  | 'test' 
  | 'silent'
  | ListrRendererFactory;

/**
 * Renderer configuration in Listr options
 */
interface ListrBaseClassOptions<Ctx, Renderer, FallbackRenderer> {
  /** Primary renderer to use */
  renderer?: Renderer;
  /** Fallback renderer when primary is unavailable */
  fallbackRenderer?: FallbackRenderer;
  /** Options for the primary renderer */
  rendererOptions?: ListrGetRendererOptions<ListrGetRendererClassFromValue<Renderer>>;
  /** Options for the fallback renderer */
  fallbackRendererOptions?: ListrGetRendererOptions<ListrGetRendererClassFromValue<FallbackRenderer>>;
  /** Condition to determine when to use fallback renderer */
  fallbackRendererCondition?: boolean | (() => boolean);
  /** Condition to determine when to use silent renderer */
  silentRendererCondition?: boolean | (() => boolean);
}

Default Renderer

Feature-rich renderer with spinners, colors, and interactive display elements. Requires TTY environment.

/**
 * Default renderer with rich interactive features
 * Requires TTY environment for full functionality
 */
class DefaultRenderer extends ListrRenderer {
  /** Indicates this renderer requires TTY */
  static nonTTY: false;
  
  /** Default renderer options */
  static rendererOptions: {
    /** Indentation settings */
    indentation?: number;
    /** Clear output on completion */
    clearOutput?: boolean;
    /** Show subtasks */
    showSubtasks?: boolean;
    /** Collapse finished tasks */
    collapse?: boolean;
    /** Collapse errors */
    collapseErrors?: boolean;
    /** Show error stack traces */
    showErrorMessage?: boolean;
    /** Suffix for task titles */
    suffixSkips?: boolean;
    /** Show skip messages */
    suffixRetries?: boolean;
    /** Show retry messages */
    lazy?: boolean;
    /** Lazy rendering mode */
    removeEmptyLines?: boolean;
    /** Format output lines */
    formatOutput?: 'truncate' | 'wrap';
  };
  
  /** Task-specific options */
  static rendererTaskOptions: {
    /** Show output bar */
    outputBar?: number;
    /** Persistent output */
    persistentOutput?: boolean;
    /** Bottom bar for persistent output */
    bottomBar?: boolean | number;
  };
}

Simple Renderer

Basic text-based renderer suitable for CI/CD environments and non-TTY outputs.

/**
 * Simple renderer for basic text output
 * Works in both TTY and non-TTY environments
 */
class SimpleRenderer extends ListrRenderer {
  /** Indicates this renderer works without TTY */
  static nonTTY: true;
  
  /** Simple renderer options */
  static rendererOptions: {
    /** Prefix character for tasks */
    prefixWithTimestamp?: boolean;
    /** Add timestamps to output */
    logEmptyTitle?: boolean;
    /** Log tasks with empty titles */
    logTitleChange?: boolean;
  };
}

Verbose Renderer

Detailed logging renderer with timestamps and comprehensive output information.

/**
 * Verbose renderer with detailed logging and timestamps
 * Works in both TTY and non-TTY environments
 */
class VerboseRenderer extends ListrRenderer {
  /** Indicates this renderer works without TTY */
  static nonTTY: true;
  
  /** Verbose renderer options */
  static rendererOptions: {
    /** Show timestamps */
    logEmptyTitle?: boolean;
    /** Log tasks with empty titles */
    logTitleChange?: boolean;
    /** Log title changes */
    useIcons?: boolean;
    /** Use icons in output */
    fields?: {
      /** Configure timestamp field */
      timestamp?: any;
      /** Configure other logging fields */
      [key: string]: any;
    };
  };
}

Test Renderer

Specialized renderer for testing scenarios with serialized output and programmatic access.

/**
 * Test renderer for testing scenarios
 * Provides serialized output for programmatic access
 */
class TestRenderer extends ListrRenderer {
  /** Test renderer options */
  static rendererOptions: {
    /** Serialize test results */
    serialize?: boolean;
    /** Log level for test output */
    logLevel?: 'silent' | 'error' | 'warn' | 'info' | 'verbose';
  };
  
  /** Get serialized test results */
  getTestResults(): any[];
}

Silent Renderer

Completely silent renderer that produces no output, useful for background operations.

/**
 * Silent renderer that produces no output
 * Useful for background operations and scripting
 */
class SilentRenderer extends ListrRenderer {
  /** Silent renderer has no configurable options */
  static rendererOptions: {};
  
  /** Silent renderer has no task options */
  static rendererTaskOptions: {};
}

Base Renderer Interface

Abstract base class that all renderers must implement.

/**
 * Abstract base class for all renderers
 */
abstract class ListrRenderer {
  /** Default renderer-level options */
  static rendererOptions: Record<PropertyKey, any>;
  /** Default task-level options */
  static rendererTaskOptions: Record<PropertyKey, any>;
  /** Whether renderer works without TTY */
  static nonTTY: boolean;

  /**
   * Create a new renderer instance
   * @param tasks - Array of tasks to render
   * @param options - Renderer options
   * @param events - Event manager for listening to task events
   */
  constructor(
    tasks: Task[],
    options: Record<PropertyKey, any>,
    events?: ListrEventManager
  );

  /**
   * Start rendering the task list
   * @returns Promise that resolves when rendering starts
   */
  abstract render(): void | Promise<void>;

  /**
   * End rendering and clean up
   * @param err - Optional error that caused rendering to end
   */
  abstract end(err?: Error): void;
}

/**
 * Renderer factory function type
 */
type ListrRendererFactory = new (
  tasks: Task[],
  options: Record<PropertyKey, any>,
  events?: ListrEventManager
) => ListrRenderer;

Usage Examples:

Basic Renderer Configuration

import { Listr, DefaultRenderer, SimpleRenderer } from "listr2";

// Use default renderer (automatic TTY detection)
const tasks1 = new Listr([
  { title: "Task 1", task: () => Promise.resolve() }
]);

// Explicitly specify renderer
const tasks2 = new Listr([
  { title: "Task 2", task: () => Promise.resolve() }
], {
  renderer: 'default',
  fallbackRenderer: 'simple'
});

// Force specific renderer
const tasks3 = new Listr([
  { title: "Task 3", task: () => Promise.resolve() }
], {
  renderer: 'verbose'
});

Renderer Options Configuration

import { Listr } from "listr2";

// Default renderer with custom options
const tasks = new Listr([
  { title: "Task with custom rendering", task: () => Promise.resolve() }
], {
  renderer: 'default',
  rendererOptions: {
    indentation: 4,
    showSubtasks: true,
    collapse: false,
    collapseErrors: false,
    showErrorMessage: true,
    formatOutput: 'wrap'
  }
});

// Simple renderer with timestamps
const simpleTasks = new Listr([
  { title: "Simple task", task: () => Promise.resolve() }
], {
  renderer: 'simple',
  rendererOptions: {
    prefixWithTimestamp: true,
    logEmptyTitle: false,
    logTitleChange: true
  }
});

Conditional Renderer Selection

import { Listr } from "listr2";

// Use different renderers based on environment
const tasks = new Listr([
  { title: "Environment-aware task", task: () => Promise.resolve() }
], {
  renderer: 'default',
  fallbackRenderer: 'simple',
  // Use simple renderer in CI environments
  fallbackRendererCondition: () => process.env.CI === 'true',
  // Use silent renderer when QUIET flag is set
  silentRendererCondition: () => process.env.QUIET === 'true'
});

Task-Specific Renderer Options

import { Listr } from "listr2";

const tasks = new Listr([
  {
    title: "Task with persistent output",
    task: (ctx, task) => {
      // This task will show persistent output at bottom
      task.output = "Processing...";
      return new Promise(resolve => {
        setTimeout(() => {
          task.output = "Completed!";
          resolve(undefined);
        }, 2000);
      });
    },
    rendererOptions: {
      persistentOutput: true,
      bottomBar: true
    }
  },
  {
    title: "Task with output bar",
    task: () => Promise.resolve(),
    rendererOptions: {
      outputBar: 10 // Show 10 lines of output
    }
  }
]);

Testing with Test Renderer

import { Listr } from "listr2";

// Create task list with test renderer
const tasks = new Listr([
  { title: "Test task 1", task: () => Promise.resolve() },
  { title: "Test task 2", task: () => Promise.reject(new Error("Test error")) }
], {
  renderer: 'test',
  rendererOptions: {
    serialize: true,
    logLevel: 'verbose'
  }
});

try {
  await tasks.run();
} catch (error) {
  // Access serialized test results
  const testResults = tasks.renderer.getTestResults();
  console.log("Test results:", testResults);
}

Custom Renderer Factory

import { Listr, ListrRenderer } from "listr2";

// Create custom renderer class
class CustomRenderer extends ListrRenderer {
  static nonTTY = true;
  static rendererOptions = {
    customOption: 'default-value'
  };

  render() {
    console.log("Custom renderer started");
  }

  end(err?: Error) {
    if (err) {
      console.log("Custom renderer ended with error:", err.message);
    } else {
      console.log("Custom renderer completed successfully");
    }
  }
}

// Use custom renderer
const tasks = new Listr([
  { title: "Custom rendered task", task: () => Promise.resolve() }
], {
  renderer: CustomRenderer,
  rendererOptions: {
    customOption: 'custom-value'
  }
});

Renderer Utility Functions

import { getRenderer, getRendererClass } from "listr2";

// Get appropriate renderer based on conditions
const rendererInfo = getRenderer({
  renderer: 'default',
  fallbackRenderer: 'simple',
  fallbackRendererCondition: () => !process.stdout.isTTY,
  silentRendererCondition: () => process.env.SILENT === 'true'
});

console.log("Selected renderer:", rendererInfo.selection);
console.log("Renderer class:", rendererInfo.renderer);
console.log("Renderer options:", rendererInfo.options);

// Get renderer class from string value
const RendererClass = getRendererClass('verbose');

Types

/**
 * Renderer selection state
 */
enum ListrRendererSelection {
  PRIMARY = 'PRIMARY',
  SECONDARY = 'SECONDARY',
  SILENT = 'SILENT'
}

/**
 * Supported renderer information
 */
interface SupportedRenderer {
  renderer: ListrRendererFactory;
  options: Record<PropertyKey, any>;
  selection: ListrRendererSelection;
}

/**
 * Generic renderer options type helpers
 */
type ListrGetRendererClassFromValue<T extends ListrRendererValue> = 
  T extends ListrRendererFactory ? T : 
  T extends 'default' ? typeof DefaultRenderer :
  T extends 'simple' ? typeof SimpleRenderer :
  T extends 'verbose' ? typeof VerboseRenderer :
  T extends 'test' ? typeof TestRenderer :
  T extends 'silent' ? typeof SilentRenderer :
  never;

type ListrGetRendererOptions<T extends ListrRendererFactory> = 
  T extends { rendererOptions: infer R } ? R : Record<PropertyKey, any>;

type ListrGetRendererTaskOptions<T extends ListrRendererFactory> = 
  T extends { rendererTaskOptions: infer R } ? R : Record<PropertyKey, any>;

/**
 * Environment detection utilities
 */
interface RendererEnvironment {
  /** Whether current environment supports TTY */
  isTTY: boolean;
  /** Whether current environment supports Unicode */
  isUnicode: boolean;
  /** Whether colors are supported */
  supportsColor: boolean;
}

docs

error-handling.md

event-management.md

index.md

renderers.md

task-configuration.md

task-management.md

tile.json