Simplify exporting

This commit is contained in:
Michiel Borkent 2021-05-24 11:29:14 +02:00
parent c90b358c62
commit 01fb5d679f
2 changed files with 89 additions and 66 deletions

View file

@ -5,8 +5,8 @@
<script src="js/sci-script-tag-plugin-reagent.js" type="application/javascript"></script> <script src="js/sci-script-tag-plugin-reagent.js" type="application/javascript"></script>
<script type="application/x-sci"> <script type="application/x-sci">
(defn my-alert [] (defn ^:export my-alert []
(js/alert "alert!")) (js/alert "You clicked!"))
(require '[reagent.core :as r] (require '[reagent.core :as r]
'[reagent.dom :as rdom]) '[reagent.dom :as rdom])
@ -23,11 +23,14 @@
</script> </script>
<script src="cljs/script.cljs" type="application/x-sci"></script> <script src="cljs/script.cljs" type="application/x-sci"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/languages/clojure.min.js" type="text/javascript"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/styles/zenburn.min.css" integrity="sha512-JPxjD2t82edI35nXydY/erE9jVPpqxEJ++6nYEoZEpX2TRsmp2FpZuQqZa+wBCen5U16QZOkMadGXHCfp+tUdg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
</head> </head>
<body> <body>
<h1>SCI script tag</h1> <h1>SCI script tag</h1>
<h2>What is this</h2> <h2>What is this?</h2>
<p>This project exposes the <a href="https://github.com/borkdude/sci">Small Clojure Interpreter</a> in the <p>This project exposes the <a href="https://github.com/borkdude/sci">Small Clojure Interpreter</a> in the
browser in such a way that you can use it with the <tt>script</tt> tag.</p> browser in such a way that you can use it with the <tt>script</tt> tag.</p>
<h2>Project status</h2> <h2>Project status</h2>
@ -43,42 +46,53 @@
<h2><a href="#usage">Usage</a></h2> <h2><a href="#usage">Usage</a></h2>
<pre> Include <tt>sci-script-tag.js</tt> and write a <tt>script</tt> tag
&lt;head&gt; where <tt>type</tt> is set
&lt;script src=&quot;https://borkdude.github.io/sci-script-tag/js/sci-script-tag.js&quot; type=&quot;application/javascript&quot;&gt;&lt;/script&gt; to <tt>application/x-sci</tt>. Use <tt>:export</tt> to make the function
&lt;script type=&quot;application/x-sci&quot;&gt; available in the JavaScript environment. The name is processed
(defn my-alert [] using <tt>munge</tt>.
(js/alert &quot;alert!&quot;))
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt; <pre>
&lt;button onclick=&quot;user.myAlert()&quot;&gt; <code class="html">&lt;head&gt;
&lt;script src=&quot;https://borkdude.github.io/sci-script-tag/js/sci-script-tag.js&quot;
type=&quot;application/javascript&quot;&gt;
&lt;/script&gt;
&lt;script type=&quot;application/x-sci&quot;&gt;
(defn ^:export my-alert []
(js/alert &quot;You clicked!&quot;))
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;button onclick=&quot;my_alert()&quot;&gt;
Click me! Click me!
&lt;/button&gt; &lt;/button&gt;
&lt;/body&gt; &lt;/body&gt;</code></pre>
</pre>
<button onclick="user.myAlert()"> <script type="text/javascript">hljs.highlightAll();</script>
Click me
<button onclick="my_alert()">
Click me!
</button> </button>
<h2><a href="#src">Source from file</a></h2> <h2><a href="#src">Source from file</a></h2>
When you have a file on your server, say <tt>cljs/script.cljs</tt>, you can load it using the <tt>src</tt> attribute: When you have a file on your server, say <tt>cljs/script.cljs</tt>, you can load it using the <tt>src</tt> attribute:
<pre> <pre><code class="html">
&lt;script src=&quot;cljs/script.cljs&quot; type=&quot;application/x-sci&quot;&gt;&lt;/script&gt; &lt;script src=&quot;cljs/script.cljs&quot; type=&quot;application/x-sci&quot;&gt;&lt;/script&gt;
</pre> </code></pre>
<h2><a href="#reagent">Reagent plugin<a/></h2> <h2><a href="#reagent">Reagent plugin<a/></h2>
To enable <a href="https://github.com/reagent-project/reagent">reagent</a>, To enable <a href="https://github.com/reagent-project/reagent">reagent</a>,
in addition to <tt>sci-script-tag.js</tt>, you need to include <tt>sci-script-tag-plugin-reagent.js</tt>. in addition to <tt>sci-script-tag.js</tt>, you need to include <tt>sci-script-tag-plugin-reagent.js</tt>.
<pre> <pre><code class="html">
&lt;script src=&quot;https://borkdude.github.io/sci-script-tag/js/sci-script-tag-plugin-reagent.js&quot; type=&quot;application/javascript&quot;&gt;&lt;/script&gt; &lt;script src=&quot;https://borkdude.github.io/sci-script-tag/js/sci-script-tag-plugin-reagent.js&quot; type=&quot;application/javascript&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;application/x-sci&quot;&gt; &lt;script type=&quot;application/x-sci&quot;&gt;
(require '[reagent.core :as r] (require '[reagent.core :as r]
'[reagent.dom :as rdom]) '[reagent.dom :as rdom])
@ -91,8 +105,8 @@
"Click me!"]]]) "Click me!"]]])
(rdom/render [my-component] (.getElementById js/document "app")) (rdom/render [my-component] (.getElementById js/document "app"))
&lt;/script&gt; &lt;/script&gt;
</pre> </code></pre>
<div id="app"></div> <div id="app"></div>
</body> </body>

View file

@ -1,50 +1,59 @@
(ns sci.script-tag (ns sci.script-tag
(:require [clojure.string :as str] (:refer-clojure :exclude [defn])
(:require [clojure.core :as c]
[clojure.string :as str]
[goog.object :as gobject] [goog.object :as gobject]
[goog.string] [goog.string]
[sci.core :as sci])) [sci.core :as sci]))
(defn kebab->camel [s] (c/defmacro defn [fn-name & args]
(str/replace s #"-[a-zA-Z0-9]" (let [ns-sym (gensym "ns")]
(fn [s] `(let [~ns-sym (ns-name *ns*)]
(str/upper-case (.charAt s 1)))))
(defn- defn-macro [_ _ fn-name & args]
`(let [ns# (ns-name *ns*)]
(clojure.core/defn ~fn-name ~@args) (clojure.core/defn ~fn-name ~@args)
(sci.script-tag/-export ~fn-name (str ns# "." '~fn-name)))) ~(when (:export (meta fn-name))
`(sci.script-tag/-export ~fn-name (str ~ns-sym "." '~fn-name))))))
(def ctx (atom (sci/init {:namespaces {'sci.script-tag (c/defn -export [f k]
{'defn (with-meta defn-macro (let [k (munge k)
{:sci/macro true}) parts (str/split k #"\.")]
'-export (fn [f k]
(let [parts (str/split k #"\.")]
(loop [parts parts (loop [parts parts
prev js/window] prev js/window]
(let [fpart (first parts) (let [fpart (first parts)]
fpart (kebab->camel fpart)] (cond (= "user" fpart)
(if (= 1 (count parts)) (recur (rest parts) prev)
(= 1 (count parts))
(gobject/set prev fpart f) (gobject/set prev fpart f)
:else
(if-let [obj (gobject/get prev fpart)] (if-let [obj (gobject/get prev fpart)]
(recur (rest parts) obj) (recur (rest parts) obj)
(let [obj #js {}] (let [obj #js {}]
(gobject/set prev fpart obj) (gobject/set prev fpart obj)
(recur (rest parts) (recur (rest parts)
obj)))))) obj))))))
(gobject/set js/window k f)))} (gobject/set js/window k f)))
'clojure.core {'println println}}
(def stns (sci/create-ns 'sci.script-tag nil))
(def namespaces
{'sci.script-tag
{'defn (sci/copy-var defn stns)
'-export (sci/copy-var -export stns)}
'clojure.core {'println (sci/copy-var println stns)
'prn (sci/copy-var prn stns)}})
(def ctx (atom (sci/init {:namespaces namespaces
:classes {'js js/window :classes {'js js/window
:allow :all}}))) :allow :all}})))
(defn eval-string [s] (c/defn eval-string [s]
(sci/eval-string* @ctx (sci/eval-string* @ctx
(str "(require '[sci.script-tag :refer :all])" (str "(require '[sci.script-tag :refer :all])"
s))) s)))
(defn merge-ctx [opts] (c/defn merge-ctx [opts]
(swap! ctx sci/merge-opts opts)) (swap! ctx sci/merge-opts opts))
(defn- load-contents [script-tags] (c/defn- load-contents [script-tags]
(when-first [tag script-tags] (when-first [tag script-tags]
(if-let [text (not-empty (gobject/get tag "textContent"))] (if-let [text (not-empty (gobject/get tag "textContent"))]
(do (eval-string text) (do (eval-string text)