Skip to content

Instantly share code, notes, and snippets.

@geraldodev
Created May 16, 2022 09:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save geraldodev/2e61f7968bb65997cabc3bde3225b214 to your computer and use it in GitHub Desktop.
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
(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',
}"]
(print
(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