|
10 | 10 | :doc "Parse Clojure namespace (ns) declarations and extract
|
11 | 11 | dependencies."}
|
12 | 12 | clojure.tools.namespace.parse
|
13 |
| - (:require [clojure.set :as set])) |
14 |
| - |
15 |
| -(defn- read-clj |
16 |
| - "Calls clojure.core/read. If reader conditionals are |
17 |
| - supported (Clojure 1.7) then adds options {:read-cond :allow}." |
18 |
| - [rdr] |
19 |
| - (if (resolve 'clojure.core/reader-conditional?) |
20 |
| - (read {:read-cond :allow} rdr) |
21 |
| - (read rdr))) |
22 |
| - |
23 |
| -(defn- force-errors |
24 |
| - "Forces reader errors to be thrown immediately. Some versions of |
25 |
| - Clojure accept invalid forms in the reader and only throw an |
26 |
| - exception when they are printed. |
27 |
| - See http://dev.clojure.org/jira/browse/TNS-1" |
28 |
| - [form] |
29 |
| - (str form) ; str forces errors |
30 |
| - form) |
| 13 | + (:require #?(:clj [clojure.tools.reader :as reader] |
| 14 | + :cljs [cljs.tools.reader :as reader]) |
| 15 | + [clojure.set :as set])) |
31 | 16 |
|
32 | 17 | (defn comment?
|
33 | 18 | "Returns true if form is a (comment ...)"
|
|
40 | 25 | (and (list? form) (= 'ns (first form))))
|
41 | 26 |
|
42 | 27 | (defn read-ns-decl
|
43 |
| - "Attempts to read a (ns ...) declaration from a |
44 |
| - java.io.PushbackReader, and returns the unevaluated form. Returns |
45 |
| - the first top-level ns form found. Returns nil if read fails or if a |
46 |
| - ns declaration cannot be found. Note that read can execute code |
47 |
| - (controlled by *read-eval*), and as such should be used only with |
48 |
| - trusted sources." |
49 |
| - [rdr] |
50 |
| - {:pre [(instance? java.io.PushbackReader rdr)]} |
51 |
| - (try |
| 28 | + "Attempts to read a (ns ...) declaration from a reader, and returns |
| 29 | + the unevaluated form. Returns the first top-level ns form found. |
| 30 | + Returns nil if a ns declaration cannot be found. Note that read can |
| 31 | + execute code (controlled by tools.reader/*read-eval*), and as such |
| 32 | + should be used only with trusted sources. read-opts is passed |
| 33 | + through to tools.reader/read, defaults to allow conditional reader |
| 34 | + expressions with :clj" |
| 35 | + ([rdr] |
| 36 | + (read-ns-decl rdr {:read-cond :allow |
| 37 | + :features #{:clj}})) |
| 38 | + ([rdr read-opts] |
52 | 39 | (loop []
|
53 |
| - (let [form (force-errors (read-clj rdr))] |
54 |
| - (if (ns-decl? form) |
55 |
| - form |
56 |
| - (recur)))) |
57 |
| - (catch Exception e nil))) |
| 40 | + (let [form (reader/read (assoc read-opts :eof ::eof) rdr)] |
| 41 | + (cond |
| 42 | + (ns-decl? form) form |
| 43 | + (= ::eof form) nil |
| 44 | + :else (recur)))))) |
58 | 45 |
|
59 | 46 | ;;; Parsing dependencies
|
60 | 47 |
|
|
91 | 78 | (keyword? form) ; Some people write (:require ... :reload-all)
|
92 | 79 | nil
|
93 | 80 | :else
|
94 |
| - (throw (IllegalArgumentException. |
95 |
| - (pr-str "Unparsable namespace form:" form))))) |
| 81 | + (throw (ex-info "Unparsable namespace form" |
| 82 | + {:reason ::unparsable-ns-form |
| 83 | + :form form})))) |
| 84 | + |
| 85 | +(def ^:private ns-clause-head-names |
| 86 | + "Set of symbol/keyword names which can appear as the head of a |
| 87 | + clause in the ns form." |
| 88 | + #{"use" "require" "use-macros" "require-macros"}) |
| 89 | + |
| 90 | +(def ^:private ns-clause-heads |
| 91 | + "Set of all symbols and keywords which can appear at the head of a |
| 92 | + dependency clause in the ns form." |
| 93 | + (set (mapcat (fn [name] (list (keyword name) |
| 94 | + (symbol name))) |
| 95 | + ns-clause-head-names))) |
96 | 96 |
|
97 | 97 | (defn- deps-from-ns-form [form]
|
98 | 98 | (when (and (sequential? form) ; should be list but sometimes is not
|
99 |
| - (contains? #{:use :require 'use 'require} (first form))) |
| 99 | + (contains? ns-clause-heads (first form))) |
100 | 100 | (mapcat #(deps-from-libspec nil %) (rest form))))
|
101 | 101 |
|
102 | 102 | (defn deps-from-ns-decl
|
|
0 commit comments