Files
wehub-resource-sync bf9395e022
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:22:54 +08:00

122 lines
2.7 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package output
import (
"encoding/json"
"fmt"
"io"
"os"
"github.com/larksuite/cli/internal/validate"
)
// PrintJson prints data as formatted JSON to w.
func PrintJson(w io.Writer, data interface{}) {
injectNotice(data)
b, err := json.MarshalIndent(data, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "json marshal error: %v\n", err)
return
}
fmt.Fprintln(w, string(b))
}
// injectNotice adds a "_notice" field into CLI envelope maps.
// Only modifies map[string]interface{} values that have an "ok" key
// (e.g. doctor, auth, config commands that build map envelopes directly).
//
// Struct-based envelopes (Envelope, the typed error envelope) are NOT handled
// here — callers must set the Notice field explicitly via GetNotice().
// See: shortcuts/common/runner.go Out(), output/errors.go WriteTypedErrorEnvelope().
func injectNotice(data interface{}) {
if PendingNotice == nil {
return
}
m, ok := data.(map[string]interface{})
if !ok {
return
}
if _, isEnvelope := m["ok"]; !isEnvelope {
return
}
notice := PendingNotice()
if notice == nil {
return
}
m["_notice"] = notice
}
// PrintNdjson prints data as NDJSON (Newline Delimited JSON) to w.
func PrintNdjson(w io.Writer, data interface{}) {
emit := func(item interface{}) {
b, err := json.Marshal(item)
if err != nil {
fmt.Fprintf(os.Stderr, "ndjson marshal error: %v\n", err)
return
}
fmt.Fprintln(w, string(b))
}
if arr, ok := data.([]interface{}); ok {
for _, item := range arr {
emit(item)
}
} else {
emit(data)
}
}
func cellStr(val interface{}) string {
if val == nil {
return ""
}
var s string
switch v := val.(type) {
case string:
s = v
case json.Number:
s = v.String()
case float64:
if v == float64(int(v)) {
s = fmt.Sprintf("%d", int(v))
} else {
s = fmt.Sprintf("%g", v)
}
case bool:
s = fmt.Sprintf("%v", v)
default:
b, err := json.Marshal(v)
if err != nil {
return fmt.Sprintf("%v", v)
}
s = string(b)
}
// Sanitize for terminal display: strip ANSI escapes, control chars, dangerous Unicode.
return validate.SanitizeForTerminal(s)
}
// PrintTable prints rows as a table to w.
// Delegates to FormatAsTable for flattening, column union, and width handling.
func PrintTable(w io.Writer, rows []map[string]interface{}) {
if len(rows) == 0 {
fmt.Fprintln(w, "(no data)")
return
}
items := make([]interface{}, len(rows))
for i, r := range rows {
items[i] = r
}
FormatAsTable(w, items)
}
// PrintSuccess prints a success message to w.
func PrintSuccess(w io.Writer, msg string) {
fmt.Fprintf(w, "OK: %s\n", msg)
}
// PrintError prints an error message to w.
func PrintError(w io.Writer, msg string) {
fmt.Fprintf(w, "ERROR: %s\n", msg)
}