#!/usr/bin/env python3 """ OpenAPI Documentation Bundler This script merges the modular OpenAPI specification files into a single api-docs.bundled.yaml file that can be served to Swagger UI or other OpenAPI tools. It merges paths from the paths/ directory and then uses Redocly CLI to resolve all $ref references into inline definitions. Usage: python bundle-api-docs.py """ import yaml import os import glob import subprocess public_dir = os.path.dirname(os.path.abspath(__file__)) components_dir = os.path.join(public_dir, "components", "schemas") paths_dir = os.path.join(public_dir, "paths") temp_file = os.path.join(public_dir, "api-docs.merged.yaml") output_file = os.path.join(public_dir, "api-docs.bundled.yaml") # Read the base api-docs.yaml with open(os.path.join(public_dir, "api-docs.yaml"), "r", encoding="utf-8") as f: api_docs = yaml.safe_load(f) # Merge paths from all path files paths = {} path_files = glob.glob(os.path.join(paths_dir, "*.yaml")) print(f"Found {len(path_files)} path files to merge...") for filepath in path_files: filename = os.path.basename(filepath) try: with open(filepath, "r", encoding="utf-8") as f: parsed = yaml.safe_load(f) if parsed: paths.update(parsed) print(f" [OK] Merged {len(parsed)} paths from {filename}") except Exception as e: print(f" [WARN] Failed to parse {filename}: {e}") # Replace the empty paths with merged paths api_docs["paths"] = paths # Write the merged file (still has $refs) with open(temp_file, "w", encoding="utf-8") as f: yaml.dump( api_docs, f, default_flow_style=False, allow_unicode=True, sort_keys=False, width=4096, ) print(f"\n[SUCCESS] Merged paths into: {temp_file}") print(f" Total paths: {len(paths)}") # Now use Redocly CLI to resolve all $ref references print("\nResolving $ref references with Redocly CLI...") try: result = subprocess.run( ["redocly", "bundle", temp_file, "-o", output_file], capture_output=True, text=True, cwd=public_dir, ) if result.returncode == 0: print(f" [SUCCESS] Resolved all $ref references to: {output_file}") # Clean up temp file os.remove(temp_file) print(f" [CLEANUP] Removed temp file: {temp_file}") else: print(f" [ERROR] Redocly CLI failed:") print(f" {result.stderr}") exit(1) except FileNotFoundError: print(" [ERROR] Redocly CLI not found. Install with: npm install -g @redocly/cli") exit(1) except Exception as e: print(f" [ERROR] Failed to run Redocly CLI: {e}") exit(1) print(f"\n{'=' * 60}") print(f"Bundling complete!") print(f" Output: {output_file}") print(f" Total paths: {len(paths)}") print(f" Total schemas: {len(api_docs.get('components', {}).get('schemas', {}))}") print(f"\nYou can now serve this file to Swagger UI.") print(f"{'=' * 60}")