mirror of
https://github.com/zap-proto/zip.git
synced 2026-10-19 15:38:57 +00:00
A typed op could only take one JSON value and answer one, so uploads, signed webhooks, form posts, YAML and merge-patch bodies, PDFs, SSE, WebSockets, OAuth redirects and upstream relays stayed untyped routes with no schema, tool, command or SDK method. Each is now a typed op and its REST wire is unchanged. Requests: a zip.Body field takes the body and Content-Type exactly as sent; an In implementing Parser decodes itself; form: fields and *zip.File parts bind url-encoded and multipart forms; cookie: binds a request cookie as an in: cookie parameter. Consumes names the media. Answers: zip.Body (bytes, filename, its own status and headers, a Reader streams chunked), Verbatim[T] (a relay documented as T), Sse[T] (events with keep-alive), Socket[M] (an upgrade after the contract runs; 426 without one, 501 over ZAP), Redirect, CookieCoder, Produces, and unions: a type whose OneOf method's results are the alternatives, with Or[A,B] as the stock one filing each under the status it states. Projections follow from the manifest: the document publishes binary media, form schemas, x-events, x-socket with 101, 3xx with Location and oneOf; MCP takes bytes as base64 and returns bytes, text or collected events as tool content, listing a socket op in _meta as no tool; the CLI reads --body @file|-, --field name=@file and --out, prints events as they arrive and bridges a socket to stdin and stdout. tools/list is ProjectMCP over the manifest, the projection MCPTools already was. Prose reaches promoted fields (filed under the declaring struct), a type defined over another struct, and the type arguments of zip's kinds and OneOf results; an instantiated generic is published under its name followed by its argument names instead of an illegal component key. The unused reflect-only document and tool builders go.
42 lines
1.2 KiB
Go
42 lines
1.2 KiB
Go
// SPDX-License-Identifier: BSD-3-Clause-Eco
|
|
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package zip
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/zap-proto/zip/internal/jsontag"
|
|
)
|
|
|
|
// The held answer's prose is the comments on Approval's fields, stated once
|
|
// more for the document because no zipdoc pass reads zip's own source. This
|
|
// holds the two to one text.
|
|
func TestApprovalProseIsItsComments(t *testing.T) {
|
|
f, err := parser.ParseFile(token.NewFileSet(), "authorize.go", nil, parser.ParseComments)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := map[string]string{}
|
|
ast.Inspect(f, func(n ast.Node) bool {
|
|
ts, ok := n.(*ast.TypeSpec)
|
|
if !ok || ts.Name.Name != "Approval" {
|
|
return true
|
|
}
|
|
for _, field := range ts.Type.(*ast.StructType).Fields.List {
|
|
tag := reflect.StructTag(strings.Trim(field.Tag.Value, "`")).Get("json")
|
|
want["Approval."+jsontag.Name(field.Names[0].Name, tag)] = strings.TrimSpace(field.Doc.Text())
|
|
}
|
|
return false
|
|
})
|
|
if !reflect.DeepEqual(want, approvalProse) {
|
|
t.Errorf("approvalProse = %v\nthe comments say %v", approvalProse, want)
|
|
}
|
|
}
|