Skip to content

Commit 6ceb61c

Browse files
committed
Added erlang.js which defines erlang terms
Updated gulp dist task so that the order of files is correct. Refactored the CLI module. ElixirScript takes the input given to it and makes it into one big es6 module. The es6 imports and the module name are taken from a new config file (either exjs.exs by default).
1 parent f276a1c commit 6ceb61c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1040
-893
lines changed

config/config.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ use Mix.Config
2121
# Configuration from the imported file will override the ones defined
2222
# here (which is why it is important to import them last).
2323
#
24-
# import_config "#{Mix.env}.exs"
24+
# import_config "#{Mix.env}.exs"

exjs.exs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
defmodule ElixirScript.Config do
2+
3+
def project() do
4+
[
5+
app: :app,
6+
js_deps: []
7+
]
8+
end
9+
end
10+

gulpfile.js

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,39 @@ var concat = require('gulp-concat');
44
var babel = require('gulp-babel');
55
var eslint = require('gulp-eslint');
66

7-
var stdLibPath = './priv/javascript/lib/**/*.js';
8-
9-
var testPath = './priv/javascript/build/tests/**/*.spec.js';
7+
var path = './priv/javascript';
8+
9+
var stdLibPath = path + '/lib/**/*.js';
10+
11+
var testPath = path + '/build/tests/**/*.spec.js';
12+
13+
var libPath = path + '/lib';
14+
15+
var libs = [
16+
libPath + '/bit_string.js',
17+
libPath + '/erlang.js',
18+
libPath + '/kernel/js.js',
19+
libPath + '/kernel/special_forms.js',
20+
libPath + '/kernel.js',
21+
libPath + '/atom.js',
22+
libPath + '/enum.js',
23+
libPath + '/integer.js',
24+
libPath + '/list.js',
25+
libPath + '/logger.js',
26+
libPath + '/mutable.js',
27+
libPath + '/range.js',
28+
libPath + '/tuple.js'
29+
];
1030

1131
gulp.task('dist', function() {
12-
return gulp.src([stdLibPath])
13-
.pipe(babel({sourceMap: false, modules:'ignore'}))
32+
return gulp.src(libs)
33+
.pipe(babel({ sourceMap: false, modules:'ignore' }))
1434
.pipe(concat('elixir.js'))
1535
.pipe(gulp.dest('./priv/javascript/dist'));
1636
});
1737

1838
gulp.task('build', function() {
19-
return gulp.src([stdLibPath, '!./priv/javascript/build/**/*.js', '!./priv/javascript/*.js'])
39+
return gulp.src([libPath + '/**/*.js'])
2040
.pipe(babel({sourceMap: false, modules:'common'}))
2141
.pipe(gulp.dest('./priv/javascript/build/lib'));
2242
});

lib/elixir_script.ex

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ defmodule ElixirScript do
1515
"""
1616
@spec parse_quoted(Macro.t) :: {binary, ESTree.Node.t}
1717
def parse_quoted(quoted) do
18-
js_ast = ElixirScript.Translator.translate(quoted)
19-
{"output.json", js_ast}
18+
ElixirScript.Translator.translate(quoted)
2019
end
2120

2221
@doc """
@@ -26,31 +25,10 @@ defmodule ElixirScript do
2625
def parse_elixir_files(path) do
2726
path
2827
|> Path.wildcard
29-
|> Enum.map(fn(x) -> parse_elixir_file(x) end)
30-
end
31-
32-
defp parse_elixir_file(path) do
33-
js_ast = path
34-
|> File.read!
28+
|> Enum.map(fn(x) -> File.read!(x) end)
29+
|> Enum.join("\n")
3530
|> Code.string_to_quoted!
36-
|> ElixirScript.Translator.translate
37-
38-
file_name = Path.basename(path, ".ex") <> ".json"
39-
40-
{file_name, js_ast}
41-
end
42-
43-
@doc """
44-
Converts JavaScript AST into JavaScript code
45-
"""
46-
@spec javascript_ast_to_code({binary, ESTree.Node.t}) :: {binary, binary} | {:error, binary}
47-
def javascript_ast_to_code({ path, js_ast }) do
48-
case javascript_ast_to_code(js_ast) do
49-
{:ok, js_code} ->
50-
{ Path.basename(path, ".json") <> ".js", js_code }
51-
{:error, error} ->
52-
{:error, error}
53-
end
31+
|> ElixirScript.Translator.translate
5432
end
5533

5634
@doc """
@@ -78,25 +56,29 @@ defmodule ElixirScript do
7856
end
7957

8058
@doc """
81-
Writes output to file
59+
Same as javascript_ast_to_code but throws an error
8260
"""
83-
@spec write_to_files([{binary, binary}], binary) :: nil
84-
def write_to_files(list, destination) when is_list(list) do
85-
Enum.each(list, &write_to_files(&1, destination))
61+
@spec javascript_ast_to_code!(ESTree.Node.t) :: binary
62+
def javascript_ast_to_code!(js_ast) do
63+
case javascript_ast_to_code(js_ast) do
64+
{:ok, js_code } ->
65+
js_code
66+
{:error, error } ->
67+
raise ElixirScript.ParseError, message: error
68+
end
8669
end
8770

8871
@doc """
8972
Writes output to file
9073
"""
91-
@spec write_to_files({binary, binary}, binary) :: :ok | no_return
92-
def write_to_files({file_name, js}, destination) do
93-
file_name = Path.join([destination, file_name])
74+
def write_to_file(js_code, destination) do
75+
file_name = Path.join([destination, "#{app_name()}.js"])
9476

9577
if !File.exists?(destination) do
9678
File.mkdir_p!(destination)
9779
end
9880

99-
File.write!(file_name, js)
81+
File.write!(file_name, js_code)
10082
end
10183

10284

@@ -112,6 +94,39 @@ defmodule ElixirScript do
11294
end
11395
end
11496

115-
def js_import(module, opts \\ []) do
97+
def post_process_js_ast(js_ast) do
98+
ESTree.Builder.program(
99+
ElixirScript.PostProcessor.create_import_statements() ++
100+
List.wrap(ElixirScript.PostProcessor.create_root_object()) ++
101+
List.wrap(js_ast) ++
102+
List.wrap(ElixirScript.PostProcessor.export_root_object())
103+
)
104+
end
105+
106+
def load_config() do
107+
load_config("exjs.exs")
108+
end
109+
110+
def load_config(path) do
111+
modules = Code.load_file(path)
112+
113+
Enum.each(modules, fn({ module, _ }) ->
114+
case module do
115+
ElixirScript.Config ->
116+
config = module.project()
117+
Application.put_env(:elixir_script, :app, config[:app])
118+
Application.put_env(:elixir_script, :js_deps, config[:js_deps])
119+
end
120+
end)
121+
end
122+
123+
def capitalize_app_name() do
124+
Atom.to_string(app_name())
125+
|> String.capitalize
126+
|> String.to_atom
127+
end
128+
129+
def app_name() do
130+
Application.get_env(:elixir_script, :app)
116131
end
117132
end

lib/elixir_script/cli.ex

Lines changed: 90 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -6,118 +6,124 @@ defmodule ElixirScript.CLI do
66
end
77

88
def parse_args(args) do
9-
switches = [ output: :binary, ast: :boolean, elixir: :boolean, stdio: :boolean, lib: :boolean]
10-
aliases = [ o: :output, t: :ast, ex: :elixir, st: :stdio ]
9+
switches = [
10+
output: :binary, ast: :boolean, elixir: :boolean,
11+
lib: :boolean, config: :binary, help: :boolean,
12+
stdio: :boolean
13+
]
14+
15+
aliases = [ o: :output, t: :ast, ex: :elixir, c: :config, h: :help, l: :lib, st: :stdio ]
1116

1217
parse = OptionParser.parse(args, switches: switches, aliases: aliases)
1318

1419
case parse do
15-
{ [stdio: true] , _ , _ } -> {:stdio}
16-
{ [lib: true] , _ , _ } -> {:lib}
17-
{ [ output: output, ast: true, elixir: true], [input], _ } -> { input, output, :ast, :elixir}
18-
{ [ output: output, ast: true], [input], _ } -> { input, output, :ast }
19-
{ [ast: true, elixir: true] , [input], _ } -> { input, :ast, :elixir }
20-
{ [ ast: true ] , [input], _ } -> { input, :ast }
21-
22-
{ [ output: output, elixir: true], [input], _ } -> { input, output, :elixir}
23-
{ [ output: output], [input], _ } -> { input, output }
24-
25-
{ [elixir: true] , [input], _ } -> { input, :elixir }
26-
{ [] , [input], _ } -> { input }
27-
_ -> :help
20+
{ [lib: true] , _ , _ } -> :lib
21+
{ [help: true] , _ , _ } -> :help
22+
23+
{ [{:stdio, true} | options] , [], _ } -> { :stdio, options }
24+
25+
{ options , [input], _ } -> { input, options }
2826
end
2927

3028
end
3129

32-
def process({ input, output, :ast, :elixir }) do
33-
input
34-
|> ElixirScript.parse_elixir
35-
|> ElixirScript.write_to_files(output)
36-
end
30+
def process(:lib) do
31+
path = ElixirScript.operating_path
3732

38-
def process({ input, output, :ast }) do
39-
input
40-
|> ElixirScript.parse_elixir_files
41-
|> ElixirScript.write_to_files(output)
33+
file = File.read!("#{path}/elixir.js")
34+
IO.write(file)
4235
end
4336

44-
def process({ input, :ast }) do
45-
input
46-
|> ElixirScript.parse_elixir_files
47-
|> Enum.map(fn({_path, ast})->
48-
ast
49-
|> Poison.encode!
50-
|> IO.write
51-
end)
52-
end
37+
def process(:help) do
38+
IO.write """
39+
usage: ex2js <input> [options]
5340
54-
def process({ input, :ast, :elixir }) do
55-
{_path, ast} = input
56-
|> ElixirScript.parse_elixir
41+
<input> path to elixir files or
42+
the elixir code string if the -ex flag is used
5743
58-
ast
59-
|> Poison.encode!
60-
|> IO.write
61-
end
44+
options:
6245
63-
def process({ input, :elixir }) do
64-
{_path, js} = input
65-
|> ElixirScript.parse_elixir
66-
|> ElixirScript.javascript_ast_to_code
46+
-ex --elixir read input as elixir code string
6747
68-
IO.write(js)
69-
end
48+
-o --output [path] places output at the given path
49+
-t --ast shows only produced spider monkey ast
50+
-c --config [path] path to exjs.exs configuration file (defaults to exjs.exs)
7051
71-
def process({ input, output, :elixir }) do
72-
input
73-
|> ElixirScript.parse_elixir
74-
|> ElixirScript.write_to_files(output)
52+
-l --lib writes the standard lib js to standard out
53+
-h --help this message
54+
"""
7555
end
7656

77-
def process({ input, output }) do
78-
input
79-
|> ElixirScript.parse_elixir_files
80-
|> Enum.map(&ElixirScript.javascript_ast_to_code(&1))
81-
|> ElixirScript.write_to_files(output)
82-
end
57+
def process({ :stdio, options }) do
58+
case options[:config] do
59+
nil ->
60+
ElixirScript.load_config()
61+
path ->
62+
ElixirScript.load_config(path)
63+
end
8364

84-
def process({ :stdio }) do
8565
Enum.each(IO.stream(:stdio, 5000), fn(x) ->
86-
process({x, :elixir})
87-
end)
88-
end
66+
js_ast = ElixirScript.parse_elixir(x)
67+
|> ElixirScript.post_process_js_ast
8968

90-
def process({ :lib }) do
91-
path = ElixirScript.operating_path
69+
parse_result = case options[:ast] do
70+
true ->
71+
Poison.encode!(js_ast)
72+
_ ->
73+
ElixirScript.javascript_ast_to_code!(js_ast)
74+
end
9275

93-
file = File.read!("#{path}/elixir.js")
94-
IO.write(file)
76+
IO.write(parse_result)
77+
end)
9578
end
9679

97-
def process({ input }) do
98-
input
99-
|> ElixirScript.parse_elixir_files
100-
|> Enum.map(&ElixirScript.javascript_ast_to_code(&1))
101-
|> Enum.map(fn({_path, code})->
102-
IO.write(code)
103-
end)
80+
def process({ input, options }) do
81+
if options_contains_unknown_values(options) do
82+
process(:help)
83+
else
84+
do_process(input, options)
85+
end
10486
end
10587

106-
def process(:help) do
107-
IO.write """
108-
usage: ex2js <input> [options]
88+
def do_process(input, options) do
89+
case options[:config] do
90+
nil ->
91+
ElixirScript.load_config()
92+
path ->
93+
ElixirScript.load_config(path)
94+
end
10995

110-
<input> path to elixir files or
111-
the elixir code string if the -ex flag is used
96+
js_ast = case options[:elixir] do
97+
true ->
98+
ElixirScript.parse_elixir(input)
99+
_ ->
100+
ElixirScript.parse_elixir_files(input)
101+
end
112102

113-
options:
103+
js_ast = ElixirScript.post_process_js_ast(js_ast)
114104

115-
-o --output [path] places output at the given path
116-
-t --ast shows only produced spider monkey ast
117-
-ex --elixir read input as elixir code string
118-
-st --stdio reads from stdio
119-
--lib writes the standard lib js to standard out
120-
-h --help this message
121-
"""
105+
parse_result = case options[:ast] do
106+
true ->
107+
Poison.encode!(js_ast)
108+
_ ->
109+
ElixirScript.javascript_ast_to_code!(js_ast)
110+
end
111+
112+
case options[:output] do
113+
nil ->
114+
IO.write(parse_result)
115+
output_path ->
116+
ElixirScript.write_to_file(parse_result, output_path)
117+
end
118+
end
119+
120+
def options_contains_unknown_values(options) do
121+
Enum.any?(options, fn({key, value}) ->
122+
if key in [:output, :ast, :elixir, :lib, :config] do
123+
false
124+
else
125+
true
126+
end
127+
end)
122128
end
123129
end

0 commit comments

Comments
 (0)