Files
larksuite-cli/internal/output/jq_raw_test.go
SunPeiYang996 e42033f5b5 feat(doc): add v2 API for docs +create / +fetch / +update (#638)
Adds an `--api-version v2` path to the docs shortcuts, backed by the
`docs_ai/v1/documents` OpenAPI. DocxXML is the default document format
and Markdown is available as an alternative. Content input is unified
across the three shortcuts via `--content` + `--doc-format`. The v1
(MCP) path is preserved for backward compatibility and now prints a
deprecation notice on use.

Shortcuts:

  - `docs +create --api-version v2`: create a document from XML or
    Markdown, with optional `--parent-token` or `--parent-position`.
    Bot identity continues to auto-grant the current CLI user
    full_access on the new document.

  - `docs +fetch --api-version v2`: adds `--detail simple|with-ids|full`
    for export granularity and `--scope full|outline|range|keyword|section`
    for partial reads, along with `--context-before` / `--context-after`,
    `--max-depth`, and `--revision-id`.

  - `docs +update --api-version v2`: introduces structured operations
    via `--command`: `str_replace`, `block_delete`, `block_insert_after`,
    `block_copy_insert_after`, `block_replace`, `block_move_after`,
    `overwrite`, `append`.

Framework support in `shortcuts/common`:

  - `OutRaw` / `OutFormatRaw` emit the JSON envelope with HTML escaping
    disabled so XML/HTML document bodies are preserved verbatim.
  - New `Shortcut.PostMount` hook runs after a cobra.Command is fully
    configured; used here to install a version-aware help function
    that hides flags belonging to the inactive `--api-version`.

Also refreshes the lark-doc skill pack (SKILL.md, create/fetch/update
references, new lark-doc-xml and lark-doc-md references, style and
workflow guides), README examples, and downstream skill call sites
(lark-drive, lark-vc, lark-whiteboard, lark-workflow-meeting-summary,
lark-event).

Change-Id: Ide2d86b190a4e21095ae29096e7fb00031d80489
2026-04-23 23:24:30 +08:00

65 lines
1.9 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package output
import (
"bytes"
"strings"
"testing"
)
func TestJqFilterRaw_PreservesXMLInComplexValue(t *testing.T) {
data := map[string]interface{}{
"data": map[string]interface{}{
"document": map[string]interface{}{
"title": "<title>hello & welcome</title>",
"content": "<p>a < b & c > d</p>",
},
},
}
var raw bytes.Buffer
if err := JqFilterRaw(&raw, data, ".data.document"); err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Raw path must keep <, >, & as literal characters, not Go json-encoder's
// default < / > / & unicode escapes.
for _, unicodeEsc := range []string{"\\u003c", "\\u003e", "\\u0026"} {
if strings.Contains(raw.String(), unicodeEsc) {
t.Errorf("JqFilterRaw unexpectedly HTML-escaped %s: %s", unicodeEsc, raw.String())
}
}
if !strings.Contains(raw.String(), "<title>") {
t.Errorf("JqFilterRaw dropped raw <title>: %s", raw.String())
}
var escaped bytes.Buffer
if err := JqFilter(&escaped, data, ".data.document"); err != nil {
t.Fatalf("unexpected error: %v", err)
}
// JqFilter keeps Go's default HTML escaping for back-compat.
if !strings.Contains(escaped.String(), "\\u003c") {
t.Errorf("JqFilter should HTML-escape < for back-compat: %s", escaped.String())
}
}
func TestJqFilterRaw_ScalarMatchesJqFilter(t *testing.T) {
data := map[string]interface{}{"content": "<title>hello</title>"}
var raw, plain bytes.Buffer
if err := JqFilterRaw(&raw, data, ".content"); err != nil {
t.Fatalf("raw: %v", err)
}
if err := JqFilter(&plain, data, ".content"); err != nil {
t.Fatalf("plain: %v", err)
}
// Scalar string path is raw in both (matches jq -r), so output is identical.
if raw.String() != plain.String() {
t.Errorf("scalar output diverged: raw=%q plain=%q", raw.String(), plain.String())
}
if !strings.Contains(raw.String(), "<title>") {
t.Errorf("scalar output dropped <title>: %q", raw.String())
}
}