(define
  component-source
  (fn
    (name)
    (let
      ((val (cek-try (fn () (eval-expr (make-symbol name))) (fn (err) nil))))
      (if
        (or (component? val) (island? val))
        (let
          ((form-name (if (island? val) "defisland" "defcomp"))
            (params (component-params val))
            (body (component-body val))
            (cname (component-name val)))
          (pretty-print
            (list
              (make-symbol form-name)
              (make-symbol (str "~" cname))
              params
              body)))
        (str ";;; Not found: " name)))))

(define
  handler-source
  (fn
    (name)
    (let
      ((handler-key (str "handler:" name))
        (hdef
          (cek-try
            (fn () (eval-expr (make-symbol handler-key)))
            (fn (err) nil))))
      (if
        (nil? hdef)
        (str ";;; Handler not found: " name)
        (let
          ((method (or (get hdef "method") "get"))
            (path (get hdef "path"))
            (csrf (get hdef "csrf"))
            (returns (or (get hdef "returns") "element"))
            (params (or (get hdef "params") (list)))
            (body (get hdef "body"))
            (parts (list (make-symbol "defhandler") (make-symbol name))))
          (let
            ((parts (append parts (list (make-keyword "path") path)))
              (parts
                (append
                  parts
                  (list (make-keyword "method") (make-keyword method))))
              (parts
                (if
                  (not csrf)
                  (append parts (list (make-keyword "csrf") false))
                  parts))
              (parts
                (if
                  (not (= returns "element"))
                  (append parts (list (make-keyword "returns") returns))
                  parts))
              (parts (append parts (list params body))))
            (pretty-print parts)))))))

(define
  _spec-dirs
  (list "spec" "web" "shared/sx/ref" "lib" "sx" "sxc" "shared/sx/templates"))

(define
  read-spec-file
  (fn
    (filename)
    (let
      ((result nil))
      (for-each
        (fn
          (dir)
          (when
            (nil? result)
            (let
              ((content (read-file (str dir "/" filename))))
              (when (not (nil? content)) (set! result content)))))
        _spec-dirs)
      (or result (str ";; spec file not found: " filename)))))

(define primitives-data (fn () primitives-by-category))

(define
  special-forms-data
  (fn
    ()
    (let
      ((source (read-spec-file "special-forms.sx")))
      (if
        (starts-with? source ";;")
        {:categories (list)}
        (categorize-special-forms (parse source))))))

(define
  _spec-search-dirs
  (fn
    ()
    (list
      _spec-dir
      _web-dir
      _lib-dir
      (str _project-dir "/shared/sx/ref")
      (str _project-dir "/sx")
      (str _project-dir "/sxc")
      (str _project-dir "/shared/sx/templates"))))

(define
  read-spec-file
  (fn
    (filename)
    (let
      ((result nil))
      (for-each
        (fn
          (dir)
          (when
            (nil? result)
            (let
              ((content (read-file (str dir "/" filename))))
              (when (not (nil? content)) (set! result content)))))
        (_spec-search-dirs))
      (or result (str ";; spec file not found: " filename)))))

(define
  reference-data
  (fn
    (slug)
    (let
      ((raw-data (case slug "attributes" {:req-attrs request-attrs :beh-attrs behavior-attrs :uniq-attrs sx-unique-attrs} "headers" {:req-headers request-headers :resp-headers response-headers} "events" {:events-list events-list} "js-api" {:js-api-list js-api-list} :else {:req-attrs request-attrs :beh-attrs behavior-attrs :uniq-attrs sx-unique-attrs}))
        (detail-keys
          (case
            slug
            "attributes"
            (keys attr-details)
            "headers"
            (keys header-details)
            "events"
            (keys event-details)
            "js-api"
            (list)
            :else (keys attr-details))))
      (build-reference-data slug raw-data detail-keys))))

(define
  attr-detail-data
  (fn (slug) (build-attr-detail slug (get attr-details slug))))

(define
  header-detail-data
  (fn (slug) (build-header-detail slug (get header-details slug))))

(define
  event-detail-data
  (fn (slug) (build-event-detail slug (get event-details slug))))

(define _spec-slug-map {:primitives (list "primitives.sx" "Primitives" "Built-in pure functions") :render (list "render.sx" "Renderer" "Three rendering modes") :parser (list "parser.sx" "Parser" "Tokenization and parsing") :evaluator (list "evaluator.sx" "Evaluator" "CEK machine evaluator") :signals (list "signals.sx" "Signals" "Fine-grained reactive primitives") :types (list "types.sx" "Types" "Optional gradual type system")})

(define
  spec-explorer-data-by-slug
  (fn
    (slug)
    (let
      ((entry (get _spec-slug-map (make-keyword slug))))
      (if
        (nil? entry)
        nil
        (let
          ((filename (first entry))
            (title (nth entry 1))
            (desc (nth entry 2)))
          {:description desc :title title :filename filename :source (read-spec-file filename)})))))

(define spec-explorer-data (fn (filename title desc) {:description (or desc "") :title (or title filename) :filename filename :source (read-spec-file filename)}))

(define bootstrapper-data (fn (target) {:target (or target "js") :status "not-implemented" :components (list)}))

(define bundle-analyzer-data (fn () {:bundles (list) :status "not-implemented"}))

(define routing-analyzer-data (fn () {:routes (list) :status "not-implemented"}))

(define data-test-data (fn () {:status "not-implemented" :tests (list)}))
