|
| 1 | +#!/usr/bin/zsh |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +# This script builds the OpenAPI documents, rendering them into YAML and JSON. |
| 5 | +# |
| 6 | +# The main inputs for this are the "openapi.jq" files in the "v?" directories. |
| 7 | +# These are jq(1) scripts that are executed with no input in the relevant |
| 8 | +# directory; they're expected to output a valid OpenAPI document. All the JSON |
| 9 | +# Schema documents in the matching "httptransport/types/v?" directory are |
| 10 | +# copied into the working directory. Matching files in the "examples" |
| 11 | +# subdirectory will be slipstreamed to the expected field. |
| 12 | +# |
| 13 | +# The result is then "bundled" into one document, then linted, rendered out to |
| 14 | +# both YAML and JSON, and strings to be used as HTTP Etags are written out. |
| 15 | + |
| 16 | +for cmd in sha256sum git jq yq npx; do |
| 17 | + if ! command -v "$cmd" &>/dev/null; then |
| 18 | + print missing needed command: "$cmd" >&2 |
| 19 | + exit 1 |
| 20 | + fi |
| 21 | +done |
| 22 | +local root=$(git rev-parse --show-toplevel) |
| 23 | + |
| 24 | +function jq() { |
| 25 | + command jq --exit-status "$@" |
| 26 | +} |
| 27 | + |
| 28 | +function yq() { |
| 29 | + command yq --exit-status "$@" |
| 30 | +} |
| 31 | + |
| 32 | +function schemalint() { |
| 33 | + local tmp=$(mktemp --tmpdir schemalint.out.XXX) |
| 34 | + trap " |
| 35 | + [[ \"\$?\" -eq 0 ]] || cat \"$tmp\" |
| 36 | + [[ -f \"$tmp\" ]] && rm \"$tmp\" |
| 37 | + " EXIT |
| 38 | + npx --yes @sourcemeta/jsonschema metaschema --resolve "$1" "$1" &>>"$tmp" |
| 39 | + npx --yes @sourcemeta/jsonschema lint --resolve "$1" "$1" &>>"$tmp" |
| 40 | +} |
| 41 | + |
| 42 | +function widdershins() { |
| 43 | + local tmp=$(mktemp --tmpdir widdershins.out.XXX) |
| 44 | + trap " |
| 45 | + [[ \"\$?\" -eq 0 ]] || cat \"$tmp\" |
| 46 | + [[ -f \"$tmp\" ]] && rm \"$tmp\" |
| 47 | + " EXIT |
| 48 | + npx --yes widdershins \ |
| 49 | + -o "${root}/Documentation/reference/api.md" \ |
| 50 | + --search false \ |
| 51 | + --language_tabs python:Python go:Golang javascript:Javascript \ |
| 52 | + --summary \ |
| 53 | + "${1?missing OpenAPI document}" &>"$tmp" |
| 54 | +} |
| 55 | + |
| 56 | +function render() { |
| 57 | + trap ' |
| 58 | + rm openapi.*.{json,yaml}(N) *.schema.json(N) |
| 59 | + popd -q |
| 60 | + ' EXIT |
| 61 | + pushd -q "${1?missing directory argument}" |
| 62 | + local v=${1:A:t} |
| 63 | + local t=${1:A:h:h}/types/v1 |
| 64 | + |
| 65 | + schemalint "$t" |
| 66 | + for f in ${t}/*.schema.json; do |
| 67 | + local ex=examples/${${f:t}%.schema.json}.json |
| 68 | + if [[ -f "$ex" ]]; then |
| 69 | + jq --slurpfile ex "${ex}" 'setpath(["examples"]; $ex)' "$f" > "${f:t}" |
| 70 | + else |
| 71 | + cp "$f" . |
| 72 | + fi |
| 73 | + done |
| 74 | + |
| 75 | + jq --null-input \ |
| 76 | + 'reduce (inputs|(.["$id"]|split("/")|.[-1]|rtrimstr(".schema.json")) as $k|{components:{schemas:{$k:.}}}) as $it({};. * $it)'\ |
| 77 | + *.schema.json >openapi.types.json |
| 78 | + |
| 79 | + |
| 80 | + jq --null-input -L "${1:A:h}/lib" --from-file openapi.jq >openapi.frag.json |
| 81 | + jq --null-input 'reduce inputs as $it({};. * $it)' openapi.{frag,types}.json >openapi.json |
| 82 | + |
| 83 | + yq -pj eval . <openapi.json >openapi.yaml |
| 84 | + # Need some validator that actually works >:( |
| 85 | + |
| 86 | + sha256sum openapi.json | |
| 87 | + awk '{printf "\"%s\"", $1 >"openapi.etag" }' |
| 88 | +} |
| 89 | + |
| 90 | +# Process all the openapi generation scripts. |
| 91 | +for d in ${root}/httptransport/api/v*/openapi.jq(om); do |
| 92 | + render "${d:h}" |
| 93 | +done |
| 94 | + |
| 95 | +# Generate documentation for the highest version. |
| 96 | +widdershins "${root}"/httptransport/api/v*/openapi.yaml(NnOn[1]) |
0 commit comments