(defn desugar-ns-specs
"Given an original set of ns specs desugar :include-macros and :refer-macros
usage into only primitive spec forms - :use, :require, :use-macros,
:require-macros. If a library includes a macro file of with the same name
as the namespace will also be desugared."
[args]
(let [{:keys [require] :as indexed}
(->> args
(map (fn [[k & specs]] [k (into [] specs)]))
(into {}))
sugar-keys #{:include-macros :refer-macros}
;; drop spec k and value from spec for generated :require-macros
remove-from-spec
(fn [pred spec]
(if-not (and (sequential? spec) (some pred spec))
spec
(let [[l r] (split-with (complement pred) spec)]
(recur pred (concat l (drop 2 r))))))
;; rewrite :refer-macros to :refer for generated :require-macros
replace-refer-macros
(fn [spec]
(if-not (sequential? spec)
spec
(map (fn [x] (if (= x :refer-macros) :refer x)) spec)))
reload-spec? #(#{:reload :reload-all} %)
to-macro-specs
(fn [specs]
(->> specs
(filter
(fn [x]
(or (and (sequential? x)
(some sugar-keys x))
(reload-spec? x)
(macro-autoload-ns? x))))
(map (fn [x]
(if-not (reload-spec? x)
(->> x (remove-from-spec #{:include-macros})
(remove-from-spec #{:refer})
(remove-from-spec #{:rename})
(replace-refer-macros))
x)))))
remove-sugar (partial remove-from-spec sugar-keys)]
(if-some [require-specs (seq (to-macro-specs require))]
(map (fn [x]
(if-not (reload-spec? x)
(let [[k v] x]
(cons k (map remove-sugar v)))
x))
(update-in indexed [:require-macros] (fnil into []) require-specs))
args)))