|
8 | 8 | means the first time we see a template *at runtime*, not the |
9 | 9 | implementation's compile-time. " |
10 | 10 | (:require |
11 | | - [clojure.set :as set] |
12 | | - [clojure.string :as string] |
13 | | - [selmer.template-parser :refer [preprocess-template]] |
14 | | - [selmer.filters :refer [filters]] |
15 | | - [selmer.filter-parser :refer [compile-filter-body literal? |
16 | | - split-value parse-literal]] |
17 | | - [selmer.tags :refer :all] |
18 | | - [selmer.util :refer :all] |
19 | | - [selmer.validator :refer [validation-error]] |
20 | | - selmer.node) |
| 11 | + [clojure.set :as set] |
| 12 | + [clojure.string :as string] |
| 13 | + [selmer.template-parser :refer [preprocess-template]] |
| 14 | + [selmer.filters :refer [filters]] |
| 15 | + [selmer.filter-parser :refer [compile-filter-body literal? |
| 16 | + split-value parse-literal]] |
| 17 | + [selmer.tags :refer :all] |
| 18 | + [selmer.util :refer :all] |
| 19 | + [selmer.validator :refer [validation-error]] |
| 20 | + selmer.node) |
21 | 21 | (:import [selmer.node TextNode FunctionNode])) |
22 | 22 |
|
23 | 23 | ;; Ahead decl because some fns call into each other. |
24 | 24 |
|
25 | | -(declare parse parse-input parse-file tag-content) |
| 25 | +(declare parse parse-input parse-str parse-file tag-content) |
26 | 26 |
|
27 | 27 | ;; Memoization atom for templates. If you pass a filepath instead |
28 | 28 | ;; of a string, we'll use the last-modified timestamp to cache the |
|
62 | 62 | (if (or (looks-like-absolute-file-path? path) |
63 | 63 | (.startsWith ^java.lang.String path "file:/")) |
64 | 64 | (append-slash |
65 | | - (try |
66 | | - (str (java.net.URL. path)) |
67 | | - (catch java.net.MalformedURLException err |
68 | | - (str "file:///" path)))) |
| 65 | + (try |
| 66 | + (str (java.net.URL. path)) |
| 67 | + (catch java.net.MalformedURLException err |
| 68 | + (str "file:///" path)))) |
69 | 69 | (append-slash path)))) |
70 | 70 |
|
71 | 71 | (defn set-resource-path! |
|
117 | 117 | (defn render |
118 | 118 | " render takes the string, the context-map and possibly also opts. " |
119 | 119 | [s context-map & [opts]] |
120 | | - (render-template (parse parse-input (java.io.StringReader. s) opts) context-map)) |
121 | | - |
| 120 | + (render-template (parse parse-str s opts) context-map)) |
122 | 121 |
|
123 | 122 | ;; Primary fn you interact with as a user, you pass a path that |
124 | 123 | ;; exists somewhere in your class-path, typically something like |
|
151 | 150 | :last-modified last-modified-time}) |
152 | 151 | (render-template template context-map)))) |
153 | 152 | (validation-error |
154 | | - (str "resource-path for " filename-or-url " returned nil, typically means the file doesn't exist in your classpath.") |
155 | | - nil nil nil)))) |
| 153 | + (str "resource-path for " filename-or-url " returned nil, typically means the file doesn't exist in your classpath.") |
| 154 | + nil nil nil)))) |
156 | 155 |
|
157 | 156 | ;; For a given tag, get the fn handler for the tag type, |
158 | 157 | ;; pass it the arguments, tag-content, render-template fn, |
|
161 | 160 | (defn expr-tag [{:keys [tag-name args]} rdr] |
162 | 161 | (if-let [handler (tag-name @expr-tags)] |
163 | 162 | (handler args tag-content render-template rdr) |
164 | | - (throw (ex-info (str "unrecognized tag: " tag-name |
165 | | - " - did you forget to close a tag?") |
| 163 | + (throw (ex-info (str "unrecognized tag: " tag-name |
| 164 | + " - did you forget to close a tag?") |
166 | 165 | {})))) |
167 | 166 |
|
168 | 167 | ;; Same as a vanilla data tag with a value, but composes |
|
338 | 337 | (defn parse-file [file params] |
339 | 338 | (-> file preprocess-template (java.io.StringReader.) (parse-input params))) |
340 | 339 |
|
| 340 | +;; File-aware parse wrapper for string. |
| 341 | + |
| 342 | +(defn parse-str [input params] |
| 343 | + (-> (char-array input) preprocess-template (java.io.StringReader.) (parse-input params))) |
| 344 | + |
341 | 345 | (defn parse [parse-fn input & [{:keys [tag-open tag-close filter-open filter-close tag-second short-comment-second] |
342 | 346 | :or {tag-open *tag-open* |
343 | 347 | tag-close *tag-close* |
|
390 | 394 | updated-vars (cond-> vars |
391 | 395 | should-add-var? (conj v))] |
392 | 396 | (recur |
393 | | - updated-vars |
394 | | - nested-keys |
395 | | - (rest tags))) |
| 397 | + updated-vars |
| 398 | + nested-keys |
| 399 | + (rest tags))) |
396 | 400 | (= :for tag-name) (let [[ids [_ items]] (aggregate-args args)] |
397 | 401 | (recur |
398 | | - (conj vars (parse-variable-paths items)) |
399 | | - (conj (set (map keyword ids)) :forloop) |
400 | | - (rest tags))) |
| 402 | + (conj vars (parse-variable-paths items)) |
| 403 | + (conj (set (map keyword ids)) :forloop) |
| 404 | + (rest tags))) |
401 | 405 |
|
402 | 406 | (= :with tag-name) (let [[id value] (string/split (first args) #"=")] |
403 | 407 | (recur |
404 | | - (conj vars (parse-variable-paths value)) |
405 | | - #{(keyword id)} |
406 | | - (rest tags))) |
| 408 | + (conj vars (parse-variable-paths value)) |
| 409 | + #{(keyword id)} |
| 410 | + (rest tags))) |
407 | 411 |
|
408 | 412 | (contains? #{:endfor :endwith} tag-name) (recur vars #{} (rest tags)) |
409 | 413 |
|
410 | 414 | :else |
411 | 415 | (let [special-syms #{nil :not :all :any :< :> := :<= :>=} |
412 | 416 | should-remove? (fn [[var-head :as var]] |
413 | 417 | (or |
414 | | - (special-syms var-head) |
415 | | - (nested-keys var-head)))] |
| 418 | + (special-syms var-head) |
| 419 | + (nested-keys var-head)))] |
416 | 420 |
|
417 | 421 | (recur (set/union |
418 | | - vars |
419 | | - (->> args |
420 | | - (filter (complement literal?)) |
421 | | - (map parse-variable-paths) |
422 | | - (remove should-remove?) |
423 | | - set)) |
| 422 | + vars |
| 423 | + (->> args |
| 424 | + (filter (complement literal?)) |
| 425 | + (map parse-variable-paths) |
| 426 | + (remove should-remove?) |
| 427 | + set)) |
424 | 428 | nested-keys |
425 | 429 | (rest tags)))) |
426 | 430 | vars))) |
|
0 commit comments