Created
May 16, 2022 09:55
-
-
Save geraldodev/2e61f7968bb65997cabc3bde3225b214 to your computer and use it in GitHub Desktop.
Generates helix clojurescript output of a React JSX input file. The files are defined on the input-jsx and output-clj variables. the executing function is on the first line of the comment
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 jsx-to-helix.core | |
(:require | |
[clojure.data.xml :as xml] | |
[clojure.edn :as edn] | |
[clojure.java.io :as io] | |
[clojure.pprint :refer [pprint]] | |
[clojure.walk :as walk] | |
[superstring.core :as str] | |
) | |
(:import [clojure.data.xml.node Element])) | |
(def input-jsx "fontes/dev/jsx_to_helix/input.jsx") | |
(def output-clj "fontes/dev/jsx_to_helix/output.clj") | |
(defn js-props-to-string | |
[^String st] | |
(-> st | |
(str/replace #"\{\{" "\"{{") | |
(str/replace #"\}\}" "}}\""))) | |
(defn element? | |
[o] | |
(instance? Element o)) | |
(defn str-indent | |
[^String s indent] | |
(str (str/pad-left "" (* indent 2) " ") | |
s)) | |
(defn format-tag | |
[^String tag] | |
(if (str/lower-case? (subs tag 0 1)) | |
(str "(d/" tag) | |
(str "($ " tag))) | |
(defn jsobj-to-edn | |
[^String obj] | |
(let | |
[o-st (->> | |
(str/split obj #"\n") | |
(mapv | |
(fn [s*] | |
(-> (str/trim s*) | |
(str/replace #"(\/\/)(.+)$" ";;$2") ;; comments from // to ;; | |
(str/replace #"':\s*(\{)" "' $1" ) ;; '&::before': { to '&::before' { | |
(str/replace "\"" "\\\"" ) ;; " to \\\" | |
(str/replace #"'([a-zA-Z@0-9\s]+)':" "\"$1\"") ;; "1: {'@initial': '3', '@bp2': '4'}, " strip : and change ' for " | |
(str/replace "'" "\"" ) ;; ' to " | |
(str/replace #"(\w+)(\:)" "\"$1\"" ) ;; jskey: to "jskey" | |
(str/replace #"\s*$" "" ) ;; strip trailing space | |
(str/replace #"\s*,\s*$" "" ) ;; strip trailing comma | |
))) | |
(str/join "\n")) | |
o (try | |
(-> | |
(edn/read-string o-st) | |
(walk/keywordize-keys) | |
(pr-str )) | |
(catch Exception e)) | |
] | |
(if-not o | |
(str ";; TODO: fix obj \n" " #js " o-st) | |
(str "#js " o)))) | |
(defn format-value | |
[v] | |
(if (and (str/starts-with? v "{{" ) | |
(str/ends-with? v "}}")) | |
(jsobj-to-edn (subs v 1 (dec (count v)))) | |
(str "\"" v "\""))) | |
(defn emit-element | |
[tag attrs indent] | |
(let [lines [(str-indent (format-tag tag) indent)]] | |
(if (empty? attrs) | |
lines | |
(let [count-attrs (dec (count attrs))] | |
(reduce | |
(fn [acc [idx [k v]]] | |
(let [start (if (= idx 0) "{" " ") | |
end? (= idx count-attrs) | |
line (str-indent (str start | |
k | |
" " | |
(format-value v) | |
(when end? "}")) | |
(inc indent)) | |
] | |
(conj acc line))) | |
lines | |
(map-indexed #(identity [%1 %2]) attrs)))))) | |
(defn close-parentheses | |
[v] | |
(assert (vector? v)) | |
(let [last-one (peek v)] | |
(conj (pop v) | |
(str last-one ")")))) | |
;; tag attrs content | |
(defn emit | |
([node] | |
(let [lines (atom [])] | |
(if (element? node) | |
(do | |
(emit node lines 0) | |
(let [result (str/join "\n" @lines)] | |
(spit output-clj result) | |
result)) | |
(throw (ex-info (str Element " expected") | |
{:type ::element-expected}))))) | |
([coll-node lines indent] | |
(cond | |
(element? coll-node) | |
(let [{:keys [tag attrs content ]} coll-node] | |
(swap! | |
lines | |
(fn [lines] | |
(reduce | |
(fn [l i] | |
(conj l i)) | |
lines | |
(emit-element (name tag) attrs indent)))) | |
(when-not (empty? content) | |
(emit content lines (inc indent))) | |
(swap! lines close-parentheses)) | |
(string? coll-node) | |
(let [trimmed (str/trim coll-node)] | |
(when-not (empty? trimmed) | |
(swap! lines | |
conj (str-indent (str "\"" trimmed "\"") indent)))) | |
(coll? coll-node) | |
(doseq [item coll-node] | |
(emit item lines indent))))) | |
(defn process | |
[^String st] | |
(-> st | |
js-props-to-string | |
(java.io.StringReader. ) | |
(xml/parse) | |
)) | |
(defn parse-input | |
[] | |
(some->> | |
(io/file input-jsx) | |
slurp | |
process | |
) | |
) | |
(comment | |
(print (emit (parse-input))) | |
(str/pad-left "" 2) | |
(into [] [:a :b :c]) | |
(coll? (list 1)) | |
(seq? (list 1)) | |
(seq? []) | |
(coll? "") | |
(str/lower-case? (subs "2" 0 1)) | |
(close-parentheses ["abc" "def"]) | |
(count (str/trim "g\n")) | |
(let [st "{{test}}"] (subs st 1 (dec (count st)))) | |
(let [s | |
"{ | |
p: '$5', | |
border: '1px solid $slate6', | |
borderRadius: '$3', | |
}"] | |
(mapv | |
(fn [s*] | |
(prn s*) | |
(str/replace (str/trim s*) #",\s*$" "" ) ;; strip trailing comma | |
) | |
(str/split s #"\n"))) | |
) | |
(pr-str (edn/read-string "{\"foo\" 1}")) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment