#!/usr/bin/env bash # Validates every question YAML file's shape against what # portal/src/content.rs actually requires at parse time - not a full # schema check (that would mean building portal itself just to lint # content, real coupling for no real benefit here), but the mistakes # that would actually break a load: bad YAML, missing `id`/`name`, # duplicate `id`s, and unknown requirement `type`s. Uses `yq` (the # jq-wrapping kislyuk/yq, not the Go mikefarah/yq) so every check is a # real jq filter, not bespoke parsing. set -euo pipefail dir="${1:-questions}" fail=0 declare -A seen_ids shopt -s nullglob for f in "$dir"/*.yaml; do if ! json=$(yq . "$f" 2>&1); then echo "FAIL $f: invalid YAML: $json" >&2 fail=1 continue fi id=$(jq -r '.id // empty' <<<"$json") name=$(jq -r '.name // empty' <<<"$json") if [[ -z "$id" ]]; then echo "FAIL $f: missing required 'id'" >&2 fail=1 elif [[ -n "${seen_ids[$id]:-}" ]]; then echo "FAIL $f: duplicate id '$id' (also used by ${seen_ids[$id]})" >&2 fail=1 else seen_ids[$id]="$f" fi if [[ -z "$name" ]]; then echo "FAIL $f: missing required 'name'" >&2 fail=1 fi # "textarea", "file", and "prosekit" are the three values # content.rs/app.rs special-case; anything else is passed straight # through as an HTML attribute, so this is the real set # of valid values, not a guess. bad_types=$(jq -r ' [.alternatives[]?.features[]?.requirements[]? | select(.type != null and (.type | IN( "text", "textarea", "file", "prosekit", "email", "tel", "url", "number", "password", "date", "datetime-local", "time", "month", "week", "color", "range", "checkbox", "radio", "hidden", "search" ) | not)) | .type] | unique | .[] ' <<<"$json") if [[ -n "$bad_types" ]]; then echo "FAIL $f: unknown requirement type(s): $(tr '\n' ' ' <<<"$bad_types")" >&2 fail=1 fi done if [[ $fail -eq 0 ]]; then echo "OK: all question files valid" fi exit $fail