Last active
December 11, 2016 12:28
-
-
Save rauhs/51312236097df2b594e4151f0d567307 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns xyz.utils.css-parser | |
" | |
Generates a bunch of keywords from parsing a CSS files. | |
Useful to get autocompletion when using Cursive (or other editors?) | |
Then you can write you cljs/sablono code like this: | |
[:div {:class [:mdl-chip--contact | |
:mdl-chip--deletable] (etc) | |
" | |
(:require [clojure.java.io :as io] | |
[clojure.string :as str]) | |
(:import (com.helger.css.decl CascadingStyleSheet CSSImportRule CSSNamespaceRule | |
CSSStyleRule CSSPageRule CSSMediaRule CSSFontFaceRule | |
CSSKeyframesRule CSSViewportRule CSSSupportsRule CSSUnknownRule | |
CSSSelector CSSDeclaration CSSMediaQuery CSSKeyframesBlock ECSSSelectorCombinator CSSSelectorMemberNot IHasCSSDeclarations CSSSelectorSimpleMember CSSSelectorAttribute CSSSelectorMemberFunctionLike ECSSAttributeOperator CSSSupportsConditionNested CSSSupportsConditionDeclaration ECSSSupportsConditionOperator CSSSupportsConditionNegation) | |
com.helger.commons.charset.CCharset | |
com.helger.css.ECSSVersion | |
com.helger.css.writer.CSSWriterSettings | |
com.helger.css.reader.CSSReader)) | |
;; Some of this is stolen from: | |
;; https://github.com/degree9/dickory-dock | |
(defprotocol CSSRepresentable | |
"Objects that can be represented as CSS Rule node maps, similar to | |
hickory.core, implement this protocol to make the conversion." | |
(as-css [this] | |
"Converts the node given into a hickory-css-format data structure. The | |
node must have an implementation of the CSSRepresentable protocol; | |
nodes created by parse-css already do.")) | |
(def writer-settings (CSSWriterSettings. (. ECSSVersion CSS30) false)) | |
(defn vec-css [this] (not-empty (into [] (map as-css this)))) | |
(defn get-declarations | |
[^IHasCSSDeclarations this] | |
(not-empty (into (sorted-map) (map as-css (.getAllDeclarations this))))) | |
(extend-protocol CSSRepresentable | |
CascadingStyleSheet | |
(as-css [this] {:type :stylesheet | |
:rules (->> (concat (map as-css (.getAllImportRules this)) | |
(map as-css (.getAllNamespaceRules this)) | |
(map as-css (.getAllRules this))) | |
(into []) | |
not-empty)}) | |
;;;;;;;;;;;;;;;;;;; RULES | |
CSSImportRule | |
(as-css [this] {:type :import | |
:at-rule "@import" | |
:url (.getLocationString this) | |
:queries (vec-css (.getAllMediaQueries this))}) | |
CSSNamespaceRule | |
(as-css [this] {:type :namespace | |
:at-rule "@namespace" | |
:prefix (.getNamespacePrefix this) | |
:url (.getNamespaceURL this)}) | |
CSSMediaRule | |
(as-css [this] {:type :media | |
:at-rule "@media" | |
:queries (vec-css (.getAllMediaQueries this)) | |
:rules (vec-css (.getAllRules this))}) | |
CSSFontFaceRule | |
(as-css [this] {:type :fontface | |
:at-rule "@font-face" | |
:declarations (get-declarations this)}) | |
CSSKeyframesRule | |
(as-css [this] {:type :keyframes | |
:at-rule "@keyframes" | |
:animation (.getAnimationName this) | |
:rules (vec-css (.getAllBlocks this))}) | |
CSSKeyframesBlock | |
(as-css [this] {:type :keyframesblock | |
:selector (vec (.getAllKeyframesSelectors this)) | |
:declarations (get-declarations this)}) | |
CSSViewportRule | |
(as-css [this] {:type :viewport | |
:at-rule "@viewport" | |
:declarations (get-declarations this)}) | |
CSSSupportsRule | |
(as-css [this] {:type :supports | |
:at-rule "@supports" | |
:condition (vec-css (.getAllSupportConditionMembers this)) | |
:rules (vec-css (.getAllRules this))}) | |
CSSStyleRule | |
(as-css [this] {:type :style | |
:selectors (vec-css (.getAllSelectors this)) | |
:declarations (get-declarations this)}) | |
CSSUnknownRule | |
(as-css [this] {:type :unknown | |
:at-rule (.getDeclaration this) | |
:parameters (.getParameterList this) | |
:rules (vec-css (.getBody this))}) | |
;;;;;;;;;;;;;;;;;;;; MISC | |
CSSMediaQuery | |
(as-css [this] (.getAsCSSString this writer-settings 0)) | |
CSSSelector | |
#_(as-css [this] (.getAsCSSString this writer-settings 0)) | |
(as-css [this] (mapv | |
(fn [i] | |
(as-css (.getMemberAtIndex this i))) | |
(range 0 (.getMemberCount this)))) | |
CSSDeclaration | |
(as-css [this] [(keyword (.getProperty this)) | |
(.getAsCSSString (.getExpression this) writer-settings 0)]) | |
;;;;;;;;;;;;;;;;;; Process ICSSSupportsConditionMember | |
CSSSupportsConditionNested | |
(as-css [this] {:type :nested | |
:conditions (vec-css (.getAllMembers this))}) | |
CSSSupportsConditionNegation | |
(as-css [this] {:type :not | |
:condition (as-css (.getSupportsMember this))}) | |
ECSSSupportsConditionOperator | |
(as-css [this] {:type :condition | |
:condition (.getName this)}) | |
CSSSupportsConditionDeclaration | |
(as-css [this] {:type :declaration | |
:declaration (as-css (.getDeclaration this))}) | |
;;;;;;;;;;;;;;;;;; Process ICSSSelectorMember | |
ECSSSelectorCombinator | |
(as-css [this] {:type :combinator | |
:combinator (.getName this)}) | |
CSSSelectorMemberNot | |
(as-css [this] {:not (vec-css (.getAllSelectors this))}) | |
CSSSelectorSimpleMember | |
(as-css [this] {:type (cond | |
(.isHash this) :id | |
(.isClass this) :class | |
(.isPseudo this) :pseudo | |
(.isElementName this) :element) | |
:simple (.getValue this)}) | |
CSSSelectorMemberFunctionLike | |
(as-css [this] {:type :function | |
:function (.getFunctionName this) | |
:selector (as-css (.getParameterExpression this))}) | |
CSSSelectorAttribute | |
(as-css [this] | |
(let [ns-prefix (.getNamespacePrefix this) | |
op (as-css (.getOperator this)) | |
attr-val (.getAttrValue this)] | |
(cond-> {:type :attribute | |
:attr (.getAttrName this)} | |
ns-prefix (assoc :ns ns-prefix) | |
op (assoc :op op) | |
attr-val (assoc :value attr-val)))) | |
;; ~=, =, ^= etc: | |
ECSSAttributeOperator | |
(as-css [this] (.getName this)) | |
nil | |
(as-css [this] nil)) | |
(defn parse-css [^String string] | |
(as-css (CSSReader/readFromString string (. CCharset CHARSET_UTF_8_OBJ) (. ECSSVersion CSS30)))) | |
(defn parse-stylesheet [file] | |
(as-css (CSSReader/readFromFile file (. CCharset CHARSET_UTF_8_OBJ) (. ECSSVersion CSS30)))) | |
#_(def css-data | |
(parse-stylesheet | |
(io/file "." "third-party/mdl/1.2.1" "material.blue-orange.min.css"))) | |
#_(spit "/tmp/mdl-rules.clj" | |
(clojure.pprint/pprint css-data)) | |
(defn get-all-classes | |
"Returns a sorted collection of all css classes" | |
[css-data] | |
(require 'com.rpl.specter) | |
(sort | |
(into #{} | |
(comp (map #(subs % 1)) | |
(map keyword)) | |
(com.rpl.specter/select | |
[(com.rpl.specter/walker (fn [x] | |
(and (map? x) | |
(= :class (:type x)) | |
(:simple x)))) | |
:simple] | |
css-data)))) | |
#_(get-all-classes css-data) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example (partial) output for the css-data: