-
Notifications
You must be signed in to change notification settings - Fork 6
/
static.clj
129 lines (120 loc) · 4.72 KB
/
static.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
(ns dynadoc.static
(:require [dynadoc.utils :as u]
[dynadoc.example :as ex]
[clojure.java.io :as io]
[clojure.tools.reader :as r]
[clojure.tools.reader.reader-types :refer [indexing-push-back-reader]]))
(defn get-cljs-arglists [args]
(loop [args args
arglists []]
(if-let [arg (first args)]
(cond
(vector? arg)
(list arg)
(and (list? arg) (vector? (first arg)))
(recur (rest args) (conj arglists (first arg)))
:else
(recur (rest args) arglists))
arglists)))
(defn read-cljs-file [ns->vars f]
(let [reader (indexing-push-back-reader (slurp f))]
(loop [current-ns nil
ns->vars ns->vars]
(if-let [form (try (r/read {:eof nil} reader)
(catch Exception _ '(comment "Reader error")))]
(recur
(if (and (list? form)
(= (first form) 'ns))
(second form)
current-ns)
(cond
; functions
(and current-ns
(list? form)
(contains? #{'def 'defn 'defonce} (first form))
(>= (count form) 3)
(not (some-> form second meta :private)))
(let [[call sym & args] form]
(update-in ns->vars [current-ns sym] merge
{:sym sym
:meta (merge
(when (= call 'defn)
{:doc (when (string? (first args))
(first args))
:arglists (get-cljs-arglists args)})
(select-keys (meta sym) [:arglists :doc]))
:source (with-out-str
(clojure.pprint/pprint
form))}))
; examples
(and current-ns
(list? form)
(symbol? (first form))
(contains? #{'defexample 'defexamples} (-> form first name symbol)))
(let [[sym k & args] form
sym (-> sym name symbol)
ns-sym (or (ex/parse-ns k) current-ns)
var-sym (ex/parse-val k)
examples (case sym
defexample [(ex/parse-example args)]
defexamples (mapv ex/parse-example args))
examples (vec
(for [i (range (count examples))]
(-> (get examples i)
u/process-example
(assoc :id (str ns-sym "/" var-sym "/" i)))))]
(update-in ns->vars [ns-sym var-sym] merge
{:sym var-sym
:examples examples}))
; protocols
(and current-ns
(list? form)
(= 'defprotocol (first form))
(symbol? (second form)))
(let [[call var-sym] form
methods (reduce
(fn [methods sub-form]
(if (list? sub-form)
(conj methods
{:sym (first sub-form)
:meta {:doc (first (filter string? sub-form))
:arglists (filter vector? sub-form)}
:protocol var-sym})
methods))
[]
form)
protocol {:sym var-sym
:meta {:doc (first (filter string? form))}
:methods (sort (map :sym methods))}]
(reduce
(fn [ns->vars {:keys [sym] :as parsed-var}]
(update-in ns->vars [current-ns sym] merge parsed-var))
ns->vars
(conj methods protocol)))
; else
:else ns->vars))
ns->vars))))
(defn visible? [^java.io.File f]
(let [n (.getName f)]
(or (= n ".")
(not (.startsWith n ".")))))
(defn get-cljs-nses-and-vars []
(loop [files (tree-seq
(fn [^java.io.File f]
(and (.isDirectory f) (visible? f)))
(fn [^java.io.File d]
(seq (.listFiles d)))
(io/file "."))
ns->vars {}]
(if-let [f (first files)]
(if (and (.isFile f)
(-> f .getName (.endsWith ".cljs")))
(recur
(rest files)
(try
(read-cljs-file ns->vars f)
(catch Exception e
(.printStackTrace e)
ns->vars)))
(recur (rest files) ns->vars))
ns->vars)))