p2p-db / test / ird / p2p / db / api_purity_test.cljs
263 words
 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
(ns ird.p2p.db.api-purity-test
  "The public-API hard rule, enforced. Every public namespace — every
  src/ird/p2p/db/**/*.cljs EXCEPT src/ird/p2p/db/impl/** — must contain
  zero JS interop: no `^js` meta, no `js/...`, no `.-` property access, no
  `#js` literal, no `js-obj`, no `goog/`, no `aget`/`aset`. All values that
  cross a public boundary are pure ClojureScript data plus core.async
  channels; bytes travel as base64 strings, with the impl namespaces doing
  the conversion. This test scans the source files and fails listing every
  offending file and pattern."
  (:require [clojure.string :as str]
            [cljs.test :refer [deftest is]]))

(def ^:private fs (js/require "node:fs"))
(def ^:private path (js/require "node:path"))

(defn- cljs-files [dir]
  (mapcat (fn [entry]
            (let [full (.join path dir (.-name entry))]
              (cond
                (.isDirectory entry) (cljs-files full)
                (str/ends-with? (.-name entry) ".cljs") [full]
                :else [])))
          (.readdirSync fs dir #js {:withFileTypes true})))

(def ^:private forbidden
  ["^js" "js/" ".-" "#js" "js-obj" "goog/" "(aget" "(aset"])

(defn- public-ns-files []
  (->> (cljs-files "src/ird/p2p/db")
       (remove #(str/includes? % "/impl/"))
       (filter #(.existsSync fs %))
       distinct
       sort))

(deftest public-namespaces-have-zero-js-interop
  (let [files (public-ns-files)]
    (is (<= 4 (count files)) "the public surface is present (core, crypto, identity, errors)")
    (doseq [f files]
      (let [src (.readFileSync fs f "utf8")
            hits (filter #(str/includes? src %) forbidden)]
        (is (empty? hits) (str f " contains forbidden JS interop: " (pr-str (vec hits))
                               " — interop belongs under src/ird/p2p/db/impl/"))))))

(deftest impl-is-the-only-interop-boundary
  ;; a sanity check that the scan actually looks at real files, not an empty set
  (let [impl (filter #(str/includes? % "/impl/") (cljs-files "src/ird/p2p/db"))]
    (is (seq impl) "there are impl namespaces")
    (is (some (fn [f] (str/includes? (.readFileSync fs f "utf8") "js/")) impl)
        "impl namespaces do use interop, so the scan distinguishes them")))

static mirror of HEAD · about · clone: git clone https://ird.cod-sursa.ro/p2p-db.git