Selaa lähdekoodia

Add first pass at large vars linter

Had to tweak rewrite-clj to read vars with metadata.
Added fail fast behavior to fns to prevent silent failure
which was impacting tasks. Started looking at a few vars. More to look
at
Gabriel Horner 3 vuotta sitten
vanhempi
sitoutus
40eb74a47c

+ 3 - 0
.github/workflows/build.yml

@@ -103,6 +103,9 @@ jobs:
       - name: Carve lint for unused vars
         run: scripts/carve.clj
 
+      - name: Lint for vars that are too large
+        run: scripts/large_vars.clj
+
       - name: Lint invalid translation entries
         run: bb lang:invalid-translations
 

+ 42 - 0
scripts/large_vars.clj

@@ -0,0 +1,42 @@
+#!/usr/bin/env bb
+
+(ns large-vars
+  "This script detects vars that are too large and that make it difficult for
+  the team to maintain and understand them."
+  (:require [babashka.pods :as pods]
+            [clojure.set :as set]))
+
+(pods/load-pod 'clj-kondo/clj-kondo "2021.12.19")
+(require '[pod.borkdude.clj-kondo :as clj-kondo])
+
+(def config
+  ;; TODO: Discuss with team and agree on lower number
+  {:max-lines-count 100
+   ;; Vars with these metadata flags are allowed. Name should indicate the reason
+   ;; it is allowed
+   :metadata-exceptions #{::data-var}})
+
+(defn -main
+  [args]
+  (let [paths (or args ["src"])
+        {{:keys [var-definitions]} :analysis}
+        (clj-kondo/run!
+         {:lint paths
+          :config {:output {:analysis {:var-definitions {:meta true}}}}})
+        vars (->> var-definitions
+                  (keep (fn [m]
+                          (let [lines-count (inc (- (:end-row m) (:row m)))]
+                            (when (and (> lines-count (:max-lines-count config))
+                                       (empty? (set/intersection (set (keys (:meta m)))
+                                                                 (:metadata-exceptions config))))
+                              {:var (:name m)
+                               :lines-count lines-count
+                               :filename (:filename m)}))))
+                  (sort-by :lines-count (fn [x y] (compare y x))))]
+    (if (seq vars)
+      (do (prn vars)
+        (System/exit 1))
+      (println "All vars are below the max size!"))))
+
+(when (= *file* (System/getProperty "babashka.file"))
+  (-main *command-line-args*))

+ 12 - 11
scripts/src/logseq/tasks/lang.clj

@@ -6,12 +6,13 @@
 
 (defn- get-dicts
   []
-  (dissoc (rewrite-clj/var-sexp "src/main/frontend/dicts.cljs" "dicts")
+  (dissoc (rewrite-clj/metadata-var-sexp "src/main/frontend/dicts.cljs" "dicts")
           :tongue/fallback))
 
 (defn- get-non-en-shortcuts
   []
-  (nth (rewrite-clj/var-sexp "src/main/frontend/modules/shortcut/dict.cljs" "dict")
+  (nth (rewrite-clj/metadata-var-sexp "src/main/frontend/modules/shortcut/dict.cljs"
+                                      "dict")
        3))
 
 ;; unnecessary complexity :(
@@ -22,7 +23,7 @@
 
 (defn- get-en-shortcut-dicts
   []
-  (->> (rewrite-clj/var-sexp
+  (->> (rewrite-clj/metadata-var-sexp
         "src/main/frontend/modules/shortcut/config.cljs"
         "all-default-keyboard-shortcuts")
        (map (fn [[k v]] (vector (decorate-namespace k) (:desc v))))
@@ -55,14 +56,14 @@
         en-count (count (dicts :en))
         langs (get-languages)]
     (->> dicts
-           (map (fn [[locale dicts]]
-                  [locale
-                   (Math/round (* 100.0 (/ (count dicts) en-count)))
-                   (count dicts)
-                   (langs locale)]))
-           (sort-by #(nth % 2) >)
-           (map #(zipmap [:locale :percent-translated :translation-count :language] %))
-           task-util/print-table)))
+         (map (fn [[locale dicts]]
+                [locale
+                 (Math/round (* 100.0 (/ (count dicts) en-count)))
+                 (count dicts)
+                 (langs locale)]))
+         (sort-by #(nth % 2) >)
+         (map #(zipmap [:locale :percent-translated :translation-count :language] %))
+         task-util/print-table)))
 
 (defn- shorten [s length]
   (if (< (count s) length)

+ 20 - 8
scripts/src/logseq/tasks/rewrite_clj.clj

@@ -2,14 +2,26 @@
   "Rewrite-clj fns"
   (:require [rewrite-clj.zip :as z]))
 
-(defn- find-symbol-first-right-sexpr
-  [zloc sym]
-  ;; Returns first symbol found
-  (-> (z/find-value zloc z/next sym)
-      z/right
-      z/sexpr))
+(defn- find-symbol-value-sexpr
+  ([zloc sym] (find-symbol-value-sexpr zloc sym z/right))
+  ([zloc sym nav-fn]
+   ;; Returns first symbol found
+   (-> (z/find-value zloc z/next sym)
+       nav-fn
+       z/sexpr)))
 
 (defn var-sexp
+  "Returns value sexp to the right of var"
   [file string-var]
-  (let [zloc (z/of-string (slurp file))]
-    (find-symbol-first-right-sexpr zloc (symbol string-var))))
+  (let [zloc (z/of-string (slurp file))
+        sexp (find-symbol-value-sexpr zloc (symbol string-var))]
+    (or sexp
+        (throw (ex-info "var-sexp must not return nil" {:file file :string-var string-var})))))
+
+(defn metadata-var-sexp
+  "Returns value sexp to the right of var with metadata"
+  [file string-var]
+  (let [zloc (z/of-string (slurp file))
+        sexp (find-symbol-value-sexpr zloc (symbol string-var) (comp z/right z/up))]
+    (or sexp
+        (throw (ex-info "sexp must not return nil" {:file file :string-var string-var})))))

+ 1 - 1
src/main/frontend/dicts.cljs

@@ -3,7 +3,7 @@
             [shadow.resource :as rc]
             [tongue.core :as tongue]))
 
-(def dicts
+(def ^:large-vars/data-var dicts
   {:en {:tutorial/text (rc/inline "tutorial-en.md")
         :tutorial/dummy-notes (rc/inline "dummy-notes-en.md")
         :on-boarding/title "Hi, welcome to Logseq!"

+ 3 - 3
src/main/frontend/modules/shortcut/config.cljs

@@ -19,7 +19,7 @@
 
 ;; Note – when you change this file, you will need to do a hard reset.
 ;; The commands are registered when the Clojurescript code runs for the first time
-(defonce all-default-keyboard-shortcuts
+(defonce ^:large-vars/data-var all-default-keyboard-shortcuts
   {:date-picker/complete         {:desc    "Date picker: Choose selected day"
                                   :binding "enter"
                                   :fn      ui-handler/shortcut-complete}
@@ -449,7 +449,7 @@
   (reduce into {}
           (map (fn [sym] {sym (get all-default-keyboard-shortcuts sym)}) symbols)))
 
-(defonce config
+(defonce ^:large-vars/data-var config
   (atom
    {:shortcut.handler/date-picker
     (build-category-map [:date-picker/complete
@@ -584,7 +584,7 @@
      (with-meta {:before m/enable-when-not-editing-mode!}))}))
 
 ;; Categories for docs purpose
-(def category
+(def ^:large-vars/data-var category
   {:shortcut.category/basics
    ^{:doc "Basics"}
    [:editor/new-block

+ 1 - 1
src/main/frontend/modules/shortcut/dict.cljs

@@ -2,7 +2,7 @@
   (:require [frontend.modules.shortcut.data-helper :as dh]
             [frontend.modules.shortcut.macro :refer [shortcut-dict]]))
 
-(def dict
+(def ^:large-vars/data-var dict
   (shortcut-dict
    (dh/desc-helper)
    (dh/category-helper)