Skip to content

Commit 2507423

Browse files
committed
[js] Module import support
1 parent 9866356 commit 2507423

9 files changed

Lines changed: 145 additions & 0 deletions

File tree

src-json/meta.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,13 @@
550550
"targets": ["TClass"],
551551
"links": ["https://haxe.org/manual/target-javascript-require.html"]
552552
},
553+
{
554+
"name": "JsImport",
555+
"metadata": ":js.import",
556+
"doc": "Generate ES module import statement for given extern. Produces import lines at the top of the generated JS output.",
557+
"platforms": ["js"],
558+
"targets": ["TClass"]
559+
},
553560
{
554561
"name": "LuaRequire",
555562
"metadata": ":luaRequire",

src/generators/genjs.ml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,6 +1677,43 @@ let generate js_gen com =
16771677

16781678
let ctx = alloc_ctx com es_version in
16791679
Gctx.map_source_header com.defines (fun s -> print ctx "// %s\n" s);
1680+
1681+
let import_statements = ref [] in
1682+
let () =
1683+
List.iter (fun mt -> match mt with
1684+
| TClassDecl c when (has_class_flag c CExtern) && Meta.has Meta.JsImport c.cl_meta && is_directly_used ctx.com c.cl_meta ->
1685+
let _, args, mp = Meta.get Meta.JsImport c.cl_meta in
1686+
let id = s_path ctx (get_generated_class_path c) in
1687+
(match args with
1688+
(* @:js.import(@star "module") - namespace import *)
1689+
| [EMeta ((Meta.Custom "star",[],_),(EConst(String(module_name,_)),_)),_] ->
1690+
import_statements := (Printf.sprintf "import * as %s from \"%s\";" id module_name) :: !import_statements
1691+
(* @:js.import(@default "module") - default import *)
1692+
| [EMeta ((Meta.Custom "default",[],_),(EConst(String(module_name,_)),_)),_] ->
1693+
import_statements := (Printf.sprintf "import %s from \"%s\";" id module_name) :: !import_statements
1694+
(* @:js.import("module") - named import using class name *)
1695+
| [(EConst(String(module_name,_)),_)] ->
1696+
import_statements := (Printf.sprintf "import { %s } from \"%s\";" id module_name) :: !import_statements
1697+
(* @:js.import("module", "exportName") - named import with alias *)
1698+
| [(EConst(String(module_name,_)),_); (EConst(String(export_name,_)),_)] ->
1699+
if export_name = id then
1700+
import_statements := (Printf.sprintf "import { %s } from \"%s\";" id module_name) :: !import_statements
1701+
else
1702+
import_statements := (Printf.sprintf "import { %s as %s } from \"%s\";" export_name id module_name) :: !import_statements
1703+
| exprs ->
1704+
abort "Unsupported @:js.import format. Use: @:js.import('module'), @:js.import('module', 'name'), @:js.import(@default 'module'), or @:js.import(@star 'module')" mp
1705+
)
1706+
| _ -> ()
1707+
) com.types;
1708+
in
1709+
(match !import_statements with
1710+
| [] -> ()
1711+
| lines ->
1712+
List.iter (fun line ->
1713+
print ctx "%s\n" line
1714+
) (List.rev lines)
1715+
);
1716+
16801717
if has_feature ctx "Class" || has_feature ctx "Type.getClassName" then add_feature ctx "js.Boot.isClass";
16811718
if has_feature ctx "Enum" || has_feature ctx "Type.getEnumName" then add_feature ctx "js.Boot.isEnum";
16821719

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
@:js.import(@star '../lib.js')
2+
extern class Lib {
3+
@:native("default") static function default_():Bool;
4+
static var str:String;
5+
static function increment(i:Int):Int;
6+
}
7+
8+
@:js.import(@star '../lib_default_fun.js')
9+
extern class DefaultFun {
10+
@:native("default") static function default_():Bool;
11+
}
12+
13+
@:js.import(@default '../lib_default_class.js')
14+
extern class DefaultClass {
15+
static function def():Bool;
16+
}
17+
18+
@:js.import('../multilib.js')
19+
extern class Foo {
20+
static function name():String;
21+
}
22+
@:js.import('../multilib.js', 'Foo')
23+
extern class Foo2 {
24+
static function name():String;
25+
}
26+
@:js.import('../multilib.js', 'Bar')
27+
extern class Bar2 {
28+
static function name():String;
29+
}
30+
31+
@:js.import(@default '../multilib.js')
32+
extern class DefaultClass2 {
33+
function new();
34+
function name():Bool;
35+
}
36+
37+
class Main {
38+
static function main() {
39+
eq("str", Lib.str);
40+
eq(2, Lib.increment(1));
41+
eq("default function", Lib.default_());
42+
43+
eq("foo", Foo.name());
44+
eq("foo", Foo2.name());
45+
eq("bar", Bar2.name());
46+
final def = new DefaultClass2();
47+
eq("default class", def.name());
48+
49+
eq("default function", DefaultFun.default_());
50+
eq("default static", DefaultClass.def());
51+
}
52+
53+
static function eq(a:Any, b:Any):Void {
54+
if (a != b) throw '$a is not $b';
55+
}
56+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
--main Main
2+
-dce full
3+
-D analyzer-optimize
4+
--js bin/main.js
5+
--cmd node bin/main
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
--main Main
2+
-dce full
3+
-D analyzer-optimize
4+
--js bin/main.js
5+
--cmd node bin/main
6+
-D js-es=6
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const str = "str";
2+
export function increment(x) {
3+
return x + 1;
4+
}
5+
6+
export default function def() {
7+
return "default function";
8+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default class Lib {
2+
static def() {
3+
return "default static";
4+
}
5+
}
6+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function def() {
2+
return "default function";
3+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export class Foo {
2+
static name() {
3+
return "foo";
4+
}
5+
}
6+
7+
export class Bar {
8+
static name() {
9+
return "bar";
10+
}
11+
}
12+
13+
export default class DefClass {
14+
name() {
15+
return "default class";
16+
}
17+
}

0 commit comments

Comments
 (0)