|
2 | 2 | "Clerk's Static App Builder."
|
3 | 3 | (:require [babashka.fs :as fs]
|
4 | 4 | [babashka.process :refer [sh]]
|
5 |
| - [clojure.edn :as edn] |
6 | 5 | [clojure.java.browse :as browse]
|
7 | 6 | [clojure.java.io :as io]
|
8 | 7 | [clojure.string :as str]
|
9 | 8 | [nextjournal.clerk.analyzer :as analyzer]
|
10 | 9 | [nextjournal.clerk.builder-ui :as builder-ui]
|
| 10 | + [nextjournal.clerk.config :as config] |
11 | 11 | [nextjournal.clerk.eval :as eval]
|
12 | 12 | [nextjournal.clerk.parser :as parser]
|
| 13 | + [nextjournal.clerk.paths :as paths] |
13 | 14 | [nextjournal.clerk.view :as view]
|
14 | 15 | [nextjournal.clerk.viewer :as viewer]
|
15 |
| - [nextjournal.clerk.webserver :as webserver] |
16 |
| - [nextjournal.clerk.config :as config]) |
17 |
| - (:import (java.net URL))) |
| 16 | + [nextjournal.clerk.webserver :as webserver])) |
18 | 17 |
|
19 | 18 | (def clerk-docs
|
20 | 19 | (into ["CHANGELOG.md"
|
|
127 | 126 | (def default-out-path
|
128 | 127 | (str "public" fs/file-separator "build"))
|
129 | 128 |
|
130 |
| -(defn ^:private ensure-not-empty [build-opts {:as opts :keys [error expanded-paths]}] |
131 |
| - (if error |
132 |
| - opts |
133 |
| - (if (empty? expanded-paths) |
134 |
| - (merge {:error "nothing to build" :expanded-paths expanded-paths} (select-keys build-opts [:paths :paths-fn :index])) |
135 |
| - opts))) |
136 |
| - |
137 |
| -(defn ^:private maybe-add-index [{:as build-opts :keys [index]} {:as opts :keys [expanded-paths]}] |
138 |
| - (if-not (contains? build-opts :index) |
139 |
| - opts |
140 |
| - (if (and (not (instance? URL index)) |
141 |
| - (not (symbol? index)) |
142 |
| - (or (not (string? index)) (not (fs/exists? index)))) |
143 |
| - {:error "`:index` must be either an instance of java.net.URL or a string and point to an existing file" |
144 |
| - :index index} |
145 |
| - (cond-> opts |
146 |
| - (and index (not (contains? (set expanded-paths) index))) |
147 |
| - (update :expanded-paths conj index))))) |
148 |
| - |
149 |
| -#_(maybe-add-index {:index "book.clj"} {:expanded-paths ["README.md"]}) |
150 |
| -#_(maybe-add-index {:index 'book.clj} {:expanded-paths ["README.md"]}) |
151 |
| - |
152 |
| -(defn resolve-paths [{:as build-opts :keys [paths paths-fn index]}] |
153 |
| - (when (and paths paths-fn) |
154 |
| - (binding [*out* *err*] |
155 |
| - (println "[info] both `:paths` and `:paths-fn` are set, `:paths` will take precendence."))) |
156 |
| - (if (not (or paths paths-fn index)) |
157 |
| - {:error "must set either `:paths`, `:paths-fn` or `:index`." |
158 |
| - :build-opts build-opts} |
159 |
| - (cond paths (if (sequential? paths) |
160 |
| - {:resolved-paths paths} |
161 |
| - {:error "`:paths` must be sequential" :paths paths}) |
162 |
| - paths-fn (let [ex-msg "`:path-fn` must be a qualified symbol pointing at an existing var."] |
163 |
| - (if-not (qualified-symbol? paths-fn) |
164 |
| - {:error ex-msg :paths-fn paths-fn} |
165 |
| - (if-some [resolved-var (try (requiring-resolve paths-fn) |
166 |
| - (catch Exception _e nil))] |
167 |
| - (let [{:as opts :keys [error paths]} |
168 |
| - (try {:paths (cond-> @resolved-var (fn? @resolved-var) (apply []))} |
169 |
| - (catch Exception e |
170 |
| - {:error (str "An error occured invoking `" (pr-str resolved-var) "`: " (ex-message e)) |
171 |
| - :paths-fn paths-fn}))] |
172 |
| - (if error |
173 |
| - opts |
174 |
| - (if-not (sequential? paths) |
175 |
| - {:error (str "`:paths-fn` must compute to a sequential value.") |
176 |
| - :paths-fn paths-fn :resolved-paths paths} |
177 |
| - {:resolved-paths paths}))) |
178 |
| - {:error ex-msg :paths-fn paths-fn}))) |
179 |
| - index {:resolved-paths []}))) |
180 |
| - |
181 |
| -#_(resolve-paths {:paths ["notebooks/di*.clj"]}) |
182 |
| -#_(resolve-paths {:paths-fn 'clojure.core/inc}) |
183 |
| -#_(resolve-paths {:paths-fn 'nextjournal.clerk.builder/clerk-docs}) |
184 |
| - |
185 |
| -(defn expand-paths [build-opts] |
186 |
| - (let [{:as opts :keys [error resolved-paths]} (resolve-paths build-opts)] |
187 |
| - (if error |
188 |
| - opts |
189 |
| - (->> resolved-paths |
190 |
| - (mapcat (fn [path] (if (fs/exists? path) |
191 |
| - [path] |
192 |
| - (fs/glob "." path)))) |
193 |
| - (filter (complement fs/directory?)) |
194 |
| - (mapv (comp str fs/file)) |
195 |
| - (hash-map :expanded-paths) |
196 |
| - (maybe-add-index build-opts) |
197 |
| - (ensure-not-empty build-opts))))) |
198 |
| - |
199 |
| -#_(expand-paths {:paths ["notebooks/di*.clj"] :index "src/nextjournal/clerk/index.clj"}) |
200 |
| -#_(expand-paths {:paths ['notebooks/rule_30.clj]}) |
201 |
| -#_(expand-paths {:index "book.clj"}) |
202 |
| -#_(expand-paths {:paths-fn `clerk-docs}) |
203 |
| -#_(expand-paths {:paths-fn `clerk-docs-2}) |
204 |
| -#_(do (defn my-paths [] ["notebooks/h*.clj"])§ |
205 |
| - (expand-paths {:paths-fn `my-paths})) |
206 |
| -#_(expand-paths {:paths ["notebooks/viewers**"]}) |
207 |
| - |
208 | 129 | (def builtin-index
|
209 | 130 | (io/resource "nextjournal/clerk/index.clj"))
|
210 | 131 |
|
|
216 | 137 | (let [opts+index (cond-> opts
|
217 | 138 | index (assoc :index (str index)))
|
218 | 139 | {:as opts' :keys [expanded-paths]} (cond-> opts+index
|
219 |
| - expand-paths? (merge (expand-paths opts+index)))] |
| 140 | + expand-paths? (merge (paths/expand-paths opts+index)))] |
220 | 141 | (-> opts'
|
221 | 142 | (update :resource->url #(merge {} %2 %1) @config/!resource->url)
|
222 | 143 | (cond-> #_opts'
|
223 | 144 | expand-paths?
|
224 | 145 | (dissoc :expand-paths?)
|
225 |
| - (and (not index) (= 1 (count expanded-paths))) |
226 |
| - (assoc :index (first expanded-paths)) |
227 | 146 | (and (not index) (< 1 (count expanded-paths)) (every? (complement viewer/index-path?) expanded-paths))
|
228 | 147 | (as-> opts
|
229 |
| - (-> opts (assoc :index builtin-index) (update :expanded-paths conj builtin-index)))))))) |
| 148 | + (-> opts (assoc :index builtin-index) (update :expanded-paths conj builtin-index)))))))) |
230 | 149 |
|
231 | 150 | #_(process-build-opts {:index 'book.clj :expand-paths? true})
|
232 | 151 | #_(process-build-opts {:paths ["notebooks/rule_30.clj"] :expand-paths? true})
|
|
336 | 255 | (str (viewer/relative-root-prefix-from (viewer/map-index opts file)) path
|
337 | 256 | (when fragment (str "#" fragment))))))
|
338 | 257 |
|
339 |
| -(defn read-opts-from-deps-edn! [] |
340 |
| - (if (fs/exists? "deps.edn") |
341 |
| - (let [deps-edn (edn/read-string (slurp "deps.edn"))] |
342 |
| - (if-some [clerk-alias (get-in deps-edn [:aliases :nextjournal/clerk])] |
343 |
| - (get clerk-alias :exec-args |
344 |
| - {:error (str "No `:exec-args` found in `:nextjournal/clerk` alias.")}) |
345 |
| - {:error (str "No `:nextjournal/clerk` alias found in `deps.edn`.")})) |
346 |
| - {:error (str "No `deps.edn` found in project.")})) |
347 |
| - |
348 |
| -(def ^:dynamic ^:private *build-opts* nil) |
349 |
| -(def build-help-link "\n\nLearn how to [set up your static build](https://book.clerk.vision/#static-building).") |
350 |
| -(defn index-paths |
351 |
| - ([] (index-paths (or *build-opts* (read-opts-from-deps-edn!)))) |
352 |
| - ([{:as opts :keys [index error]}] |
353 |
| - (if error |
354 |
| - (update opts :error str build-help-link) |
355 |
| - (let [{:as result :keys [expanded-paths error]} (expand-paths opts)] |
356 |
| - (if error |
357 |
| - (update result :error str build-help-link) |
358 |
| - {:paths (remove #{index "index.clj"} expanded-paths)}))))) |
359 |
| - |
360 |
| -#_(index-paths) |
361 |
| -#_(index-paths {:paths ["CHANGELOG.md"]}) |
362 |
| -#_(index-paths {:paths-fn "boom"}) |
363 |
| - |
364 | 258 | (defn build-static-app! [{:as opts :keys [bundle?]}]
|
365 | 259 | (let [{:as opts :keys [download-cache-fn upload-cache-fn report-fn compile-css? expanded-paths error]}
|
366 | 260 | (process-build-opts (assoc opts :expand-paths? true))
|
|
391 | 285 | (let [{result :result duration :time-ms} (eval/time-ms
|
392 | 286 | (try
|
393 | 287 | (binding [*ns* *ns*
|
394 |
| - *build-opts* opts |
| 288 | + paths/*build-opts* opts |
395 | 289 | viewer/doc-url (partial doc-url opts file)]
|
396 | 290 | (let [doc (eval/eval-analyzed-doc doc)]
|
397 | 291 | (assoc doc :viewer (view/doc->viewer (assoc opts
|
398 |
| - :static-build? true |
399 | 292 | :nav-path (if (instance? java.net.URL file)
|
400 | 293 | (str "'" (:ns doc))
|
401 | 294 | (str file)))
|
|
0 commit comments