formatting

package
v1.0.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 7, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package formatting provides product-agnostic table view policies on top of the framework output primitives.

Index

Constants

This section is empty.

Variables

View Source
var GlobalColumnPriority = []string{
	"id", "key", "work_item_id", "work_item_type_key",
	"name", "title", "subject", "display_name",
	"state", "status", "state_key",
	"owner", "assignee", "created_by", "user_key",
	"email",
	"created_at", "updated_at", "finish_time",
}

GlobalColumnPriority is the seed priority list for auto-column-selection when the user does not pass --select. Hits come first in priority order; remaining keys are appended alphabetically up to the column cap.

Functions

func DefaultProcessor

func DefaultProcessor() *frameworkoutput.Processor

DefaultProcessor assembles the full output pipeline for a product: select → envelope → composite formatter (json/ndjson/table) → stdio writer. Products should use this instead of pkg/framework/output/formatter.DefaultProcessor() when they want table rendering.

No implicit wrapper-array unwrap happens in the hook chain — every format receives the raw response so metadata siblings (total, pagination, ...) are preserved. Users drill into wrapped records explicitly via --select=KEY or --select=KEY.field, where the FieldSelectorHook broadcasts the remaining path over array elements when needed. CompositeFormatter still applies a loss-less single-key peel before table/ndjson rendering so {"list":[...]} alone still renders as rows.

func Normalize

func Normalize(data any) any

Normalize unwraps json.RawMessage / []byte to native Go values.

func RenderCell

func RenderCell(v any, maxWidth int) string

RenderCell returns the table-cell string for an arbitrary value.

Rules (matching the design spec §格式行为规约 > table):

  • nil → ""
  • string/number/bool → Sprint, truncated by maxWidth
  • primitive-only arrays → comma-joined, truncated
  • objects and mixed/object arrays → compact JSON, bracket-balanced truncation

maxWidth <= 0 disables truncation.

func ResolveColumns

func ResolveColumns(row map[string]any, selected []string, maxCols int, priority []string) []string

ResolveColumns picks the final column order for a row.

  • If selected is non-empty, that list is used verbatim (honoring user intent).
  • Otherwise: priority hits (in priority order) come first; remaining keys are appended in alphabetical order. Result is capped at maxCols.

func TruncateBalanced

func TruncateBalanced(s string, maxWidth int) string

TruncateBalanced shortens a rendered string to at most maxWidth runes.

  • Strings not starting with '{' or '[' are tail-truncated with '…'.
  • Objects/arrays are truncated between top-level items when possible: the result stays a well-formed JSON literal whose final character is the closing bracket, with a trailing ",…]" / ",…}" to flag truncation.
  • If even one top-level item does not fit within budget (e.g. a single long object inside a cell narrower than the object), we fall back to plain tail-truncation so the user still sees content. That violates the "always valid JSON" guarantee but is preferable to emitting a deceptively empty "[]" or "{}".

maxWidth <= 0 or short input → returned unchanged.

func UnwrapWrapperObject

func UnwrapWrapperObject(data any) any

UnwrapWrapperObject performs loss-less drill-in before table/ndjson rendering so that single-wrapper payloads render naturally:

  • Single-key map whose value is []any → returns the []any (e.g. {"list":[...]} → [...]).
  • Single-key map whose value is a map[string]any → returns the inner map, and repeats (e.g. {"creator":{"name":"alice","email":"x"}} → {"name":"alice","email":"x"}).

Peeling is strictly loss-less: it stops as soon as the current map has zero or more than one key, so {"list":[...], "total":N} is never peeled — metadata siblings are preserved and the renderer shows the outer KV/structure. Scalar values under a single key are also left alone so {"creator":"alice"} stays a KV row instead of collapsing into "alice".

Types

type CompositeFormatter

type CompositeFormatter struct {
	Base  frameworkoutput.Formatter
	Table TableView
}

CompositeFormatter dispatches by FormatOptions.Mode:

  • "table" → TableView.Encode (after wrapper-array unwrap)
  • "ndjson" → Base.Format (after wrapper-array unwrap)
  • "json" / "" → Base.Format (pass-through, no unwrap)
  • anything else → user-facing error listing the supported set

Unwrap rationale: most MCP list responses arrive as {"list": [...]} / {"data": [...]} wrappers. For ndjson and table the wrapper hides the records users want to stream/tabulate, so we peel it; json stays faithful so existing scripts reading .list[0] keep working. When --envelope is on, we do NOT unwrap (the envelope itself is a {data, meta, error} wrapper and that is exactly what the user asked to see).

Error-envelope rendering (FormatOptions.ErrorEnvelope=true) takes priority over everything above: no unwrapping, and table mode renders the inner `error` record as a KV table with code/message/retryable rows per the design spec §"错误处理契约".

func NewComposite

func NewComposite(base frameworkoutput.Formatter, table TableView) CompositeFormatter

NewComposite wires a base framework Formatter and a TableView into a single Formatter usable by frameworkoutput.Processor.

func (CompositeFormatter) Format

func (c CompositeFormatter) Format(data any, opts *frameworkoutput.FormatOptions) ([]byte, error)

type DataShape

type DataShape int

DataShape classifies an arbitrary payload for table rendering.

const (
	ShapeEmpty DataShape = iota
	ShapePrimitive
	ShapeObject
	ShapePrimitiveArray
	ShapeObjectArray
	ShapeMixedArray
)

func DetectShape

func DetectShape(data any) DataShape

DetectShape inspects data and returns its shape. Inputs wrapped as json.RawMessage or []byte are decoded first.

type TableView

type TableView struct {
	ColumnPriority []string
	MaxColumns     int       // default 8; --verbose bumps to 16
	MaxCellWidth   int       // default 40
	Stderr         io.Writer // hints target; defaults to os.Stderr
}

TableView is the table-mode Formatter. It is shape-aware and produces deterministic output even when the input payload is irregular.

func DefaultTableView

func DefaultTableView() TableView

DefaultTableView returns a TableView with the standard policies.

func (TableView) Encode

func (v TableView) Encode(data any, opts *frameworkoutput.FormatOptions) ([]byte, error)

Encode renders data as an ASCII table according to the shape-aware rules.

type ViewRegistry

type ViewRegistry struct{}

ViewRegistry is a placeholder extension point for per-command column overrides. The current design commits to the global priority list covering ~80% of commands (see spec §决策摘要); add RegisterView methods here when a command needs a bespoke view. Keeping this type published ensures the API shape is stable before the first override lands.

func NewViewRegistry

func NewViewRegistry() *ViewRegistry

NewViewRegistry returns a new empty registry.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL