-
-
Notifications
You must be signed in to change notification settings - Fork 95
/
core.clj
200 lines (156 loc) · 6.46 KB
/
core.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
(ns figwheel.main.schema.core
(:require
[clojure.java.io :as io]
[clojure.string :as string]
[clojure.spec.alpha :as s]
[clojure.set]
[figwheel.main.util :as util]
[expound.printer :as printer]
[expound.alpha :as exp]))
(def ^:dynamic *spec-meta* (atom {}))
(defn def-spec-meta [k & args]
(assert (even? (count args)))
(swap! *spec-meta* assoc k (assoc (into {} (map vec (partition 2 args)))
:position (count (keys @*spec-meta*))
:key k)))
(defn spec-doc [k doc] (swap! *spec-meta* assoc-in [k :doc] doc))
(defn file-exists? [s] (and s (.isFile (io/file s))))
(defn directory-exists? [s] (and s (.isDirectory (io/file s))))
(defn non-blank-string? [x] (and (string? x) (not (string/blank? x))))
(defn integer-like? [x]
(and (string? x)
(re-matches #"\d+" x)))
(defn flag-arg? [s]
(and (non-blank-string? s)
(.startsWith s "-")))
(defn not-flag? [x]
(and (string? x)
(not (flag-arg? x))))
(defn unquoted-symbol? [a]
(and (symbol? a)
(not (string/starts-with? (str a) "'"))))
;; ------------------------------------------------------------
;; Shared specs
;; ------------------------------------------------------------
(exp/def ::host not-flag?
"should be an existing host interface (i.e. \"localhost\" \"127.0.0.1\" \"0.0.0.0\" \"192.168.0.1\")")
(exp/def ::port integer-like?
"should be an integer port i.e 9500")
(exp/def ::integer-port integer?
"should be an integer port i.e 9500")
(defn has-cljs-source-files? [dir]
(not-empty (clojure.set/intersection
#{"cljs" "cljc"}
(util/source-file-types-in-dir dir))))
(exp/def ::unquoted-symbol unquoted-symbol?
"should be a symbol WITHOUT an initial quote. Quoted symbols are not needed in EDN")
(exp/def ::has-cljs-source-files has-cljs-source-files?
"directory should contain cljs or cljc source files")
;; ------------------------------------------------------------
;; Validate
;; ------------------------------------------------------------
(defn key-meta-for-problem [{:keys [via :spell-spec.alpha/likely-misspelling-of] :as prob}]
(or
(when-let [n (first likely-misspelling-of)]
(when-let [ns (namespace (first via))]
(get @*spec-meta* (keyword ns (name n)))))
(some->> (reverse via)
(filter @*spec-meta*)
;; don't show the root docs
(filter (complement
#{:figwheel.main.schema.config/edn
:figwheel.main.schema.cljs-options/cljs-options}))
first
(get @*spec-meta*))))
(let [expected-str (deref #'exp/expected-str)]
(defn expected-str-with-doc [_type spec-name val path problems opts]
(str (expected-str _type spec-name val path problems opts)
(when-let [{:keys [key doc]} (key-meta-for-problem (first problems))]
(when doc
(str
"\n\n-- Doc for " (pr-str (keyword (name key))) " -----\n\n"
(printer/indent doc)))))))
(defn expound-string [spec form]
(when-let [explain-data (s/explain-data spec form)]
(with-redefs [exp/expected-str expected-str-with-doc]
(with-out-str
((exp/custom-printer
{:print-specs? false})
explain-data)))))
(defn validate-config! [spec config-data context-msg]
(if-let [explained (expound-string spec config-data)]
(throw (ex-info (str context-msg "\n" explained)
{::error explained}))
true))
#_(expound-string
:figwheel.main.schema.config/edn
(read-string (slurp "figwheel-main.edn")))
;; ------------------------------------------------------------
;; Spec validation
;; ------------------------------------------------------------
(defmacro ensure-all-registered-keys-included [ignore-reg-keys key-spec]
(let [spec-keys (set (concat ignore-reg-keys
(mapcat second (partition 2 (rest key-spec)))))
reg-keys (set (filter #(= (str *ns*) (namespace %))
(keys (s/registry))))
missing-keys (clojure.set/difference reg-keys spec-keys)]
(assert (empty? missing-keys) (str "missing keys " (pr-str missing-keys))))
key-spec)
;; ------------------------------------------------------------
;; Generate docs
;; ------------------------------------------------------------
(defn markdown-option-docs [key-datas]
(string/join
"\n\n"
(mapv (fn [{:keys [key doc]}]
(let [k (keyword (name key))]
(format "## %s\n\n%s" (pr-str k) doc)))
key-datas)))
(defn markdown-docs []
(let [{:keys [common un-common]} (->> (vals @*spec-meta*)
(filter #(-> %
:key
namespace
(= "figwheel.main.schema.config")))
(sort-by :position)
(group-by :group))]
(str "---
layout: config-options
---
# Figwheel Main Configuration Options
This page is a reference for all of the Figwheel configuration options.
You can enter these options in a `figwheel-main.edn` file that is in the root
of your project directory.
Example `figwheel-main.edn` file:
```clojure
{:watch-dirs [\"src\" \"admin-src\"]
:css-dirs [\"resources/public/css\"]}
```
The options can also be entered as metadata in a Figwheel build file
in your project's root directory. The name of a build file has the form
`[build-id].cljs.edn` where `[build-id]` is an identifier of your
choice.
An example `dev.cljs.edn` build file that supplies figwheel config options.
```clojure
^{:watch-dirs [\"src\" \"admin-src\"]
:css-dirs [\"resources/public/css\"]}
{:main example.core}
```
Any options provided in the metadata of the build file will override the
options in the `figwheel-main.edn` file.
# Commonly used options
*The options below are listed in order of importance*
"
(markdown-option-docs common)
"\n\n"
"# Rarely used options\n\n"
(markdown-option-docs un-common))))
(defn output-docs [output-to]
(require 'figwheel.main.schema.config)
(require 'figwheel.server.ring)
(.mkdirs (.getParentFile (io/file output-to)))
(spit output-to (markdown-docs)))
#_(validate-config! :figwheel.main.schema.config/edn (read-string (slurp "figwheel-main.edn")) "")
#_(doseq [dir ["doc/figwheel-main-options.md" "docs/config-options.md"]]
(output-docs dir))
#_(markdown-docs)