mirror of
https://github.com/zap-proto/gen.git
synced 2026-10-30 15:05:01 +00:00
- Fix zapgen binary path: dist/bin/zapgen.mjs (was .js; tsup outExtension emits .mjs and package bin points there) — the driver never found the CLI. - go emit now produces a compiling Tier-1 HTTP client: zapgen OpenAPI -> oapi-codegen (models+client) -> stdlib-only go.mod. No more 'pending' stub. - Stamp every generated .go/.ts with 'generated from a ZAP schema — DO NOT EDIT' + the exact regenerate command; JSON left as-is (no comment syntax). - Thread a repo-relative schema path into every regenerate hint. - Preserve emit_docs.
161 lines
6.2 KiB
Bash
Executable File
161 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# zapsdk — the one and only way to generate a Hanzo client SDK from a .zap
|
|
# schema. ZAP-native (primary) + OpenAPI HTTP/WS/SSE (fallback), from one
|
|
# schema, per language. See ../README.md (ADR-0001).
|
|
#
|
|
# zapsdk <lang> <schema.zap> # one language
|
|
# zapsdk all # every language x every schema in ./schemas
|
|
#
|
|
# lang ∈ { go rust python ts cpp ruby php }
|
|
set -euo pipefail
|
|
|
|
GEN_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
ZAP_JS="${ZAP_JS:-$(cd "$GEN_DIR/../js" && pwd)}"
|
|
OUT="${OUT:-$GEN_DIR/out}"
|
|
|
|
log() { printf 'zapsdk: %s\n' "$*" >&2; }
|
|
die() { printf 'zapsdk: error: %s\n' "$*" >&2; exit 1; }
|
|
|
|
# relpath prints a path relative to GEN_DIR (so the regenerate hint is stable).
|
|
relpath() { # <path>
|
|
local abs; abs="$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
|
|
printf '%s' "${abs#"$GEN_DIR"/}"
|
|
}
|
|
|
|
# stamp prepends a ZAP provenance + regenerate line to a generated source file
|
|
# that supports `//` comments (.go/.ts). Written once, at the top; JSON outputs
|
|
# carry no comment syntax and are left as emitted.
|
|
stamp() { # <file> <lang> <schema-rel>
|
|
local file="$1" lang="$2" schema="$3" tmp; tmp="$(mktemp)"
|
|
{
|
|
printf '// Code generated from a ZAP schema (zap-proto/gen) — DO NOT EDIT.\n'
|
|
printf '// Regenerate: bin/zapsdk %s %s\n\n' "$lang" "$schema"
|
|
cat "$file"
|
|
} >"$tmp"
|
|
mv "$tmp" "$file"
|
|
}
|
|
|
|
# Build/locate the canonical TS zapgen (dependency-free core; node builtins).
|
|
# tsup emits the CLI as dist/bin/zapgen.mjs (see js/tsup.config.ts + package bin).
|
|
zapgen() {
|
|
local built="$ZAP_JS/dist/bin/zapgen.mjs"
|
|
if [ ! -f "$built" ]; then
|
|
log "building zapgen in $ZAP_JS (one-time)"
|
|
( cd "$ZAP_JS" && { [ -d node_modules ] || pnpm install --frozen-lockfile 2>/dev/null || pnpm install; } && pnpm build )
|
|
fi
|
|
node "$built" "$@"
|
|
}
|
|
|
|
# Locate (installing once if needed) the oapi-codegen used for the Go Tier-1
|
|
# HTTP client. Canonical: github.com/oapi-codegen/oapi-codegen/v2.
|
|
oapi_codegen() {
|
|
local bin; bin="$(command -v oapi-codegen || true)"
|
|
[ -n "$bin" ] || bin="$(go env GOPATH)/bin/oapi-codegen"
|
|
if [ ! -x "$bin" ]; then
|
|
log "installing oapi-codegen (one-time)"
|
|
GOFLAGS=-mod=mod go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
|
|
bin="$(go env GOPATH)/bin/oapi-codegen"
|
|
fi
|
|
"$bin" "$@"
|
|
}
|
|
|
|
# emit_go generates the Tier-1 Go HTTP client: zapgen OpenAPI → oapi-codegen
|
|
# (models + client) → stdlib-only module. The generated client speaks
|
|
# POST /<service>/<method>, the exact route the ZAP HTTP transport serves.
|
|
emit_go() { # <schema> <outdir> <base> <schema-rel>
|
|
local schema="$1" outdir="$2" base="$3" rel="$4"
|
|
zapgen --emit=openapi -out "$outdir" "$schema"
|
|
cat >"$outdir/oapi-codegen.yaml" <<EOF
|
|
# Code generated by zap-proto/gen (zapsdk go) — do not hand-edit.
|
|
# Regenerate: bin/zapsdk go $rel
|
|
package: $base
|
|
output: client.gen.go
|
|
generate:
|
|
models: true
|
|
client: true
|
|
output-options:
|
|
skip-prune: true
|
|
EOF
|
|
( cd "$outdir" && oapi_codegen -config oapi-codegen.yaml "$base.openapi.json" )
|
|
stamp "$outdir/client.gen.go" go "$rel"
|
|
# stdlib-only client → the module needs no require directives.
|
|
cat >"$outdir/go.mod" <<EOF
|
|
// Code generated from a ZAP schema (zap-proto/gen) — DO NOT EDIT.
|
|
// Regenerate: bin/zapsdk go $rel
|
|
module github.com/hanzoai/go-sdk/$base
|
|
|
|
go 1.23
|
|
EOF
|
|
}
|
|
|
|
emit_native() { # <lang> <schema> <outdir> <base> <schema-rel>
|
|
local lang="$1" schema="$2" outdir="$3" base="$4" rel="$5"
|
|
case "$lang" in
|
|
ts)
|
|
# Tier-2 zero-copy native client + Tier-1 OpenAPI, both from one schema.
|
|
zapgen --emit=ts,openapi -out "$outdir" "$schema"
|
|
stamp "$outdir/${base}_zap.ts" ts "$rel"
|
|
;;
|
|
go)
|
|
emit_go "$schema" "$outdir" "$base" "$rel"
|
|
;;
|
|
python|rust|cpp|ruby)
|
|
# Tier-1 fallback: emit the OpenAPI contract; the per-language HTTP client
|
|
# comes from that language's best-in-class generator (openapi-python-client
|
|
# / progenitor / openapi-generator). Native ZAP emit backend pending.
|
|
zapgen --emit=openapi -out "$outdir" "$schema"
|
|
log "$lang: ZAP-native emit backend pending; OpenAPI emitted (Tier-1 fallback client)"
|
|
;;
|
|
php)
|
|
zapgen --emit=openapi -out "$outdir" "$schema"
|
|
log "php: fallback-only (no zap-proto/php runtime yet); OpenAPI emitted"
|
|
;;
|
|
*) die "unknown lang '$lang' (go rust python ts cpp ruby php)" ;;
|
|
esac
|
|
}
|
|
|
|
# emit_docs writes the per-language SDK docs into the hanzo-docs reserved slot
|
|
# content/docs/sdks/<lang>/ (gitignored there — regenerate, never hand-edit).
|
|
# Scope: usage/quickstart/typed-client + transport selection only; it LINKS to
|
|
# the canonical API reference (generated from hanzoai/openapi) and never
|
|
# re-lists endpoints. Default target: out/docs/<lang> unless DOCS_ROOT points at
|
|
# a hanzo-docs .../content/docs/sdks checkout.
|
|
emit_docs() { # <lang> <service> <schema-rel>
|
|
local lang="$1" svc="$2" rel="$3"
|
|
local docdir="${DOCS_ROOT:-$OUT/docs}/$lang"
|
|
mkdir -p "$docdir"
|
|
{
|
|
printf -- '---\ntitle: %s SDK\ndescription: Generated ZAP SDK — quickstart and typed-client usage.\n---\n\n' "$lang"
|
|
printf '{/* Generated by zap-proto/gen from %s. DO NOT EDIT — regenerate: bin/zapsdk %s %s */}\n\n' "$rel" "$lang" "$rel"
|
|
printf '# %s SDK\n\nZAP-native transport is primary; HTTPS/WS/SSE is the fallback. Install, construct the client, pick a transport, call a method. For the full endpoint reference see the [canonical API reference](/docs/api) — this page does not re-list endpoints.\n' "$lang"
|
|
} > "$docdir/${svc}.mdx"
|
|
log "docs $lang <- $svc -> ${docdir#"$GEN_DIR"/}/${svc}.mdx"
|
|
}
|
|
|
|
one() { # <lang> <schema>
|
|
local lang="$1" schema="$2"
|
|
[ -f "$schema" ] || die "schema not found: $schema"
|
|
local base outdir rel
|
|
base="$(basename "$schema" .zap)"
|
|
outdir="$OUT/$lang/$base"
|
|
rel="$(relpath "$schema")"
|
|
mkdir -p "$outdir"
|
|
log "generate $lang <- $rel -> ${outdir#"$GEN_DIR"/}"
|
|
emit_native "$lang" "$schema" "$outdir" "$base" "$rel"
|
|
emit_docs "$lang" "$base" "$rel"
|
|
log "done $lang/$base"
|
|
}
|
|
|
|
main() {
|
|
[ $# -ge 1 ] || die "usage: zapsdk <lang> <schema.zap> | zapsdk all"
|
|
if [ "$1" = "all" ]; then
|
|
for lang in go rust python ts cpp ruby php; do
|
|
for s in "$GEN_DIR"/schemas/*.zap; do one "$lang" "$s"; done
|
|
done
|
|
return
|
|
fi
|
|
[ $# -eq 2 ] || die "usage: zapsdk <lang> <schema.zap>"
|
|
one "$1" "$2"
|
|
}
|
|
main "$@"
|