-
Notifications
You must be signed in to change notification settings - Fork 7
/
analyzer.clj
63 lines (53 loc) · 2.88 KB
/
analyzer.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
(ns clj-depend.analyzer)
(defn- layer-cannot-access-dependency-layer?
[config layer dependency-layer]
(when-let [accesses-layers (get-in config [:layers layer :accesses-layers])]
(not-any? (partial = dependency-layer) accesses-layers)))
(defn- dependency-layer-cannot-be-accessed-by-layer?
[config dependency-layer layer]
(when-let [accessed-by-layers (get-in config [:layers dependency-layer :accessed-by-layers])]
(not-any? (partial = layer) accessed-by-layers)))
(defn- violate?
[config
{:keys [layer dependency-layer]}]
(and (not= layer dependency-layer)
(or (dependency-layer-cannot-be-accessed-by-layer? config dependency-layer layer)
(layer-cannot-access-dependency-layer? config layer dependency-layer))))
(defn- namespace-belongs-to-layer?
[config namespace layer]
(let [namespaces (get-in config [:layers layer :namespaces])
defined-by (get-in config [:layers layer :defined-by])]
(or (some #{namespace} namespaces)
(when defined-by (re-find (re-pattern defined-by) (str namespace))))))
(defn- layer-by-namespace
[config namespace]
(some #(when (namespace-belongs-to-layer? config namespace %) %) (keys (:layers config))))
(defn- layer-and-namespace [config namespace dependency-namespace]
(when-let [layer (layer-by-namespace config namespace)]
{:namespace namespace
:layer layer
:dependency-namespace dependency-namespace
:dependency-layer (layer-by-namespace config dependency-namespace)}))
(defn- layer-violations
[config namespace dependencies]
(->> dependencies
(map #(layer-and-namespace config namespace %))
(filter #(violate? config %))
(map (fn [{:keys [namespace dependency-namespace layer dependency-layer] :as violation}]
(assoc violation :message (str \" namespace \" " should not depend on " \" dependency-namespace \" " (layer " \" layer \" " on " \" dependency-layer \" ")"))))))
(defn ^:private circular-dependency-violations
[namespace dependencies dependencies-by-namespace]
(->> dependencies-by-namespace
(filter (fn [[k _]] (contains? dependencies k)))
(filter (fn [[_ v]] (contains? v namespace)))
(map (fn [[k _]] {:namespace namespace :message (str "Circular dependency between " \" namespace \" " and " \" k \")}))))
(defn- violations
[config dependencies-by-namespace namespace]
(let [dependencies (get dependencies-by-namespace namespace)
circular-dependency-violations (circular-dependency-violations namespace dependencies dependencies-by-namespace)
layer-violations (layer-violations config namespace dependencies)]
(not-empty (concat circular-dependency-violations layer-violations))))
(defn analyze
"Analyze namespaces dependencies."
[{:keys [config dependencies-by-namespace]}]
(flatten (keep #(violations config dependencies-by-namespace %) (keys dependencies-by-namespace))))