cloJS
A library for Clojure to convert Clojure code to JavaScript. It combines the simplicity of Clojure syntax with the power of JavaScript libraries. So all the function calls are of JavaScript.
clojs
artifacts are released to Clojars.
If you are using Maven, add the following repository definition to your pom.xml
:
<repository>
<id>clojars.org</id>
<url>http://clojars.org/repo</url>
</repository>
With Leiningen
With Maven:
<dependency>
<groupId>clojs</groupId>
<artifactId>clojs</artifactId>
<version>0.1.4</version>
</dependency>
node.js
escodegen npm package
npm
(node.js package manager) is installed with node.js
. escodegen
can be installed by typing:
npm install escodegen
in your terminal/command line.
Please open issues against the cloJS repo on Github.
Please ask questions on the cloJS mailing list.
This is for:
You write Clojure syntax code using JavaScript functions and it is converted into JavaScript code.
The namespace for code conversion in the clojs
library is clojs.clojs
.
(require '[clojs.clojs :refer [convert convert-string] :as cj])
Convert a code snippet as string with convert-string
. It takes a string(Clojure code) and returns a string(JavaScript code):
(convert-string "(def a 1)")
=> const a = 1;
Convert one or more files containing code with convert
. It takes the path of each input file as a string and creates the equivalent JavaScript file(.js) in the same folder as the input file:
(convert "a.clj" "resources/b.clj")
=> nil
This will create a.js
in the folder where a.clj
is present and b.js
in the resources
folder where b.clj
is present.
Note: If a.js
or b.js
are already present in the respective folders, they will be overwritten.
Here's a sample Clojure app that uses clojs
Here is all the syntax that clojs
supports:
Legend: a -> b
means a
in Clojure is converted to b
in JavaScript
Input literal type | Input | Output | Output literal type |
---|---|---|---|
String | "abc" | 'abc' | String |
Number | 123 , 123.456 | 123 , 123.456 | Number |
Nil | nil | null | Null |
Boolean | true , false | true , false | Boolean |
Note
null
in JavaScript is nil
in Clojure.""
as delimiters.Identifiers like variable names, function names are converted as it is.
Note to Clojure programmers: Do not use -
in variable/function names like string-length
because running the resulting JavaScript code will error out as JavaScript use infix notation and -
is not allowed in identifiers. Use _
instead like string_length
.
["abc" 123 nil true false [1 2 3]]
->
['abc', 123, null, true, false, [1, 2, 3]]
No commas in Clojure. Nesting is supported.
{"a" 1 "b" {10 "t" 20 "f"} c 3 "d" [1 2 3]}
->
{'a': 1, 'b': { 10: 't', 20: 'f'}, c: 3, 'd': [1, 2, 3]}
No semicolons or commas in Clojure. Nesting is supported.
Note: Literals, identifiers, vectors, objects are not supported at the top-level. They have to be inside parentheses.
def
-> const
(def a 1 b "xyz" c nil d true e [1 2 3] f a g {a 1})
->
const a = 1, b = 'xyz', c = null, d = true, e = [1, 2, 3], f = a, g = {a: 1}
(def h e[0] i g.a j g["a"])
->
const h = e[0], i = g.a, j = g['a'];
Note: Currently only 1D arrays are supported i.e. a[1][2]
wont work.
As Clojure uses prefix notation you can give any number of arguments to the operators. clojs
requires them to be greater than or equal to two.
Input | Output |
---|---|
(+ a b 1 1.2 c) | a + b + 1 + 1.2 + c |
(- a b 1 1.2 c) | a - b - 1 - 1.2 - c |
(* a b 1 1.2 c) | a * b * 1 * 1.2 * c |
(/ a b 1 1.2 c) | a / b / 1 / 1.2 / c |
(mod a b 1 1.2 c) | a % b % 1 % 1.2 % c |
(< a b 1 1.2 c) | a < b < 1 < 1.2 < c |
(<= a b 1 1.2 c) | a <= b <= 1 <= 1.2 <= c |
(> a b 1 1.2 c) | a > b > 1 > 1.2 > c |
(>= a b 1 1.2 c) | a >= b >= 1 >= 1.2 >= c |
(= a b 1 1.2 c) | a === b === 1 === 1.2 === c |
(== a b 1 1.2 c) | a == b == 1 == 1.2 == c |
(!== a b 1 1.2 c) | a !== b !== 1 !== 1.2 !== c |
(!= a b 1 1.2 c) | a != b != 1 != 1.2 != c |
(in a b 1 1.2 c) | a in b in 1 in 1.2 in c |
(instanceof a b 1 1.2 c) | a instanceof b instanceof 1 instanceof 1.2 instanceof c |
(and a b 1 1.2 c) | a && b && 1 && 1.2 && c |
(or a b 1 1.2 c) | a || b || 1 || 1.2 || c |
Input | Output |
---|---|
(not a) | !a |
(typeof a) | typeof a |
if
statement(if (= n 0)
true
false)
if (n === 0)
true;
else
false;
(console.log 1 2 "abc" a b)
->
console.log(1, 2, "abc", a, b);
No commas in Clojure.
do
(if (= 1 1)
(do (console.log "x :" x)
(console.log "y :" y)
(console.log "z :" z))
(do (console.log "a :" a)
(console.log "b :" b)
(console.log "c :" c))
->
if (1 === 1) {
console.log('x :', x);
console.log('y :', y);
console.log('z :', z);;
} else {
console.log('a :', a);
console.log('b :', b);
console.log('c :', c);
}
defn
(defn factorial [n]
(if (= n 0)
1
(* n (factorial (- n 1)))))
->
const factorial = n => {
if (n === 0)
return 1;
else
return n * factorial(n - 1);
};
Return is implicit. The last statement is the return statement.
(fn [x]
(console.log x)
(console.log (+ 5 x)))
->
x => {
console.log(x);
return console.log(5 + x);
};
let
(fn [x]
(console.log x)
(let a 2 b 5)
(console.log (+ 5 x a b)))
->
x => {
console.log(x);
let a = 2, b = 5;
return console.log(5 + x + a + b);
};
cond
-> if-else
chain(fn [x]
(cond
(is_array_member form) (do (get_array_member form) (+ 1 2))
(is_defn form) (get_defn form)
(is_def form) (get_const form)
(is_if form) (get_if form)
(is_do form) (get_do form)
(is_vec form) (get_vec form)
(is_lambda form) (get_lambda form)
(is_map_ds form) (get_map_ds form)
(is_literal form) (get_literal form)
(is_operator form) (get_operator form)
(is_fn_call form) (get_fn_call form)
true nil))
->
x => {
if (is_array_member(form)) {
get_array_member(form);
return 1 + 2;
} else if (is_defn(form))
return get_defn(form);
else if (is_def(form))
return get_const(form);
else if (is_if(form))
return get_if(form);
else if (is_do(form))
return get_do(form);
else if (is_vec(form))
return get_vec(form);
else if (is_lambda(form))
return get_lambda(form);
else if (is_map_ds(form))
return get_map_ds(form);
else if (is_literal(form))
return get_literal(form);
else if (is_operator(form))
return get_operator(form);
else if (is_fn_call(form))
return get_fn_call(form);
else if (true)
return null;
};
(defmacro m-bind [mv mf]
(conj (list ~mv test) ~mf))
(m-bind mvv mff)
->
mff(mvv, test);
You can see a converted sample containing all the syntax: all.clj
-> all.js
clojs
uses this AST to convert it into an equivalent JavaScript AST in JSON format.Released under the Eclipse Public License: https://github.com/puneetpahuja/cloJS/blob/master/LICENSE
Can you improve this documentation? These fine people already did:
Puneet Pahuja & PuneetEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close