diff --git a/.gitignore b/.gitignore index c7535bc..b10f8ad 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ pom.xml.asc /.idea .hgignore .hg/ +/.lsp/ +/.clj-kondo/ diff --git a/src/main/shadow/css.clj b/src/main/shadow/css.clj index 3c611ab..5a984b6 100644 --- a/src/main/shadow/css.clj +++ b/src/main/shadow/css.clj @@ -37,7 +37,7 @@ ;; but may end up emitting invalid references in code ;; which again is fine in JS since it'll just be undefined css-id - (s/generate-id ns-str line column) + (s/generate-id (vec body)) passthrough (->> body diff --git a/src/main/shadow/css/build.cljc b/src/main/shadow/css/build.cljc index 1f0b108..75f5052 100644 --- a/src/main/shadow/css/build.cljc +++ b/src/main/shadow/css/build.cljc @@ -91,11 +91,18 @@ (emitln w " " (name prop) ": " (get group-rules prop) ";")) (emitln w "}"))) -(defn emit-def [w {:keys [sel rules at-rules ns line column rules] :as def}] - ;; (emitln w (str "/* " ns " " line ":" column " */")) +(defn emit-meta-comments + "Within a single comment, output a list of namespaces, line and column numbers + for a given set of rules." + [w rules] + (emitln w (str "/*\n" + (str/join "\n" + (for [{:keys [ns line column]} rules] + (str ns " " line ":" column ))) + "\n*/"))) +(defn emit-def [w {:keys [sel rules at-rules ns line column rules] :as def}] (emit-rule w sel rules) - (doseq [[media-query rules] at-rules] (emitln w media-query "{") (emit-rule w sel rules) @@ -114,8 +121,12 @@ [(doseq [inc classpath-includes] (emitln sw (slurp (io/resource inc))))]) - (doseq [def rules] - (emit-def sw def)) + (doseq [[_ def-rules] (group-by :css-id rules)] + ;; emit comments for all of the rules + (emit-meta-comments sw def-rules) + ;; but we only need to emit the first actual def + (emit-def sw (first def-rules))) + (.toString sw)))))) (defn collect-namespaces-for-chunk @@ -187,8 +198,8 @@ (let [all-rules (->> (for [ns (:chunk-namespaces chunk) :let [{:keys [ns css] :as ns-info} (get namespaces ns)] - {:keys [line column] :as form-info} css - :let [css-id (s/generate-id ns line column)]] + {:keys [form] :as form-info} css + :let [css-id (s/generate-id form)]] (-> (ana/process-form build-state form-info) (assoc :ns ns @@ -499,4 +510,4 @@ (load-colors-from-classpath) (load-indexes-from-classpath) (generate-color-aliases) - (generate-spacing-aliases)))))) \ No newline at end of file + (generate-spacing-aliases)))))) diff --git a/src/main/shadow/css/specs.cljc b/src/main/shadow/css/specs.cljc index 520ef5f..fa1c5c1 100644 --- a/src/main/shadow/css/specs.cljc +++ b/src/main/shadow/css/specs.cljc @@ -1,6 +1,7 @@ (ns shadow.css.specs (:require [clojure.spec.alpha :as s] - [clojure.string :as str])) + [clojure.string :as str] + [clojure.walk :refer [postwalk]])) (s/def ::alias keyword?) @@ -94,11 +95,21 @@ {:parts [] :invalid true :body body :spec (s/explain-data ::class-def body)} conformed))) -(defn generate-id [ns line column] - (str (-> (str ns) - (str/replace #"\." "_") - (munge)) - "__" - "L" line - "_" - "C" column)) \ No newline at end of file +(defn generate-id + "Generates a class name which is unique given the contents. Will account for + different ordering within the subqueries." + [rules] + (str "sc-" (postwalk + (fn [rule] + (cond + ;; postwalk will give you a vector pair for a map before it + ;; gives you the actual map + (map-entry? rule) + rule + + (vector? rule) + (hash (sort rule)) + + :else + (hash rule))) + rules))) diff --git a/src/test/shadow/css/specs_test.cljc b/src/test/shadow/css/specs_test.cljc new file mode 100644 index 0000000..68d601d --- /dev/null +++ b/src/test/shadow/css/specs_test.cljc @@ -0,0 +1,33 @@ +(ns shadow.css.specs-test + (:require + [clojure.test :refer [deftest is testing]] + [shadow.css.specs :as specs])) + +(deftest generate-id-test + (testing "Complex ID" + (is (= "sc--1789522625" + (specs/generate-id [:px-4 :my-2 + "pass" + :c-text-1 + [:&hover :py-10] + [:md+ :px-6 + ["@media print" :px-2]] + [:lg+ :px-8 + [:&hover :py-12]]])))) + + (testing "Order of rules" + (testing "doesn't matter within selectors/main list" + (is (= (specs/generate-id [:px-4 :my-2 + [:&hover :m-4 :py-10 :px-4] + [:lg+ :px-8 + [:&hover :p-4 :py-12]]]) + (specs/generate-id [:px-4 :my-2 + [:&hover :py-10 :m-4 :px-4] + [:lg+ :px-8 + [:&hover :py-12 :p-4]]])))) + + (testing "does matter for the whole structure" + (is (not= (specs/generate-id [:m-4 + [:&hover :px-4]]) + (specs/generate-id [:px-4 + [:&hover :m-4]]))))))