Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions .clj-kondo/imports/metosin/malli-types-clj/config.edn
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,21 @@
:req {:cwd :string}},
:handler {:op :keys,
:req {:includes :sequential,
:excludes :sequential}},
:excludes :sequential,
:config-map :map,
:aliases :map}},
:interceptor {:op :keys,
:req {:includes :sequential,
:excludes :sequential}},
:excludes :sequential,
:config-map :map}},
:log {:op :keys,
:req {:level :keyword}},
:opt {:appenders :map},
:req {:min-level :keyword}},
:server {:op :keys,
:req {:host :string,
:port :int}}}}}}}},
:port :int,
:entrypoints :map}}}}}}},
lint-config {:arities {1 {:args [:string], :ret :nilable/map}}}},
elin.function.connect {client-identifier {:arities {1 {:args [:any],
:ret :string}}}},
elin.util.interceptor {self {:arities {1 {:args [:map],
Expand Down
58 changes: 49 additions & 9 deletions bin/elin
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#_{:clj-kondo/ignore [:namespace-name-mismatch]}
(ns elin
(:require
[clojure.pprint :as pp]
[babashka.cli :as cli]
[babashka.deps :as deps]
[clojure.java.io :as io]
Expand All @@ -21,16 +22,24 @@

(require
'[babashka.process :as b.process]
'[elin.config :as e.config]
'[elin.function.jack-in :as e.f.jack-in]
'[elin.util.nrepl :as e.u.nrepl])

(def ^:private global-cli-options
{:help {:default false :coerce :boolean}})

(def ^:private cli-options-map
{"repl" {:force-leiningen {:coerce :boolean}
:force-shadow-cljs {:coerce :boolean}
:dry-run {:coerce :boolean}
:port {:coerce :long :validate pos?}
:instant {:coerce :boolean}
:help {:default false :coerce :boolean}}})
{"repl" ^{:doc "Start a REPL session in the current project."}
{:force-leiningen {:coerce :boolean}
:force-shadow-cljs {:coerce :boolean}
:dry-run {:coerce :boolean}
:port {:coerce :long :validate pos?}
:instant {:coerce :boolean}
:help {:default false :coerce :boolean}}

"lint" ^{:doc "Lint the elin configuration in the current project."}
{:help {:default false :coerce :boolean}}})

(def ^:private elin-option-map
(update-vals cli-options-map #(->> (keys %)
Expand All @@ -52,14 +61,45 @@

(defn- show-help
[sub-command]
(let [spec (get cli/parse-opts sub-command)]
(let [spec (get cli-options-map sub-command)]
(cli/format-opts (merge {:spec spec}
{:order (vec (keys spec))}))))

(defn- show-available-sub-commands
[]
(str "Available sub-commands:\n"
(->> cli-options-map
(map (fn [[cmd options]]
(let [desc (or (:doc (meta options)) "")]
(format " %s\t%s" cmd desc))))
(str/join "\n"))))

(defmulti dispatch first)
(defmethod dispatch :default
[_]
(throw (ex-info "Unknown command" {})))
[args]
(let [options (cli/parse-opts args global-cli-options)]
(if (:help options)
(println (show-available-sub-commands))
(throw (ex-info "Unknown command" {})))))

(defmethod dispatch "lint"
[args]
(let [dir (System/getProperty "user.dir")
sub-command (first args)
{:keys [options]} (parse-opts args)]
(if (:help options)
(println (show-help sub-command))
(if-let [result (e.config/lint-config dir)]
(do
(doseq [[root-key errors] result]
(println (format "### %s" (name root-key)))
(->> errors
(mapcat (fn [[k vs]]
(map #(hash-map :key k :error %) vs)))
(pp/print-table))
(println ""))
(System/exit 1))
(println "Configuration lint passed.")))))

(defmethod dispatch "repl"
[args]
Expand Down
2 changes: 1 addition & 1 deletion dev/analysis.edn

Large diffs are not rendered by default.

58 changes: 28 additions & 30 deletions resources/config.edn
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,22 @@
:test-var #resource "template/var_test_skeleton.mustache"}
:.cljc {:src #resource "template/clj_src_skeleton.mustache"
:test #resource "template/cljc_test_skeleton.mustache"
:test-var #resource "template/var_test_skeleton.mustache"}}}
:test-var #resource "template/var_test_skeleton.mustache"}}

:interceptor {:preset {:evaluation {:includes [elin.interceptor.evaluate/output-eval-result-to-cmdline
elin.interceptor.evaluate/set-eval-result-to-virtual-text
elin.interceptor.evaluate/unwrap-comment-form
elin.interceptor.evaluate/yank-eval-result
elin.interceptor.evaluate/show-last-stacktrace]}

:test {:includes [elin.interceptor.test/correct-test-vars-automatically
elin.interceptor.test/register-started-at
elin.interceptor.test/parse-test-result
elin.interceptor.test/update-test-result-sign
elin.interceptor.test/append-test-result-to-info-buffer
elin.interceptor.test/apply-test-result-to-quickfix
elin.interceptor.test/store-last-failed-test-query
elin.interceptor.test/output-test-result-to-cmdline]}}}}

:interceptor {:uses [elin.interceptor.autocmd/deinitialize {}
elin.interceptor.autocmd/switch-connection {}
Expand Down Expand Up @@ -45,22 +60,7 @@
:highlight "DiffText"
:align "after"
:close-after 3000}
elin.interceptor.evaluate/show-last-stacktrace {:ignoring-vars #include "ignoring_stacktrace_vars.edn"}}

:preset {:evaluation {:includes [elin.interceptor.evaluate/output-eval-result-to-cmdline
elin.interceptor.evaluate/set-eval-result-to-virtual-text
elin.interceptor.evaluate/unwrap-comment-form
elin.interceptor.evaluate/yank-eval-result
elin.interceptor.evaluate/show-last-stacktrace]}

:test {:includes [elin.interceptor.test/correct-test-vars-automatically
elin.interceptor.test/register-started-at
elin.interceptor.test/parse-test-result
elin.interceptor.test/update-test-result-sign
elin.interceptor.test/append-test-result-to-info-buffer
elin.interceptor.test/apply-test-result-to-quickfix
elin.interceptor.test/store-last-failed-test-query
elin.interceptor.test/output-test-result-to-cmdline]}}}
elin.interceptor.evaluate/show-last-stacktrace {:ignoring-vars #include "ignoring_stacktrace_vars.edn"}}}

:handler {:uses [elin.handler.callback/callback {}
elin.handler.complete/complete {:log {:min-level :error}}
Expand All @@ -73,11 +73,11 @@
elin.handler.debug/enable-debug-log {}
elin.handler.debug/disable-debug-log {}
elin.handler.evaluate/evaluate {:interceptor {:includes [elin.interceptor.evaluate/output-eval-result-to-cmdline]}}
elin.handler.evaluate/evaluate-at-mark {:interceptor #ref [:interceptor :preset :evaluation]}
elin.handler.evaluate/evaluate-at-mark {:interceptor #ref [:common :interceptor :preset :evaluation]}
elin.handler.evaluate/evaluate-current-buffer {:interceptor {:includes [elin.interceptor.nrepl/output-result-to-cmdline]}}
elin.handler.evaluate/evaluate-current-expr {:interceptor #ref [:interceptor :preset :evaluation]}
elin.handler.evaluate/evaluate-current-list {:interceptor #ref [:interceptor :preset :evaluation]}
elin.handler.evaluate/evaluate-current-top-list {:interceptor #ref [:interceptor :preset :evaluation]}
elin.handler.evaluate/evaluate-current-expr {:interceptor #ref [:common :interceptor :preset :evaluation]}
elin.handler.evaluate/evaluate-current-list {:interceptor #ref [:common :interceptor :preset :evaluation]}
elin.handler.evaluate/evaluate-current-top-list {:interceptor #ref [:common :interceptor :preset :evaluation]}
elin.handler.evaluate/evaluate-namespace-form {:interceptor {:includes [elin.interceptor.evaluate/output-eval-result-to-cmdline]}}
elin.handler.evaluate/expand-1 {:interceptor {:uses [elin.interceptor.handler/append-result-to-info-buffer {:show-temporarily? true}]}}
elin.handler.evaluate/expand-1-current-list {:interceptor {:uses [elin.interceptor.handler/append-result-to-info-buffer {:show-temporarily? true}]}}
Expand All @@ -89,7 +89,7 @@
elin.handler.evaluate/undef-all {:interceptor {:includes [elin.interceptor.nrepl/output-result-to-cmdline]}}
elin.handler.internal/error {}
elin.handler.internal/healthcheck {:log {:min-level :error}}
elin.handler.internal/initialize {}
elin.handler.internal/initialize {:export {"g:elin_http_server_port" #ref [:http-server :port]}}
elin.handler.internal/intercept {}
elin.handler.internal/status {:log {:min-level :error}
:label {:disconnected ""
Expand Down Expand Up @@ -142,11 +142,11 @@
elin.handler.navigate/local-references {:interceptor {:includes [elin.interceptor.handler/jump-to-file]}}
elin.handler.tap/tapped {:interceptor {:uses [elin.interceptor.handler/append-result-to-info-buffer {:show-temporarily? true
:header ";; Tapped value\n"}]}}
elin.handler.test/rerun-last-failed-tests {:interceptor #ref [:interceptor :preset :test]}
elin.handler.test/rerun-last-tests {:interceptor #ref [:interceptor :preset :test]}
elin.handler.test/run-test-under-cursor {:interceptor #ref [:interceptor :preset :test]}
elin.handler.test/run-tests-in-ns {:interceptor #ref [:interceptor :preset :test]}
elin.handler.test/run-all-tests {:interceptor #ref [:interceptor :preset :test]}]
elin.handler.test/rerun-last-failed-tests {:interceptor #ref [:common :interceptor :preset :test]}
elin.handler.test/rerun-last-tests {:interceptor #ref [:common :interceptor :preset :test]}
elin.handler.test/run-test-under-cursor {:interceptor #ref [:common :interceptor :preset :test]}
elin.handler.test/run-tests-in-ns {:interceptor #ref [:common :interceptor :preset :test]}
elin.handler.test/run-all-tests {:interceptor #ref [:common :interceptor :preset :test]}]

:aliases {elin-alias-evaluate-current-list-in-context {:handler elin.handler.evaluate/evaluate-current-list
:config {:interceptor {:includes [elin.interceptor.evaluate/eval-with-context]}}}
Expand All @@ -164,9 +164,7 @@
elin.interceptor.evaluate/yank-eval-result]}}}
;; Used in operator
elin-alias-evaluate-in-context {:handler elin.handler.evaluate/evaluate
:config {:interceptor {:includes [elin.interceptor.evaluate/eval-with-context]}}}}

:initialize {:export {"g:elin_http_server_port" #ref [:http-server :port]}}}
:config {:interceptor {:includes [elin.interceptor.evaluate/eval-with-context]}}}}}

:clj-kondo {:command "clj-kondo"
:config {:output {:analysis {:protocol-impls true
Expand Down
11 changes: 11 additions & 0 deletions src/elin/config.clj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
[elin.schema.config :as e.s.config]
[elin.util.file :as e.u.file]
[malli.core :as m]
[malli.error :as me]
[malli.transform :as mt]
[taoensso.timbre :as timbre])
(:import
Expand Down Expand Up @@ -219,6 +220,16 @@
config
config-transformer)))

(m/=> lint-config [:=> [:cat string?] [:maybe map?]])
(defn lint-config
[dir]
(let [dummy-server-config {:plugin {:edn-files []}
:env {:cwd dir}
:server {:host "dummy" :port 12345}}
conf (load-config dir dummy-server-config)]
(-> (m/explain e.s.config/?ConfigLinter conf)
(me/humanize))))

(comment
(def config (load-config "." {:server {:host "" :port 0}
:env {:cwd "."}})))
10 changes: 6 additions & 4 deletions src/elin/handler/internal.clj
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

(m/=> initialize [:=> [:cat e.s.handler/?Elin] any?])
(defn initialize
[{:component/keys [handler host clj-kondo]}]
[{:as elin :component/keys [host clj-kondo]}]
(e.p.host/on-connect host)
(e.p.clj-kondo/restore clj-kondo)
(doseq [[export-name export-value] (or (get-in handler [:initialize :export]) {})]
(timbre/debug (format "Exporting %s as %s" export-value export-name))
(e.p.host/set-variable! host export-name export-value))

(let [{:keys [export]} (e.u.handler/config elin #'initialize)]
(doseq [[export-name export-value] (or export {})]
(timbre/debug (format "Exporting %s as %s" export-value export-name))
(e.p.host/set-variable! host export-name export-value)))
true)

(m/=> intercept [:=> [:cat e.s.handler/?Elin] any?])
Expand Down
35 changes: 30 additions & 5 deletions src/elin/schema/config.clj
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
(ns elin.schema.config)
(ns elin.schema.config
(:require
[malli.util :as mu]))

(def ^:private ?Env
[:map
[:cwd string?]])

(def ^:private ?ConfigMap
[:map-of qualified-symbol? map?])

(def ^:private ?HandlerAlias
[:map
[:handler qualified-symbol?]
[:config map?]])

(def ^:private ?Handler
[:map
[:includes {:default []} [:sequential qualified-symbol?]]
[:excludes {:default []} [:sequential qualified-symbol?]]])
[:excludes {:default []} [:sequential qualified-symbol?]]
[:config-map {:default {}} ?ConfigMap]
[:aliases {:default {}} [:map-of symbol? ?HandlerAlias]]])

(def ?InterceptorItem
[:or
Expand All @@ -17,19 +29,22 @@
(def ^:private ?Interceptor
[:map
[:includes {:default []} [:sequential ?InterceptorItem]]
[:excludes {:default []} [:sequential ?InterceptorItem]]])
[:excludes {:default []} [:sequential ?InterceptorItem]]
[:config-map {:default {}} ?ConfigMap]])

(def ^:private ?LogLevel
[:enum :debug :info :warning :error])

(def ^:private ?Log
[:map
[:level {:default :info} ?LogLevel]])
[:min-level {:default :info} ?LogLevel]
[:appenders {:optional true} map?]])

(def ^:private ?Server
[:map
[:host string?]
[:port int?]])
[:port int?]
[:entrypoints map?]])

(def ?Config
[:map
Expand All @@ -38,3 +53,13 @@
[:interceptor {:default {}} ?Interceptor]
[:log {:default {}} ?Log]
[:server ?Server]])

(def ?ConfigLinter
(let [top-schema-keys (->>
(mu/subschemas ?Config)
(filter #(= 1 (count (:path %))))
(map (comp first :path)))]
(reduce
(fn [accm k]
(mu/update accm k mu/closed-schema))
?Config top-schema-keys)))
10 changes: 9 additions & 1 deletion test/elin/config_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@
(t/deftest load-config-test
(with-redefs [sut/load-user-config (constantly {})
sut/load-project-local-config (constantly {})]
(let [server-config {:server {:host "" :port 0}
(let [server-config {:server {:host "" :port 0 :entrypoints {}}
:env {:cwd "."}}
test-load-config #(sut/load-config "." server-config)
base-config (test-load-config)
Expand Down Expand Up @@ -313,3 +313,11 @@
(with-redefs [sut/load-user-config (constantly {:interceptor {:includes [random-symbol]}})
sut/load-project-local-config (constantly {:interceptor {:excludes [random-symbol]}})]
(t/is (nil? (find-included-interceptor (test-load-config) random-symbol)))))))))

(t/deftest lint-config-test
(with-redefs [sut/load-project-local-config (constantly {})]
(t/is (nil? (sut/lint-config "."))))

(with-redefs [sut/load-project-local-config (constantly {:handler {:invalid "foo"}})]
(t/is (= {:handler {:invalid ["disallowed key"]}}
(sut/lint-config ".")))))
Loading