Opinionated Dart to Clojure converter for Flutter widgets. It doesn't (and probably will not) convert classes, setters, annotations — only the part that could be reused after translation.
There are 7 options now:
- Calva (VSCode);
- Intellij Idea;
- Jvm/Js REPL;
- Clojure Cli;
- Jar;
- Native image;
- Native image, emacs;
- NPM CLI;
- NPM library;
All the converted code would not be idiomatic. Instead of using classes there is a widget macro.
Setters are also useless, there would be a :state
atom
and swap!
or reset!
functions for changing the state.
So I see little value in converting everything.
But rewriting widgets is a routine part and most of the time translates literally:
Center(
child: Text(
_active ? 'Active' : 'Inactive',
style: const TextStyle(fontSize: 32.0, color: Colors.white),
),
);
(m/Center
.child (m/Text
(if _active "Active" "Inactive")
.style (m/TextStyle .fontSize 32.0 .color m.Colors/white)))
3 more examples:
- constructors invocation;
- static, factory methods invocation;
- named arguments;
- (typed) lists, maps, cascade operator (
..
); - math and logical expressions;
- ternary operators;
- lambdas;
- comments (will be removed);
- nesting children with f/nest macro;
- constants;
- variables in strings with$;
- raw (interpreted) strings like
r'some string $dollar'
- class/methods/fields declarations (not tested well, pre-alpha);
- try-catch;
- for in;
- switch with breaks and returns;
- bitwise operators;
- proper aliases for everything, it's not possible to get this info generally;
- enums;
- external keywork;
- yield;
- exports;
- switch with continue, withouth breaks or returns (considered unidiomatic);
- for with declare, conditions and increment (considered unidiomatic)
- while (considered unidiomatic)
- early exits from lambdas (ignored);
...
operator (ignored);- typedefs (ignored);
- annotations (ignored);
- test classes and methods extensively;
- handle early exit from lambdas/if/for/methods with
return
;
Calva (a VSCode Clojure extension) packs DartClojure conversion into a command. This makes it easy to paste some Dart code and convert it.
calva-dart-clojure-conversion.mp4
See calva clojuredart docs for some (tiny) bit more on the subject.
You could use available api (4, 5, 6, 7) directly from Idea with External Tools.
Preferences —> Tools —> External Tools —> +
Program
: any terminal command. For example, if you have npm, install
dartclojure globally and put dartclojure
in the Program
field. If you
downloaded native image, put path to native image here:
/Users/PcName/Downloads/dartclojure-aarch64-darwin
Arguments
: "$SelectedText$"
Thats it. Select code, press shift + shift
(or cmd + shift + a
), type
DartClojure
and press enter (or setup hotkey on it). Little video how it
looks.
Add Cli/deps:
{:deps
{
org.clojars.liverm0r/dartclojure {:mvn/version "0.2.23-SNAPSHOT"}
}}
Or Leiningen/Boot:
[org.clojars.liverm0r/dartclojure "0.2.23-SNAPSHOT"]
Convert dart code (simplify and wrap-nest under the hood):
(require '[dumch.convert :refer [convert]])
(convert "1 + 1 + 2 * 1;" :format :sexpr) ; => (+ 1 1 (* 2 1))
You may pass aliases for material and flutter-macro:
(convert "Text('1')" :material "m" :flutter "f") ; => "(m/Text "1")"
If you just need to wrap clojure code with nest:
(require
'[dumch.improve :as impr]
'[rewrite-clj.zip :as z])
(-> "(Container .child (Box .child (Padding .child (:Text \"2\"))))"
z/of-string
impr/wrap-nest
z/sexpr)
; => (f/nest (Container) (Box) (Padding) (:Text "2"))
clojure -Sdeps \
'{:deps {org.clojars.liverm0r/dartclojure {:mvn/version "0.2.23-SNAPSHOT"}}}' \
-e "(require '[dumch.convert :refer [convert]]) (convert \"Text('1')\" :material \"m\" :flutter \"f\")"
There are two ways to interact with the jar. First one is to run it each time:
$ java -jar dartclojure.jar "Divider(
height: 0,
color: Colors.grey,
)"
(m/Divider .height 0 .color m.Colors/grey)
Second one is to run repl-like console (and send code into it with your editor/idea):
$ java -jar dartclojure.jar -r true -m "material"
Paste dart code below, press enter and see the result:
Divider(
height: 0,
color: Colors.grey,
)
(material/Divider .height 0 .color material.Colors/grey)
Colors are also supported:
For example, you may start the repl-like console app with -e key:
$ java -jar dartclojure.jar -r true -e :end
For all the arguments see:
$ java -jar dartclojure.jar -h
Same api as with jar:
./dartclojure -h
./dartclojure "Text('a')" -m "m"
./dartclojure --path main.dart
./dartclojure -r true
If there is no build for your architecture on release page, see how to build it with graalvm below.
You can use the Emacs package from dartclojure.el via your favorite Emacs package manager.
Same api as with jar and native image:
npm i dartclojure
npx dartclojure -h
npx dartclojure "Text('a')" -m "m"
You can of course also install globally:
npm i -g dartclojure
dartclojure -h
dartclojure "Text('a')" -m "m"
const converter = require('dartclojure');
const clojureCode = converter.convert("Text('a')");
Build jar:
$ clj -T:build uber :version '"0.2.22"'
Run tests:
$ clj -X:test ; clj -M:test-cljs
Run docker, build graalvm image:
$ cp target/dartclojure*.jar dartclojure.jar
$ docker build --pull --no-cache --tag dartclojure .
$ docker run --name dc -it dartclojure ./dartclojure "Text('should work')"
$ docker cp dc:/usr/src/app/dartclojure.
Compile native image with graalvm locally:
# install graalvm
$ chmod +x compile.sh
$ ./compile.sh
Remember to comment out line with -H:+StaticExecutableWithDynamicLibC
for osx m1
builds.
Start shadow-cljs watcher and REPL:
clj -M:shadow-cljs watch :app :lib :test
(You can use this for developing both the Clojure and ClojureScript library, but the test watcher will only be watching and running the ClojureScript tests.)
Install the local npm package:
npm link dartclojure
Copyright © 2022 Artur Dumchev
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.