Fork of daniellemaywood.uk/gleam — Wasm codegen work
74 kB
2592 lines
1use super::*;
2use crate::{
3 ast::SrcSpan,
4 build::{
5 package_compiler::{PackageCompiler, Source},
6 Origin, Target,
7 },
8 codegen,
9 config::{Docs, ErlangConfig, PackageConfig, Repository},
10 erlang,
11 io::test::FilesChannel,
12 javascript, type_,
13};
14use std::{path::PathBuf, sync::Arc};
15
16use hexpm::version::{Range, Version};
17use pretty_assertions::assert_eq;
18
19macro_rules! assert_erlang_compile {
20 ($sources:expr, $expected_output:expr $(,)?) => {
21 let mut modules = HashMap::new();
22 let config = PackageConfig {
23 name: "the_package".to_string(),
24 version: Version::new(1, 0, 0),
25 licences: vec![],
26 description: "The description".into(),
27 documentation: Docs { pages: vec![] },
28 dependencies: [].into(),
29 dev_dependencies: [].into(),
30 repository: Repository::None,
31 links: vec![],
32 erlang: ErlangConfig {
33 application_start_module: None,
34 extra_applications: vec![],
35 },
36 target: Target::Erlang,
37 };
38 let (file_writer, file_receiver) = FilesChannel::new();
39 let root = PathBuf::from("some/build/path/root");
40 let out = PathBuf::from("_build/default/lib/the_package");
41 let mut compiler =
42 PackageCompiler::new(&config, &root, &out, Target::Erlang, "", file_writer);
43 compiler.write_entrypoint = false;
44 compiler.write_metadata = false;
45 compiler.compile_erlang = false;
46 compiler.sources = $sources;
47 let outputs = compiler
48 .compile(&mut vec![], &mut modules, &mut HashMap::with_capacity(4))
49 .map(|_| {
50 let mut outputs = FilesChannel::recv_utf8_files(&file_receiver).unwrap();
51 outputs.sort_by(|a, b| a.path.partial_cmp(&b.path).unwrap());
52 outputs
53 })
54 .map_err(|e| normalise_error(e));
55 assert_eq!($expected_output, outputs);
56 };
57}
58
59macro_rules! assert_javascript_compile {
60 ($sources:expr, $expected_output:expr $(,)?) => {
61 let mut modules = HashMap::new();
62 let config = PackageConfig {
63 name: "the_package".to_string(),
64 version: Version::new(1, 0, 0),
65 licences: vec![],
66 description: "The description".into(),
67 documentation: Docs { pages: vec![] },
68 dependencies: [].into(),
69 dev_dependencies: [].into(),
70 repository: Repository::None,
71 links: vec![],
72 erlang: ErlangConfig {
73 application_start_module: None,
74 extra_applications: vec![],
75 },
76 target: Target::JavaScript,
77 };
78 let (file_writer, file_receiver) = FilesChannel::new();
79 let root = PathBuf::from("some/build/path/root");
80 let out = PathBuf::from("_build/default/lib/the_package");
81 let mut compiler = PackageCompiler::new(
82 &config,
83 &root,
84 &out,
85 Target::JavaScript,
86 "erl/libs/*",
87 file_writer,
88 );
89 compiler.write_entrypoint = false;
90 compiler.write_metadata = false;
91 compiler.compile_erlang = false;
92 compiler.sources = $sources;
93 let outputs = compiler
94 .compile(&mut vec![], &mut modules, &mut HashMap::with_capacity(4))
95 .map(|_| {
96 let mut outputs = FilesChannel::recv_utf8_files(&file_receiver).unwrap();
97 outputs.sort_by(|a, b| a.path.partial_cmp(&b.path).unwrap());
98 outputs
99 })
100 .map_err(|e| normalise_error(e));
101 assert_eq!($expected_output, outputs);
102 };
103}
104
105macro_rules! assert_no_warnings {
106 ($sources:expr $(,)?) => {
107 let mut modules = HashMap::new();
108 let config = PackageConfig {
109 name: "the_package".to_string(),
110 version: Version::new(1, 0, 0),
111 licences: vec![],
112 description: "The description".into(),
113 documentation: Docs { pages: vec![] },
114 dependencies: [].into(),
115 dev_dependencies: [].into(),
116 repository: Repository::None,
117 links: vec![],
118 erlang: ErlangConfig {
119 application_start_module: None,
120 extra_applications: vec![],
121 },
122 target: Target::Erlang,
123 };
124 let mut warnings = vec![];
125 let (file_writer, file_receiver) = FilesChannel::new();
126 let root = PathBuf::from("some/build/path/root");
127 let out = PathBuf::from("_build/default/lib/the_package");
128 let mut compiler =
129 PackageCompiler::new(&config, &root, &out, Target::Erlang, "", file_writer);
130 compiler.write_entrypoint = false;
131 compiler.write_metadata = false;
132 compiler.compile_erlang = false;
133 compiler.sources = $sources;
134 let outputs = compiler
135 .compile(&mut warnings, &mut modules, &mut HashMap::with_capacity(4))
136 .unwrap();
137 assert_eq!(vec![] as Vec<crate::Warning>, warnings);
138 };
139}
140
141#[test]
142fn package_compiler_test() {
143 assert_erlang_compile!(
144 vec![],
145 Ok(vec![OutputFile {
146 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
147 text: "{application, the_package, [
148 {vsn, \"1.0.0\"},
149 {applications, []},
150 {description, \"The description\"},
151 {modules, []},
152 {registered, []}
153]}.
154"
155 .into(),
156 },])
157 );
158
159 assert_erlang_compile!(
160 vec![Source {
161 path: PathBuf::from("src/one.gleam"),
162 name: "one".to_string(),
163 code: "".to_string(),
164 origin: Origin::Src,
165 }],
166 Ok(vec![
167 OutputFile {
168 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
169 text: "{application, the_package, [
170 {vsn, \"1.0.0\"},
171 {applications, []},
172 {description, \"The description\"},
173 {modules, [one]},
174 {registered, []}
175]}.
176"
177 .into(),
178 },
179 OutputFile {
180 text: "-module(one).\n".to_string(),
181 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
182 },
183 ])
184 );
185
186 assert_erlang_compile!(
187 vec![
188 Source {
189 path: PathBuf::from("src/one.gleam"),
190 name: "one".to_string(),
191 code: "".to_string(),
192 origin: Origin::Src,
193 },
194 Source {
195 path: PathBuf::from("src/one.gleam"),
196 name: "two".to_string(),
197 code: "".to_string(),
198 origin: Origin::Src,
199 },
200 ],
201 Ok(vec![
202 OutputFile {
203 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
204 text: "{application, the_package, [
205 {vsn, \"1.0.0\"},
206 {applications, []},
207 {description, \"The description\"},
208 {modules, [one,
209 two]},
210 {registered, []}
211]}.
212"
213 .into(),
214 },
215 OutputFile {
216 text: "-module(one).\n".to_string(),
217 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
218 },
219 OutputFile {
220 text: "-module(two).\n".to_string(),
221 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
222 },
223 ])
224 );
225
226 assert_erlang_compile!(
227 vec![Source {
228 name: "one".to_string(),
229 origin: Origin::Src,
230 path: PathBuf::from("src/one.gleam"),
231 code: "".to_string(),
232 }],
233 Ok(vec![
234 OutputFile {
235 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
236 text: "{application, the_package, [
237 {vsn, \"1.0.0\"},
238 {applications, []},
239 {description, \"The description\"},
240 {modules, [one]},
241 {registered, []}
242]}.
243"
244 .into(),
245 },
246 OutputFile {
247 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
248 text: "-module(one).\n".to_string(),
249 },
250 ]),
251 );
252
253 // TODO: src modules cannot be allowed to import test modules
254 // TODO: Does this get handled at this level? I forget
255 // assert_erlang_compile!(
256 // vec![
257 // Source {
258 // origin: Origin::Test,
259 // name: "two".to_string(),
260 // path: PathBuf::from("/test/two.gleam"),
261 // code: "".to_string(),
262 // },
263 // Source {
264 // origin: Origin::Src,
265 // name: "one".to_string(),
266 // path: PathBuf::from("/src/one.gleam"),
267 // code: "import two".to_string(),
268 // },
269 // ],
270 // Err(Error::SrcImportingTest {
271 // path: PathBuf::from("/src/one.gleam"),
272 // src: "import two".to_string(),
273 // location: crate::ast::SrcSpan { start: 7, end: 10 },
274 // src_module: "one".to_string(),
275 // test_module: "two".to_string(),
276 // }),
277 // );
278
279 assert_erlang_compile!(
280 vec![
281 Source {
282 origin: Origin::Src,
283 path: PathBuf::from("/src/one.gleam"),
284 name: "one".to_string(),
285 code: "import two".to_string(),
286 },
287 Source {
288 origin: Origin::Src,
289 path: PathBuf::from("/src/two.gleam"),
290 name: "two".to_string(),
291 code: "".to_string(),
292 },
293 ],
294 Ok(vec![
295 OutputFile {
296 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
297 text: "{application, the_package, [
298 {vsn, \"1.0.0\"},
299 {applications, []},
300 {description, \"The description\"},
301 {modules, [one,
302 two]},
303 {registered, []}
304]}.
305"
306 .into(),
307 },
308 OutputFile {
309 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
310 text: "-module(one).\n".to_string(),
311 },
312 OutputFile {
313 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
314 text: "-module(two).\n".to_string(),
315 },
316 ]),
317 );
318
319 assert_erlang_compile!(
320 vec![
321 Source {
322 origin: Origin::Src,
323 path: PathBuf::from("/src/one.gleam"),
324 name: "one".to_string(),
325 code: "".to_string(),
326 },
327 Source {
328 origin: Origin::Src,
329 path: PathBuf::from("/src/two.gleam"),
330 name: "two".to_string(),
331 code: "import one".to_string(),
332 },
333 ],
334 Ok(vec![
335 OutputFile {
336 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
337 text: "{application, the_package, [
338 {vsn, \"1.0.0\"},
339 {applications, []},
340 {description, \"The description\"},
341 {modules, [one,
342 two]},
343 {registered, []}
344]}.
345"
346 .into(),
347 },
348 OutputFile {
349 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
350 text: "-module(one).\n".to_string(),
351 },
352 OutputFile {
353 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
354 text: "-module(two).\n".to_string(),
355 },
356 ]),
357 );
358
359 assert_erlang_compile!(
360 vec![
361 Source {
362 origin: Origin::Src,
363 path: PathBuf::from("/src/one.gleam"),
364 name: "one".to_string(),
365 code: "pub type Box { Box(Int) }".to_string(),
366 },
367 Source {
368 origin: Origin::Src,
369 path: PathBuf::from("/src/two.gleam"),
370 name: "two".to_string(),
371 code: "import one pub fn unbox(x) { let one.Box(i) = x i }".to_string(),
372 },
373 ],
374 Ok(vec![
375 OutputFile {
376 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
377 text: "{application, the_package, [
378 {vsn, \"1.0.0\"},
379 {applications, []},
380 {description, \"The description\"},
381 {modules, [one,
382 two]},
383 {registered, []}
384]}.
385"
386 .into(),
387 },
388 OutputFile {
389 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
390 text: "-module(one).
391-compile(no_auto_import).
392
393-export_type([box/0]).
394
395-type box() :: {box, integer()}.
396
397
398"
399 .to_string(),
400 },
401 OutputFile {
402 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
403 text: "-module(two).
404-compile(no_auto_import).
405
406-export([unbox/1]).
407
408-spec unbox(one:box()) -> integer().
409unbox(X) ->
410 {box, I} = X,
411 I.
412"
413 .to_string(),
414 },
415 ]),
416 );
417
418 assert_erlang_compile!(
419 vec![
420 Source {
421 origin: Origin::Test,
422 path: PathBuf::from("/test/one.gleam"),
423 name: "one".to_string(),
424 code: "pub type Box { Box(Int) }".to_string(),
425 },
426 Source {
427 origin: Origin::Test,
428 path: PathBuf::from("/test/two.gleam"),
429 name: "two".to_string(),
430 code: "import one pub fn box(x) { one.Box(x) }".to_string(),
431 },
432 ],
433 Ok(vec![
434 OutputFile {
435 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
436 text: "{application, the_package, [
437 {vsn, \"1.0.0\"},
438 {applications, []},
439 {description, \"The description\"},
440 {modules, [one,
441 two]},
442 {registered, []}
443]}.
444"
445 .into(),
446 },
447 OutputFile {
448 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
449 text: "-module(one).
450-compile(no_auto_import).
451
452-export_type([box/0]).
453
454-type box() :: {box, integer()}.
455
456
457"
458 .to_string(),
459 },
460 OutputFile {
461 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
462 text: "-module(two).
463-compile(no_auto_import).
464
465-export([box/1]).
466
467-spec box(integer()) -> one:box().
468box(X) ->
469 {box, X}.
470"
471 .to_string(),
472 },
473 ]),
474 );
475
476 assert_erlang_compile!(
477 vec![Source {
478 origin: Origin::Src,
479 path: PathBuf::from("/src/one/two.gleam"),
480 name: "one/two".to_string(),
481 code: "pub type Box { Box }".to_string(),
482 }],
483 Ok(vec![
484 OutputFile {
485 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
486 text: "{application, the_package, [
487 {vsn, \"1.0.0\"},
488 {applications, []},
489 {description, \"The description\"},
490 {modules, [one@two]},
491 {registered, []}
492]}.
493"
494 .into(),
495 },
496 OutputFile {
497 path: PathBuf::from("_build/default/lib/the_package/build/one@two.erl"),
498 text: "-module(one@two).
499-compile(no_auto_import).
500
501-export_type([box/0]).
502
503-type box() :: box.
504
505
506"
507 .to_string(),
508 }
509 ]),
510 );
511
512 assert_erlang_compile!(
513 vec![
514 Source {
515 origin: Origin::Src,
516 path: PathBuf::from("/src/one.gleam"),
517 name: "one".to_string(),
518 code: "pub type Box { Box }".to_string(),
519 },
520 Source {
521 origin: Origin::Src,
522 path: PathBuf::from("/src/two.gleam"),
523 name: "two".to_string(),
524 code: "import one pub fn box() { one.Box }".to_string(),
525 },
526 ],
527 Ok(vec![
528 OutputFile {
529 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
530 text: "{application, the_package, [
531 {vsn, \"1.0.0\"},
532 {applications, []},
533 {description, \"The description\"},
534 {modules, [one,
535 two]},
536 {registered, []}
537]}.
538"
539 .into(),
540 },
541 OutputFile {
542 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
543 text: "-module(one).
544-compile(no_auto_import).
545
546-export_type([box/0]).
547
548-type box() :: box.
549
550
551"
552 .to_string(),
553 },
554 OutputFile {
555 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
556 text: "-module(two).
557-compile(no_auto_import).
558
559-export([box/0]).
560
561-spec box() -> one:box().
562box() ->
563 box.
564"
565 .to_string(),
566 },
567 ]),
568 );
569
570 assert_erlang_compile!(
571 vec![
572 Source {
573 origin: Origin::Src,
574 path: PathBuf::from("/src/one.gleam"),
575 name: "one".to_string(),
576 code: "pub fn go() { 1 }".to_string(),
577 },
578 Source {
579 origin: Origin::Src,
580 path: PathBuf::from("/src/two.gleam"),
581 name: "two".to_string(),
582 code: "import one as thingy pub fn call() { thingy.go() }".to_string(),
583 },
584 ],
585 Ok(vec![
586 OutputFile {
587 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
588 text: "{application, the_package, [
589 {vsn, \"1.0.0\"},
590 {applications, []},
591 {description, \"The description\"},
592 {modules, [one,
593 two]},
594 {registered, []}
595]}.
596"
597 .into(),
598 },
599 OutputFile {
600 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
601 text: "-module(one).
602-compile(no_auto_import).
603
604-export([go/0]).
605
606-spec go() -> integer().
607go() ->
608 1.
609"
610 .to_string(),
611 },
612 OutputFile {
613 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
614 text: "-module(two).
615-compile(no_auto_import).
616
617-export([call/0]).
618
619-spec call() -> integer().
620call() ->
621 one:go().
622"
623 .to_string(),
624 },
625 ]),
626 );
627
628 assert_erlang_compile!(
629 vec![
630 Source {
631 origin: Origin::Src,
632 path: PathBuf::from("/src/nested/one.gleam"),
633 name: "nested/one".to_string(),
634 code: "pub type Box { Box(Int) }".to_string(),
635 },
636 Source {
637 origin: Origin::Src,
638 path: PathBuf::from("/src/two.gleam"),
639 name: "two".to_string(),
640 code: "import nested/one
641pub fn go(x) { let one.Box(y) = x y }"
642 .to_string(),
643 },
644 ],
645 Ok(vec![
646 OutputFile {
647 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
648 text: "{application, the_package, [
649 {vsn, \"1.0.0\"},
650 {applications, []},
651 {description, \"The description\"},
652 {modules, [nested@one,
653 two]},
654 {registered, []}
655]}.
656"
657 .into(),
658 },
659 OutputFile {
660 path: PathBuf::from("_build/default/lib/the_package/build/nested@one.erl"),
661 text: "-module(nested@one).
662-compile(no_auto_import).
663
664-export_type([box/0]).
665
666-type box() :: {box, integer()}.
667
668
669"
670 .to_string(),
671 },
672 OutputFile {
673 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
674 text: "-module(two).
675-compile(no_auto_import).
676
677-export([go/1]).
678
679-spec go(nested@one:box()) -> integer().
680go(X) ->
681 {box, Y} = X,
682 Y.
683"
684 .to_string(),
685 },
686 ]),
687 );
688
689 assert_erlang_compile!(
690 vec![
691 Source {
692 origin: Origin::Src,
693 path: PathBuf::from("/src/nested/one.gleam"),
694 name: "nested/one".to_string(),
695 code: "pub type Box { Box(Int) }".to_string(),
696 },
697 Source {
698 origin: Origin::Src,
699 path: PathBuf::from("/src/two.gleam"),
700 name: "two".to_string(),
701 code: "import nested/one as thingy
702pub fn go(x) { let thingy.Box(y) = x y }"
703 .to_string(),
704 },
705 ],
706 Ok(vec![
707 OutputFile {
708 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
709 text: "{application, the_package, [
710 {vsn, \"1.0.0\"},
711 {applications, []},
712 {description, \"The description\"},
713 {modules, [nested@one,
714 two]},
715 {registered, []}
716]}.
717"
718 .into(),
719 },
720 OutputFile {
721 path: PathBuf::from("_build/default/lib/the_package/build/nested@one.erl"),
722 text: "-module(nested@one).
723-compile(no_auto_import).
724
725-export_type([box/0]).
726
727-type box() :: {box, integer()}.
728
729
730"
731 .to_string(),
732 },
733 OutputFile {
734 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
735 text: "-module(two).
736-compile(no_auto_import).
737
738-export([go/1]).
739
740-spec go(nested@one:box()) -> integer().
741go(X) ->
742 {box, Y} = X,
743 Y.
744"
745 .to_string(),
746 },
747 ]),
748 );
749
750 assert_erlang_compile!(
751 vec![
752 Source {
753 origin: Origin::Src,
754 path: PathBuf::from("/src/nested/one.gleam"),
755 name: "nested/one".to_string(),
756 code: "pub external type Thing pub fn go() { 1 }".to_string(),
757 },
758 Source {
759 origin: Origin::Src,
760 path: PathBuf::from("/src/two.gleam"),
761 name: "two".to_string(),
762 code: "import nested/one
763 pub fn go() { one.go() }
764 pub external fn thing() -> one.Thing = \"thing\" \"new\"
765 pub fn call_thing() { thing() }
766 "
767 .to_string(),
768 },
769 ],
770 Ok(vec![
771 OutputFile {
772 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
773 text: "{application, the_package, [
774 {vsn, \"1.0.0\"},
775 {applications, []},
776 {description, \"The description\"},
777 {modules, [nested@one,
778 two]},
779 {registered, []}
780]}.
781"
782 .into(),
783 },
784 OutputFile {
785 path: PathBuf::from("_build/default/lib/the_package/build/nested@one.erl"),
786 text: "-module(nested@one).
787-compile(no_auto_import).
788
789-export([go/0]).
790-export_type([thing/0]).
791
792-type thing() :: any().
793
794-spec go() -> integer().
795go() ->
796 1.
797"
798 .to_string(),
799 },
800 OutputFile {
801 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
802 text: "-module(two).
803-compile(no_auto_import).
804
805-export([go/0, thing/0, call_thing/0]).
806
807-spec go() -> integer().
808go() ->
809 nested@one:go().
810
811-spec thing() -> nested@one:thing().
812thing() ->
813 thing:new().
814
815-spec call_thing() -> nested@one:thing().
816call_thing() ->
817 thing:new().
818"
819 .to_string(),
820 },
821 ]),
822 );
823
824 assert_erlang_compile!(
825 vec![
826 Source {
827 origin: Origin::Src,
828 path: PathBuf::from("/src/one.gleam"),
829 name: "one".to_string(),
830 code: "".to_string(),
831 },
832 Source {
833 origin: Origin::Src,
834 path: PathBuf::from("/test/one.gleam"),
835 name: "one".to_string(),
836 code: "".to_string(),
837 },
838 ],
839 Err(Error::DuplicateModule {
840 module: "one".to_string(),
841 first: PathBuf::from("/src/one.gleam"),
842 second: PathBuf::from("/test/one.gleam"),
843 }),
844 );
845
846 assert_erlang_compile!(
847 vec![
848 Source {
849 origin: Origin::Src,
850 path: PathBuf::from("/src/one.gleam"),
851 name: "one".to_string(),
852 code: "pub type Point { Point(x: Int, y: Int) }".to_string(),
853 },
854 Source {
855 origin: Origin::Src,
856 path: PathBuf::from("/src/two.gleam"),
857 name: "two".to_string(),
858 code: "import one
859pub fn make() { one.Point(1, 4) }
860pub fn x(p) { let one.Point(x, _) = p x }"
861 .to_string(),
862 },
863 ],
864 Ok(vec![
865 OutputFile {
866 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
867 text: "{application, the_package, [
868 {vsn, \"1.0.0\"},
869 {applications, []},
870 {description, \"The description\"},
871 {modules, [one,
872 two]},
873 {registered, []}
874]}.
875"
876 .into(),
877 },
878 OutputFile {
879 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
880 text: "-module(one).
881-compile(no_auto_import).
882
883-export_type([point/0]).
884
885-type point() :: {point, integer(), integer()}.
886
887
888"
889 .to_string(),
890 },
891 OutputFile {
892 path: PathBuf::from("_build/default/lib/the_package/build/one_Point.hrl"),
893 text: "-record(point, {x :: integer(), y :: integer()}).
894"
895 .to_string(),
896 },
897 OutputFile {
898 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
899 text: "-module(two).
900-compile(no_auto_import).
901
902-export([make/0, x/1]).
903
904-spec make() -> one:point().
905make() ->
906 {point, 1, 4}.
907
908-spec x(one:point()) -> integer().
909x(P) ->
910 {point, X, _@1} = P,
911 X.
912"
913 .to_string(),
914 },
915 ]),
916 );
917
918 // Erlang keywords are escaped
919 assert_erlang_compile!(
920 vec![
921 Source {
922 origin: Origin::Src,
923 path: PathBuf::from("/src/one.gleam"),
924 name: "one".to_string(),
925 code: "pub fn div(top x, bottom y) { x%y }".to_string(),
926 },
927 Source {
928 origin: Origin::Src,
929 path: PathBuf::from("/src/two.gleam"),
930 name: "two".to_string(),
931 code: "import one.{div}
932 pub fn run() { 2 |> div(top: _, bottom: 4) |> div(2, bottom: _) }"
933 .to_string(),
934 },
935 ],
936 Ok(vec![
937 OutputFile {
938 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
939 text: "{application, the_package, [
940 {vsn, \"1.0.0\"},
941 {applications, []},
942 {description, \"The description\"},
943 {modules, [one,
944 two]},
945 {registered, []}
946]}.
947"
948 .into(),
949 },
950 OutputFile {
951 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
952 text: "-module(one).
953-compile(no_auto_import).
954
955-export([\'div\'/2]).
956
957-spec \'div\'(integer(), integer()) -> integer().
958'div'(X, Y) ->
959 case Y of
960 0 -> 0;
961 Gleam@denominator -> X rem Gleam@denominator
962 end.
963"
964 .to_string(),
965 },
966 OutputFile {
967 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
968 text: "-module(two).
969-compile(no_auto_import).
970
971-export([run/0]).
972
973-spec run() -> integer().
974run() ->
975 _pipe = 2,
976 _pipe@1 = one:'div'(_pipe, 4),
977 one:'div'(2, _pipe@1).
978"
979 .to_string(),
980 },
981 ]),
982 );
983
984 assert_erlang_compile!(
985 vec![
986 Source {
987 origin: Origin::Src,
988 path: PathBuf::from("/src/one.gleam"),
989 name: "one".to_string(),
990 code: "pub type Empty { Empty }".to_string(),
991 },
992 Source {
993 origin: Origin::Src,
994 path: PathBuf::from("/src/two.gleam"),
995 name: "two".to_string(),
996 code: "import one
997pub fn make() { one.Empty }"
998 .to_string(),
999 },
1000 ],
1001 Ok(vec![
1002 OutputFile {
1003 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1004 text: "{application, the_package, [
1005 {vsn, \"1.0.0\"},
1006 {applications, []},
1007 {description, \"The description\"},
1008 {modules, [one,
1009 two]},
1010 {registered, []}
1011]}.
1012"
1013 .into(),
1014 },
1015 OutputFile {
1016 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1017 text: "-module(one).
1018-compile(no_auto_import).
1019
1020-export_type([empty/0]).
1021
1022-type empty() :: empty.
1023
1024
1025"
1026 .to_string(),
1027 },
1028 OutputFile {
1029 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1030 text: "-module(two).
1031-compile(no_auto_import).
1032
1033-export([make/0]).
1034
1035-spec make() -> one:empty().
1036make() ->
1037 empty.
1038"
1039 .to_string(),
1040 },
1041 ]),
1042 );
1043
1044 assert_erlang_compile!(
1045 vec![
1046 Source {
1047 origin: Origin::Src,
1048 path: PathBuf::from("/src/one.gleam"),
1049 name: "one".to_string(),
1050 code: "pub fn id(x) { x } pub type Empty { Empty }".to_string(),
1051 },
1052 Source {
1053 origin: Origin::Src,
1054 path: PathBuf::from("/src/two.gleam"),
1055 name: "two".to_string(),
1056 code: "import one.{Empty, id} pub fn make() { id(Empty) }".to_string(),
1057 },
1058 ],
1059 Ok(vec![
1060 OutputFile {
1061 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1062 text: "{application, the_package, [
1063 {vsn, \"1.0.0\"},
1064 {applications, []},
1065 {description, \"The description\"},
1066 {modules, [one,
1067 two]},
1068 {registered, []}
1069]}.
1070"
1071 .into(),
1072 },
1073 OutputFile {
1074 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1075 text: "-module(one).
1076-compile(no_auto_import).
1077
1078-export([id/1]).
1079-export_type([empty/0]).
1080
1081-type empty() :: empty.
1082
1083-spec id(H) -> H.
1084id(X) ->
1085 X.
1086"
1087 .to_string(),
1088 },
1089 OutputFile {
1090 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1091 text: "-module(two).
1092-compile(no_auto_import).
1093
1094-export([make/0]).
1095
1096-spec make() -> one:empty().
1097make() ->
1098 one:id(empty).
1099"
1100 .to_string(),
1101 },
1102 ]),
1103 );
1104
1105 // https://github.com/gleam-lang/gleam/issues/303
1106 assert_erlang_compile!(
1107 vec![
1108 Source {
1109 origin: Origin::Src,
1110 path: PathBuf::from("/src/one.gleam"),
1111 name: "one".to_string(),
1112 code: "pub fn id(x) { x } pub type Empty { Empty }".to_string(),
1113 },
1114 Source {
1115 origin: Origin::Src,
1116 path: PathBuf::from("/src/two.gleam"),
1117 name: "two".to_string(),
1118 code: "import one.{Empty as E, id as i} pub fn make() { i(E) }".to_string(),
1119 },
1120 ],
1121 Ok(vec![
1122 OutputFile {
1123 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1124 text: "{application, the_package, [
1125 {vsn, \"1.0.0\"},
1126 {applications, []},
1127 {description, \"The description\"},
1128 {modules, [one,
1129 two]},
1130 {registered, []}
1131]}.
1132"
1133 .into(),
1134 },
1135 OutputFile {
1136 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1137 text: "-module(one).
1138-compile(no_auto_import).
1139
1140-export([id/1]).
1141-export_type([empty/0]).
1142
1143-type empty() :: empty.
1144
1145-spec id(H) -> H.
1146id(X) ->
1147 X.
1148"
1149 .to_string(),
1150 },
1151 OutputFile {
1152 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1153 text: "-module(two).
1154-compile(no_auto_import).
1155
1156-export([make/0]).
1157
1158-spec make() -> one:empty().
1159make() ->
1160 one:id(empty).
1161"
1162 .to_string(),
1163 },
1164 ]),
1165 );
1166
1167 assert_erlang_compile!(
1168 vec![
1169 Source {
1170 origin: Origin::Src,
1171 path: PathBuf::from("/src/one.gleam"),
1172 name: "one".to_string(),
1173 code: "pub fn receive() { 1 }".to_string(),
1174 },
1175 Source {
1176 origin: Origin::Src,
1177 path: PathBuf::from("/src/two.gleam"),
1178 name: "two".to_string(),
1179 code: "import one pub fn funky() { one.receive }".to_string(),
1180 },
1181 ],
1182 Ok(vec![
1183 OutputFile {
1184 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1185 text: "{application, the_package, [
1186 {vsn, \"1.0.0\"},
1187 {applications, []},
1188 {description, \"The description\"},
1189 {modules, [one,
1190 two]},
1191 {registered, []}
1192]}.
1193"
1194 .into(),
1195 },
1196 OutputFile {
1197 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1198 text: "-module(one).
1199-compile(no_auto_import).
1200
1201-export(['receive'/0]).
1202
1203-spec \'receive\'() -> integer().
1204'receive'() ->
1205 1.
1206"
1207 .to_string(),
1208 },
1209 OutputFile {
1210 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1211 text: "-module(two).
1212-compile(no_auto_import).
1213
1214-export([funky/0]).
1215
1216-spec funky() -> fun(() -> integer()).
1217funky() ->
1218 fun one:'receive'/0.
1219"
1220 .to_string(),
1221 },
1222 ]),
1223 );
1224
1225 assert_erlang_compile!(
1226 vec![
1227 Source {
1228 origin: Origin::Src,
1229 path: PathBuf::from("/src/one.gleam"),
1230 name: "one".to_string(),
1231 code: "pub fn receive() { 1 }".to_string(),
1232 },
1233 Source {
1234 origin: Origin::Src,
1235 path: PathBuf::from("/src/two.gleam"),
1236 name: "two".to_string(),
1237 code: "import one.{receive} pub fn funky() { receive }".to_string(),
1238 },
1239 ],
1240 Ok(vec![
1241 OutputFile {
1242 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1243 text: "{application, the_package, [
1244 {vsn, \"1.0.0\"},
1245 {applications, []},
1246 {description, \"The description\"},
1247 {modules, [one,
1248 two]},
1249 {registered, []}
1250]}.
1251"
1252 .into(),
1253 },
1254 OutputFile {
1255 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1256 text: "-module(one).
1257-compile(no_auto_import).
1258
1259-export(['receive'/0]).
1260
1261-spec \'receive\'() -> integer().
1262'receive'() ->
1263 1.
1264"
1265 .to_string(),
1266 },
1267 OutputFile {
1268 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1269 text: "-module(two).
1270-compile(no_auto_import).
1271
1272-export([funky/0]).
1273
1274-spec funky() -> fun(() -> integer()).
1275funky() ->
1276 fun one:'receive'/0.
1277"
1278 .to_string(),
1279 },
1280 ]),
1281 );
1282
1283 // https://github.com/gleam-lang/gleam/issues/340
1284 assert_erlang_compile!(
1285 vec![
1286 Source {
1287 origin: Origin::Src,
1288 path: PathBuf::from("/src/one.gleam"),
1289 name: "one".to_string(),
1290 code: "pub fn receive(x) { x }".to_string(),
1291 },
1292 Source {
1293 origin: Origin::Src,
1294 path: PathBuf::from("/src/two.gleam"),
1295 name: "two".to_string(),
1296 code: "import one pub fn funky() { one.receive(1) }".to_string(),
1297 },
1298 ],
1299 Ok(vec![
1300 OutputFile {
1301 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1302 text: "{application, the_package, [
1303 {vsn, \"1.0.0\"},
1304 {applications, []},
1305 {description, \"The description\"},
1306 {modules, [one,
1307 two]},
1308 {registered, []}
1309]}.
1310"
1311 .into(),
1312 },
1313 OutputFile {
1314 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1315 text: "-module(one).
1316-compile(no_auto_import).
1317
1318-export(['receive'/1]).
1319
1320-spec \'receive\'(H) -> H.
1321'receive'(X) ->
1322 X.
1323"
1324 .to_string(),
1325 },
1326 OutputFile {
1327 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1328 text: "-module(two).
1329-compile(no_auto_import).
1330
1331-export([funky/0]).
1332
1333-spec funky() -> integer().
1334funky() ->
1335 one:'receive'(1).
1336"
1337 .to_string(),
1338 },
1339 ]),
1340 );
1341
1342 // We can use record accessors for types with only one constructor, defined
1343 // in another module
1344 assert_erlang_compile!(
1345 vec![
1346 Source {
1347 origin: Origin::Src,
1348 path: PathBuf::from("/src/one.gleam"),
1349 name: "one".to_string(),
1350 code: "pub type Person { Person(name: String, age: Int) }".to_string(),
1351 },
1352 Source {
1353 origin: Origin::Src,
1354 path: PathBuf::from("/src/two.gleam"),
1355 name: "two".to_string(),
1356 code: "import one.{Person}
1357 pub fn get_age(person: Person) { person.age }
1358 pub fn get_name(person: Person) { person.name }"
1359 .to_string(),
1360 },
1361 ],
1362 Ok(vec![
1363 OutputFile {
1364 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1365 text: "{application, the_package, [
1366 {vsn, \"1.0.0\"},
1367 {applications, []},
1368 {description, \"The description\"},
1369 {modules, [one,
1370 two]},
1371 {registered, []}
1372]}.
1373"
1374 .into(),
1375 },
1376 OutputFile {
1377 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1378 text: "-module(one).
1379-compile(no_auto_import).
1380
1381-export_type([person/0]).
1382
1383-type person() :: {person, binary(), integer()}.
1384
1385
1386"
1387 .to_string(),
1388 },
1389 OutputFile {
1390 path: PathBuf::from("_build/default/lib/the_package/build/one_Person.hrl"),
1391 text: "-record(person, {name :: binary(), age :: integer()}).
1392"
1393 .to_string(),
1394 },
1395 OutputFile {
1396 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1397 text: "-module(two).
1398-compile(no_auto_import).
1399
1400-export([get_age/1, get_name/1]).
1401
1402-spec get_age(one:person()) -> integer().
1403get_age(Person) ->
1404 erlang:element(3, Person).
1405
1406-spec get_name(one:person()) -> binary().
1407get_name(Person) ->
1408 erlang:element(2, Person).
1409"
1410 .to_string(),
1411 },
1412 ]),
1413 );
1414
1415 // Can use imported types in Type Constructors
1416 assert_erlang_compile!(
1417 vec![
1418 Source {
1419 origin: Origin::Src,
1420 path: PathBuf::from("/src/one.gleam"),
1421 name: "one".to_string(),
1422 code: "pub type Person { Person(name: String, age: Int) }".to_string(),
1423 },
1424 Source {
1425 origin: Origin::Src,
1426 path: PathBuf::from("/src/two.gleam"),
1427 name: "two".to_string(),
1428 code: "import one type Two = one.Person".to_string(),
1429 },
1430 ],
1431 Ok(vec![
1432 OutputFile {
1433 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1434 text: "{application, the_package, [
1435 {vsn, \"1.0.0\"},
1436 {applications, []},
1437 {description, \"The description\"},
1438 {modules, [one,
1439 two]},
1440 {registered, []}
1441]}.
1442"
1443 .into(),
1444 },
1445 OutputFile {
1446 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1447 text: "-module(one).
1448-compile(no_auto_import).
1449
1450-export_type([person/0]).
1451
1452-type person() :: {person, binary(), integer()}.
1453
1454
1455"
1456 .to_string(),
1457 },
1458 OutputFile {
1459 path: PathBuf::from("_build/default/lib/the_package/build/one_Person.hrl"),
1460 text: "-record(person, {name :: binary(), age :: integer()}).
1461"
1462 .to_string(),
1463 },
1464 OutputFile {
1465 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1466 text: "-module(two).\n".to_string(),
1467 },
1468 ]),
1469 );
1470
1471 // Can use imported, fully qualified types in Type Constructors
1472 assert_erlang_compile!(
1473 vec![
1474 Source {
1475 origin: Origin::Src,
1476 path: PathBuf::from("/src/one.gleam"),
1477 name: "one".to_string(),
1478 code: "pub type Person { Person(name: String, age: Int) }".to_string(),
1479 },
1480 Source {
1481 origin: Origin::Src,
1482 path: PathBuf::from("/src/two.gleam"),
1483 name: "two".to_string(),
1484 code: "import one.{Person} type Two = Person".to_string(),
1485 },
1486 ],
1487 Ok(vec![
1488 OutputFile {
1489 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1490 text: "{application, the_package, [
1491 {vsn, \"1.0.0\"},
1492 {applications, []},
1493 {description, \"The description\"},
1494 {modules, [one,
1495 two]},
1496 {registered, []}
1497]}.
1498"
1499 .into(),
1500 },
1501 OutputFile {
1502 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1503 text: "-module(one).
1504-compile(no_auto_import).
1505
1506-export_type([person/0]).\n\n-type person() :: {person, binary(), integer()}.
1507
1508
1509"
1510 .to_string(),
1511 },
1512 OutputFile {
1513 path: PathBuf::from("_build/default/lib/the_package/build/one_Person.hrl"),
1514 text: "-record(person, {name :: binary(), age :: integer()}).
1515"
1516 .to_string(),
1517 },
1518 OutputFile {
1519 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1520 text: "-module(two).\n".to_string(),
1521 },
1522 ]),
1523 );
1524
1525 // Imported type constructors have the correct arity
1526 assert_erlang_compile!(
1527 vec![
1528 Source {
1529 origin: Origin::Src,
1530 path: PathBuf::from("/src/one.gleam"),
1531 name: "one".to_string(),
1532 code: "pub type T(x) { C(a: Int, b: Int) }".to_string(),
1533 },
1534 Source {
1535 origin: Origin::Src,
1536 path: PathBuf::from("/src/two.gleam"),
1537 name: "two".to_string(),
1538 code: "import one.{C} pub fn main() { C }".to_string(),
1539 },
1540 ],
1541 Ok(vec![
1542 OutputFile {
1543 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1544 text: "{application, the_package, [
1545 {vsn, \"1.0.0\"},
1546 {applications, []},
1547 {description, \"The description\"},
1548 {modules, [one,
1549 two]},
1550 {registered, []}
1551]}.
1552"
1553 .into(),
1554 },
1555 OutputFile {
1556 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1557 text: "-module(one).
1558-compile(no_auto_import).
1559
1560-export_type([t/1]).\n\n-type t(H) :: {c, integer(), integer()} | {gleam_phantom, H}.
1561
1562
1563"
1564 .to_string(),
1565 },
1566 OutputFile {
1567 path: PathBuf::from("_build/default/lib/the_package/build/one_C.hrl"),
1568 text: "-record(c, {a :: integer(), b :: integer()}).
1569"
1570 .to_string(),
1571 },
1572 OutputFile {
1573 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1574 text: "-module(two).
1575-compile(no_auto_import).
1576
1577-export([main/0]).
1578
1579-spec main() -> fun((integer(), integer()) -> one:t(any())).
1580main() ->
1581 fun(A, B) -> {c, A, B} end.
1582"
1583 .to_string(),
1584 },
1585 ]),
1586 );
1587
1588 // Unqualified and aliased type constructor imports use the correct name
1589 assert_erlang_compile!(
1590 vec![
1591 Source {
1592 origin: Origin::Src,
1593 path: PathBuf::from("/src/one.gleam"),
1594 name: "one".to_string(),
1595 code: "pub fn id(x) { x } pub type T { X(x: Int) }".to_string(),
1596 },
1597 Source {
1598 origin: Origin::Src,
1599 path: PathBuf::from("/src/two.gleam"),
1600 name: "two".to_string(),
1601 code: "import one.{X as E, id as i} pub fn make() { i(E) }".to_string(),
1602 },
1603 ],
1604 Ok(vec![
1605 OutputFile {
1606 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1607 text: "{application, the_package, [
1608 {vsn, \"1.0.0\"},
1609 {applications, []},
1610 {description, \"The description\"},
1611 {modules, [one,
1612 two]},
1613 {registered, []}
1614]}.
1615"
1616 .into(),
1617 },
1618 OutputFile {
1619 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1620 text: "-module(one).
1621-compile(no_auto_import).
1622
1623-export([id/1]).
1624-export_type([t/0]).
1625
1626-type t() :: {x, integer()}.
1627
1628-spec id(H) -> H.
1629id(X) ->
1630 X.
1631"
1632 .to_string(),
1633 },
1634 OutputFile {
1635 path: PathBuf::from("_build/default/lib/the_package/build/one_X.hrl"),
1636 text: "-record(x, {x :: integer()}).
1637"
1638 .to_string(),
1639 },
1640 OutputFile {
1641 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1642 text: "-module(two).
1643-compile(no_auto_import).
1644
1645-export([make/0]).
1646
1647-spec make() -> fun((integer()) -> one:t()).
1648make() ->
1649 one:id(fun(A) -> {x, A} end).
1650"
1651 .to_string(),
1652 },
1653 ]),
1654 );
1655
1656 // Custom type constructors can be aliased when imported
1657 assert_erlang_compile!(
1658 vec![
1659 Source {
1660 origin: Origin::Src,
1661 path: PathBuf::from("/src/one.gleam"),
1662 name: "one".to_string(),
1663 code: "pub type Headers = List(String)".to_string(),
1664 },
1665 Source {
1666 origin: Origin::Src,
1667 path: PathBuf::from("/src/two.gleam"),
1668 name: "two".to_string(),
1669 code: r#"import one.{Headers as StringList} pub fn make_list() -> StringList { ["aliased", "type", "constructor"] }"#.to_string(),
1670 },
1671 ],
1672 Ok(vec![
1673 OutputFile {
1674 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1675 text: "{application, the_package, [
1676 {vsn, \"1.0.0\"},
1677 {applications, []},
1678 {description, \"The description\"},
1679 {modules, [one,
1680 two]},
1681 {registered, []}
1682]}.
1683".into(),
1684 },
1685 OutputFile {
1686 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1687 text: "-module(one).\n"
1688 .to_string(),
1689 },
1690 OutputFile {
1691 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1692 text: r#"-module(two).
1693-compile(no_auto_import).
1694
1695-export([make_list/0]).
1696
1697-spec make_list() -> list(binary()).
1698make_list() ->
1699 [<<"aliased"/utf8>>, <<"type"/utf8>>, <<"constructor"/utf8>>].
1700"#
1701 .to_string(),
1702 },
1703 ]),
1704 );
1705
1706 // Imported type constructors have the correct arity
1707 assert_erlang_compile!(
1708 vec![
1709 Source {
1710 origin: Origin::Src,
1711 path: PathBuf::from("/src/one.gleam"),
1712 name: "one".to_string(),
1713 code: "pub type T(x) { C(a: Int, b: Int) }".to_string(),
1714 },
1715 Source {
1716 origin: Origin::Src,
1717 path: PathBuf::from("/src/two.gleam"),
1718 name: "two".to_string(),
1719 code: "import one pub fn main() { one.C }".to_string(),
1720 },
1721 ],
1722 Ok(vec![
1723 OutputFile {
1724 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1725 text: "{application, the_package, [
1726 {vsn, \"1.0.0\"},
1727 {applications, []},
1728 {description, \"The description\"},
1729 {modules, [one,
1730 two]},
1731 {registered, []}
1732]}.
1733"
1734 .into(),
1735 },
1736 OutputFile {
1737 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
1738 text: "-module(one).
1739-compile(no_auto_import).
1740
1741-export_type([t/1]).
1742
1743-type t(H) :: {c, integer(), integer()} | {gleam_phantom, H}.
1744
1745
1746"
1747 .to_string(),
1748 },
1749 OutputFile {
1750 path: PathBuf::from("_build/default/lib/the_package/build/one_C.hrl"),
1751 text: "-record(c, {a :: integer(), b :: integer()}).
1752"
1753 .to_string(),
1754 },
1755 OutputFile {
1756 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
1757 text: "-module(two).
1758-compile(no_auto_import).
1759
1760-export([main/0]).
1761
1762-spec main() -> fun((integer(), integer()) -> one:t(any())).
1763main() ->
1764 fun(A, B) -> {c, A, B} end.
1765"
1766 .to_string(),
1767 },
1768 ]),
1769 );
1770
1771 // A custom type marked as opaque cannot have its constructors accessed
1772 // from other modules
1773 assert_erlang_compile!(
1774 vec![
1775 Source {
1776 origin: Origin::Src,
1777 path: PathBuf::from("/src/one.gleam"),
1778 name: "one".to_string(),
1779 code: "pub opaque type T(x) { C(a: Int, b: Int) }".to_string(),
1780 },
1781 Source {
1782 origin: Origin::Src,
1783 path: PathBuf::from("/src/two.gleam"),
1784 name: "two".to_string(),
1785 code: "import one fn main() { one.C }".to_string(),
1786 },
1787 ],
1788 Err(Error::Type {
1789 path: PathBuf::from("/src/two.gleam"),
1790 src: "import one fn main() { one.C }".to_string(),
1791 error: crate::type_::Error::UnknownModuleValue {
1792 location: crate::ast::SrcSpan { start: 26, end: 28 },
1793 name: "C".to_string(),
1794 module_name: vec!["one".to_string(),],
1795 value_constructors: vec![],
1796 }
1797 }),
1798 );
1799
1800 // A custom type marked as opaque cannot have its fields accessed
1801 // from a different module
1802 assert_erlang_compile!(
1803 vec![
1804 Source {
1805 origin: Origin::Src,
1806 path: PathBuf::from("/src/one.gleam"),
1807 name: "one".to_string(),
1808 code: "pub opaque type T { C(a: Int, b: Int) }".to_string(),
1809 },
1810 Source {
1811 origin: Origin::Src,
1812 path: PathBuf::from("/src/two.gleam"),
1813 name: "two".to_string(),
1814 code: "import one fn test(t: one.T) { t.a }".to_string(),
1815 },
1816 ],
1817 Err(Error::Type {
1818 path: PathBuf::from("/src/two.gleam"),
1819 src: "import one fn test(t: one.T) { t.a }".to_string(),
1820 error: crate::type_::Error::UnknownRecordField {
1821 location: crate::ast::SrcSpan { start: 31, end: 34 },
1822 typ: Arc::new(crate::type_::Type::App {
1823 public: true,
1824 module: vec!["one".to_string(),],
1825 name: "T".to_string(),
1826 args: vec![],
1827 }),
1828 label: "a".to_string(),
1829 fields: vec![],
1830 }
1831 }),
1832 );
1833
1834 // Import cycles between modules are not allowed
1835 assert_erlang_compile!(
1836 vec![
1837 Source {
1838 origin: Origin::Src,
1839 path: PathBuf::from("/src/one.gleam"),
1840 name: "one".to_string(),
1841 code: "import two".to_string(),
1842 },
1843 Source {
1844 origin: Origin::Src,
1845 path: PathBuf::from("/src/two.gleam"),
1846 name: "two".to_string(),
1847 code: "import three".to_string(),
1848 },
1849 Source {
1850 origin: Origin::Src,
1851 path: PathBuf::from("/src/three.gleam"),
1852 name: "three".to_string(),
1853 code: "import one".to_string(),
1854 },
1855 ],
1856 Err(Error::ImportCycle {
1857 modules: vec!["one".to_string(), "three".to_string(), "two".to_string()],
1858 }),
1859 );
1860
1861 // Bug: https://github.com/gleam-lang/gleam/issues/752
1862 assert_erlang_compile!(
1863 vec![
1864 Source {
1865 origin: Origin::Src,
1866 path: PathBuf::from("/src/one.gleam"),
1867 name: "one".to_string(),
1868 code: "pub type One(a) { One(a) }".to_string(),
1869 },
1870 Source {
1871 origin: Origin::Src,
1872 path: PathBuf::from("/src/two.gleam"),
1873 name: "two".to_string(),
1874 code: "import one.{One} pub type Two(b) { Two(thing: One(Int)) }".to_string(),
1875 },
1876 ],
1877 Ok(vec![
1878 OutputFile {
1879 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1880 text: "{application, the_package, [
1881 {vsn, \"1.0.0\"},
1882 {applications, []},
1883 {description, \"The description\"},
1884 {modules, [one,
1885 two]},
1886 {registered, []}
1887]}.
1888"
1889 .into(),
1890 },
1891 OutputFile {
1892 path: PathBuf::from("_build/default/lib/the_package/build/one.erl",),
1893 text: "-module(one).
1894-compile(no_auto_import).
1895
1896-export_type([one/1]).
1897
1898-type one(H) :: {one, H}.
1899
1900
1901"
1902 .to_string(),
1903 },
1904 OutputFile {
1905 path: PathBuf::from("_build/default/lib/the_package/build/two.erl",),
1906 text: "-module(two).
1907-compile(no_auto_import).
1908
1909-export_type([two/1]).
1910
1911-type two(I) :: {two, one:one(integer())} | {gleam_phantom, I}.
1912
1913
1914"
1915 .to_string(),
1916 },
1917 OutputFile {
1918 path: PathBuf::from("_build/default/lib/the_package/build/two_Two.hrl",),
1919 text: "-record(two, {thing :: one:one(integer())}).
1920"
1921 .to_string(),
1922 },
1923 ]),
1924 );
1925}
1926
1927#[test]
1928// Discriminate between imported functions, and fields, when shadowing a name:
1929// https://github.com/gleam-lang/gleam/issues/807
1930fn variable_module_name_collide() {
1931 assert_erlang_compile!(
1932 vec![
1933 Source {
1934 origin: Origin::Src,
1935 path: PathBuf::from("/src/power.gleam"),
1936 name: "power".to_string(),
1937 code: "pub type Power { Power(value: Int) }
1938pub fn to_int(p: Power) { p.value * 9000 }"
1939 .to_string(),
1940 },
1941 Source {
1942 origin: Origin::Src,
1943 path: PathBuf::from("/src/main.gleam"),
1944 name: "main".to_string(),
1945 code: "import power.{Power}
1946pub fn main(power: Power) { power.to_int(power) }"
1947 .to_string(),
1948 },
1949 ],
1950 Ok(vec![
1951 OutputFile {
1952 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
1953 text: "{application, the_package, [
1954 {vsn, \"1.0.0\"},
1955 {applications, []},
1956 {description, \"The description\"},
1957 {modules, [main,
1958 power]},
1959 {registered, []}
1960]}.
1961"
1962 .into(),
1963 },
1964 OutputFile {
1965 path: PathBuf::from("_build/default/lib/the_package/build/main.erl",),
1966 text: "-module(main).
1967-compile(no_auto_import).
1968
1969-export([main/1]).
1970
1971-spec main(power:power()) -> integer().
1972main(Power) ->
1973 power:to_int(Power).
1974"
1975 .to_string(),
1976 },
1977 OutputFile {
1978 path: PathBuf::from("_build/default/lib/the_package/build/power.erl",),
1979 text: "-module(power).
1980-compile(no_auto_import).
1981
1982-export([to_int/1]).
1983-export_type([power/0]).
1984
1985-type power() :: {power, integer()}.
1986
1987-spec to_int(power()) -> integer().
1988to_int(P) ->
1989 erlang:element(2, P) * 9000.
1990"
1991 .to_string(),
1992 },
1993 OutputFile {
1994 path: PathBuf::from("_build/default/lib/the_package/build/power_Power.hrl",),
1995 text: "-record(power, {value :: integer()}).
1996"
1997 .to_string(),
1998 },
1999 ]),
2000 );
2001}
2002
2003#[test]
2004fn imported_module_consts() {
2005 assert_erlang_compile!(
2006 vec![
2007 Source {
2008 origin: Origin::Src,
2009 path: PathBuf::from("/src/one.gleam"),
2010 name: "one".to_string(),
2011 code: "pub type Test { A }".to_string(),
2012 },
2013 Source {
2014 origin: Origin::Src,
2015 path: PathBuf::from("/src/two.gleam"),
2016 name: "two".to_string(),
2017 code: "import one
2018pub const test = one.A
2019pub fn x() { test }"
2020 .to_string(),
2021 },
2022 ],
2023 Ok(vec![
2024 OutputFile {
2025 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2026 text: "{application, the_package, [
2027 {vsn, \"1.0.0\"},
2028 {applications, []},
2029 {description, \"The description\"},
2030 {modules, [one,
2031 two]},
2032 {registered, []}
2033]}.
2034"
2035 .into(),
2036 },
2037 OutputFile {
2038 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
2039 text: "-module(one).
2040-compile(no_auto_import).
2041
2042-export_type([test/0]).
2043
2044-type test() :: a.
2045
2046
2047"
2048 .to_string(),
2049 },
2050 OutputFile {
2051 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
2052 text: "-module(two).
2053-compile(no_auto_import).
2054
2055-export([x/0]).
2056
2057-spec x() -> one:test().
2058x() ->
2059 a.
2060"
2061 .to_string(),
2062 }
2063 ]),
2064 );
2065
2066 assert_erlang_compile!(
2067 vec![
2068 Source {
2069 origin: Origin::Src,
2070 path: PathBuf::from("/src/one.gleam"),
2071 name: "one".to_string(),
2072 code: "pub type A { A } pub type B { B(A) }".to_string(),
2073 },
2074 Source {
2075 origin: Origin::Src,
2076 path: PathBuf::from("/src/two.gleam"),
2077 name: "two".to_string(),
2078 code: "import one
2079pub const test = one.B(one.A)
2080pub fn x() { test }"
2081 .to_string(),
2082 },
2083 ],
2084 Ok(vec![
2085 OutputFile {
2086 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2087 text: "{application, the_package, [
2088 {vsn, \"1.0.0\"},
2089 {applications, []},
2090 {description, \"The description\"},
2091 {modules, [one,
2092 two]},
2093 {registered, []}
2094]}.
2095"
2096 .into(),
2097 },
2098 OutputFile {
2099 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
2100 text: "-module(one).
2101-compile(no_auto_import).
2102
2103-export_type([a/0, b/0]).
2104
2105-type a() :: a.
2106
2107-type b() :: {b, a()}.
2108
2109
2110"
2111 .to_string(),
2112 },
2113 OutputFile {
2114 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
2115 text: "-module(two).
2116-compile(no_auto_import).
2117
2118-export([x/0]).
2119
2120-spec x() -> one:b().
2121x() ->
2122 {b, a}.
2123"
2124 .to_string(),
2125 }
2126 ]),
2127 );
2128
2129 assert_erlang_compile!(
2130 vec![
2131 Source {
2132 origin: Origin::Src,
2133 path: PathBuf::from("/src/one.gleam"),
2134 name: "one".to_string(),
2135 code: "".to_string(),
2136 },
2137 Source {
2138 origin: Origin::Src,
2139 path: PathBuf::from("/src/two.gleam"),
2140 name: "two".to_string(),
2141 code: "import one
2142pub const test = one.A
2143fn x() { test }"
2144 .to_string(),
2145 },
2146 ],
2147 Err(Error::Type {
2148 path: PathBuf::from("/src/two.gleam"),
2149 src: "import one
2150pub const test = one.A
2151fn x() { test }"
2152 .to_string(),
2153 error: type_::Error::UnknownModuleValue {
2154 location: SrcSpan { start: 28, end: 33 },
2155 module_name: vec!["one".to_string()],
2156 name: "A".to_string(),
2157 value_constructors: vec![]
2158 }
2159 })
2160 );
2161}
2162
2163#[test]
2164fn imported_type_constructor_used_as_function() {
2165 assert_erlang_compile!(
2166 vec![
2167 Source {
2168 origin: Origin::Src,
2169 path: PathBuf::from("/src/one.gleam"),
2170 name: "one".to_string(),
2171 code: "pub type A { A(String) }".to_string(),
2172 },
2173 Source {
2174 origin: Origin::Src,
2175 path: PathBuf::from("/src/two.gleam"),
2176 name: "two".to_string(),
2177 code: "import one
2178pub fn x() { one.A }"
2179 .to_string(),
2180 },
2181 ],
2182 Ok(vec![
2183 OutputFile {
2184 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2185 text: "{application, the_package, [
2186 {vsn, \"1.0.0\"},
2187 {applications, []},
2188 {description, \"The description\"},
2189 {modules, [one,
2190 two]},
2191 {registered, []}
2192]}.
2193"
2194 .into(),
2195 },
2196 OutputFile {
2197 path: PathBuf::from("_build/default/lib/the_package/build/one.erl"),
2198 text: "-module(one).
2199-compile(no_auto_import).
2200
2201-export_type([a/0]).
2202
2203-type a() :: {a, binary()}.
2204
2205
2206"
2207 .to_string(),
2208 },
2209 OutputFile {
2210 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
2211 text: "-module(two).
2212-compile(no_auto_import).
2213
2214-export([x/0]).
2215
2216-spec x() -> fun((binary()) -> one:a()).
2217x() ->
2218 fun(A) -> {a, A} end.
2219"
2220 .to_string(),
2221 }
2222 ]),
2223 );
2224}
2225
2226// https://github.com/gleam-lang/otp/pull/22
2227#[test]
2228fn import_shadowed_name_warnings() {
2229 assert_no_warnings!(vec![
2230 Source {
2231 origin: Origin::Src,
2232 path: PathBuf::from("/src/one.gleam"),
2233 name: "one".to_string(),
2234 code: "pub external type Port".to_string(),
2235 },
2236 Source {
2237 origin: Origin::Src,
2238 path: PathBuf::from("/src/two.gleam"),
2239 name: "two".to_string(),
2240 code: r#"import one.{Port}
2241type Shadowing { Port }
2242
2243pub external fn use_type(Port) -> Nil =
2244 "" ""
2245"#
2246 .to_string(),
2247 },
2248 ]);
2249
2250 assert_no_warnings!(vec![
2251 Source {
2252 origin: Origin::Src,
2253 path: PathBuf::from("/src/one.gleam"),
2254 name: "one".to_string(),
2255 code: "pub type Port { Port }".to_string(),
2256 },
2257 Source {
2258 origin: Origin::Src,
2259 path: PathBuf::from("/src/two.gleam"),
2260 name: "two".to_string(),
2261 code: r#"import one.{Port}
2262type Shadowing { Port }
2263
2264pub external fn use_type(Port) -> Nil =
2265 "" ""
2266"#
2267 .to_string(),
2268 },
2269 ]);
2270}
2271
2272#[test]
2273fn config_compilation_test() {
2274 macro_rules! assert_config_compile {
2275 ($config:expr, $sources:expr, $expected_output:expr $(,)?) => {
2276 let config = $config;
2277 let mut modules = HashMap::new();
2278 let (file_writer, file_receiver) = FilesChannel::new();
2279 let root = PathBuf::from("some/build/path/root");
2280 let out = PathBuf::from("_build/default/lib/the_package");
2281 let mut compiler =
2282 PackageCompiler::new(&config, &root, &out, Target::Erlang, "", file_writer);
2283 compiler.write_entrypoint = false;
2284 compiler.write_metadata = false;
2285 compiler.compile_erlang = false;
2286 compiler.sources = $sources;
2287 let compiled = compiler
2288 .compile(&mut vec![], &mut modules, &mut HashMap::with_capacity(4))
2289 .expect("Should compile OK");
2290 let mut outputs = FilesChannel::recv_utf8_files(&file_receiver).unwrap();
2291 outputs.sort_by(|a, b| a.path.partial_cmp(&b.path).unwrap());
2292 assert_eq!($expected_output, outputs);
2293 };
2294 };
2295
2296 fn make_config() -> PackageConfig {
2297 PackageConfig {
2298 dependencies: HashMap::new(),
2299 dev_dependencies: HashMap::new(),
2300 description: "".to_string(),
2301 version: Version::parse("1.0.0").unwrap(),
2302 name: "the_package".to_string(),
2303 repository: Repository::None,
2304 documentation: Default::default(),
2305 licences: Default::default(),
2306 erlang: Default::default(),
2307 links: vec![],
2308 target: Target::Erlang,
2309 }
2310 }
2311
2312 assert_config_compile!(
2313 {
2314 let mut config = make_config();
2315 config.erlang.application_start_module = Some("myapp/mymod".to_string());
2316 config
2317 },
2318 vec![],
2319 vec![OutputFile {
2320 text: r#"{application, the_package, [
2321 {mod, 'myapp@mymod'},
2322 {vsn, "1.0.0"},
2323 {applications, []},
2324 {description, ""},
2325 {modules, []},
2326 {registered, []}
2327]}.
2328"#
2329 .to_string(),
2330 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2331 }]
2332 );
2333
2334 assert_config_compile!(
2335 make_config(),
2336 vec![],
2337 vec![OutputFile {
2338 text: r#"{application, the_package, [
2339 {vsn, "1.0.0"},
2340 {applications, []},
2341 {description, ""},
2342 {modules, []},
2343 {registered, []}
2344]}.
2345"#
2346 .to_string(),
2347 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2348 }]
2349 );
2350
2351 // Version is included if given
2352 let mut config = make_config();
2353 config.version = Version::parse("1.3.5").unwrap();
2354 assert_config_compile!(
2355 config,
2356 vec![],
2357 vec![OutputFile {
2358 text: r#"{application, the_package, [
2359 {vsn, "1.3.5"},
2360 {applications, []},
2361 {description, ""},
2362 {modules, []},
2363 {registered, []}
2364]}.
2365"#
2366 .to_string(),
2367 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2368 }]
2369 );
2370
2371 // We can specify a description
2372 let mut config = make_config();
2373 config.description = "Very exciting".to_string();
2374 assert_config_compile!(
2375 config,
2376 vec![],
2377 vec![OutputFile {
2378 text: r#"{application, the_package, [
2379 {vsn, "1.0.0"},
2380 {applications, []},
2381 {description, "Very exciting"},
2382 {modules, []},
2383 {registered, []}
2384]}.
2385"#
2386 .to_string(),
2387 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2388 }]
2389 );
2390
2391 // Deps applications are listed
2392 let mut config = make_config();
2393 config.dependencies = [
2394 ("gleam_stdlib", "1.0.0"),
2395 ("gleam_otp", "1.0.0"),
2396 ("midas", "1.0.0"),
2397 ("simple_json", "1.0.0"),
2398 ]
2399 .into_iter()
2400 .map(|(a, b)| (a.to_string(), Range::new(b.to_string())))
2401 .collect();
2402 assert_config_compile!(
2403 config,
2404 vec![],
2405 vec![OutputFile {
2406 text: r#"{application, the_package, [
2407 {vsn, "1.0.0"},
2408 {applications, [gleam_otp,
2409 gleam_stdlib,
2410 midas,
2411 simple_json]},
2412 {description, ""},
2413 {modules, []},
2414 {registered, []}
2415]}.
2416"#
2417 .to_string(),
2418 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2419 }]
2420 );
2421
2422 // Dev deps applications are listed
2423 let mut config = make_config();
2424 config.dependencies = [("gleam_stdlib", "1.0.0"), ("gleam_otp", "1.0.0")]
2425 .into_iter()
2426 .map(|(a, b)| (a.to_string(), Range::new(b.to_string())))
2427 .collect();
2428 config.dev_dependencies = [("midas", "1.0.0"), ("simple_json", "1.0.0")]
2429 .into_iter()
2430 .map(|(a, b)| (a.to_string(), Range::new(b.to_string())))
2431 .collect();
2432 assert_config_compile!(
2433 config,
2434 vec![],
2435 vec![OutputFile {
2436 text: r#"{application, the_package, [
2437 {vsn, "1.0.0"},
2438 {applications, [gleam_otp,
2439 gleam_stdlib,
2440 midas,
2441 simple_json]},
2442 {description, ""},
2443 {modules, []},
2444 {registered, []}
2445]}.
2446"#
2447 .to_string(),
2448 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2449 }]
2450 );
2451
2452 // Extra applications are included
2453 let mut config = make_config();
2454 config.dependencies = [("gleam_stdlib", "1.0.0"), ("gleam_otp", "1.0.0")]
2455 .into_iter()
2456 .map(|(a, b)| (a.to_string(), Range::new(b.to_string())))
2457 .collect();
2458 config.dev_dependencies = [("midas", "1.0.0"), ("simple_json", "1.0.0")]
2459 .into_iter()
2460 .map(|(a, b)| (a.to_string(), Range::new(b.to_string())))
2461 .collect();
2462 config.erlang.extra_applications = vec!["inets".into(), "ssl".into()];
2463 assert_config_compile!(
2464 config,
2465 vec![],
2466 vec![OutputFile {
2467 text: r#"{application, the_package, [
2468 {vsn, "1.0.0"},
2469 {applications, [gleam_otp,
2470 gleam_stdlib,
2471 inets,
2472 midas,
2473 simple_json,
2474 ssl]},
2475 {description, ""},
2476 {modules, []},
2477 {registered, []}
2478]}.
2479"#
2480 .to_string(),
2481 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2482 }]
2483 );
2484}
2485
2486fn normalise_error(e: Error) -> Error {
2487 match e {
2488 Error::ImportCycle { mut modules } => {
2489 modules.sort();
2490 Error::ImportCycle { modules }
2491 }
2492 e => e,
2493 }
2494}
2495
2496// https://github.com/gleam-lang/gleam/issues/922#issuecomment-803272624
2497#[test]
2498fn qualified_constant_with_nested_module() {
2499 assert_erlang_compile!(
2500 vec![
2501 Source {
2502 origin: Origin::Src,
2503 path: PathBuf::from("/src/one/two.gleam"),
2504 name: "one/two".to_string(),
2505 code: "pub type A { A }".to_string(),
2506 },
2507 Source {
2508 origin: Origin::Src,
2509 path: PathBuf::from("/src/two.gleam"),
2510 name: "two".to_string(),
2511 code: r#"import one/two
2512const x = two.A"#
2513 .to_string(),
2514 },
2515 ],
2516 Ok(vec![
2517 OutputFile {
2518 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"),
2519 text: "{application, the_package, [
2520 {vsn, \"1.0.0\"},
2521 {applications, []},
2522 {description, \"The description\"},
2523 {modules, [one@two,
2524 two]},
2525 {registered, []}
2526]}.
2527"
2528 .into(),
2529 },
2530 OutputFile {
2531 path: PathBuf::from("_build/default/lib/the_package/build/one@two.erl"),
2532 text: "-module(one@two).
2533-compile(no_auto_import).
2534
2535-export_type([a/0]).
2536
2537-type a() :: a.
2538
2539
2540"
2541 .to_string(),
2542 },
2543 OutputFile {
2544 path: PathBuf::from("_build/default/lib/the_package/build/two.erl"),
2545 text: "-module(two).\n".to_string(),
2546 }
2547 ]),
2548 );
2549}
2550
2551#[test]
2552fn javascript_package() {
2553 assert_javascript_compile!(
2554 vec![
2555 Source {
2556 origin: Origin::Src,
2557 path: PathBuf::from("/src/one/two.gleam"),
2558 name: "one/two".to_string(),
2559 code: "pub type A { A }".to_string(),
2560 },
2561 Source {
2562 origin: Origin::Src,
2563 path: PathBuf::from("/src/two.gleam"),
2564 name: "two".to_string(),
2565 code: r#"import one/two
2566const x = two.A"#
2567 .to_string(),
2568 },
2569 ],
2570 Ok(vec![
2571 OutputFile {
2572 path: PathBuf::from("_build/default/lib/the_package/build/gleam.mjs"),
2573 text: javascript::PRELUDE.to_string(),
2574 },
2575 OutputFile {
2576 path: PathBuf::from("_build/default/lib/the_package/build/one/two.mjs"),
2577 text: "import { CustomType } from \"../gleam.mjs\";
2578
2579export class A extends CustomType {}\n"
2580 .to_string(),
2581 },
2582 OutputFile {
2583 path: PathBuf::from("_build/default/lib/the_package/build/two.mjs"),
2584 text: r#"import * as $two from "./one/two.mjs";
2585
2586const x = new $two.A();
2587"#
2588 .to_string(),
2589 }
2590 ]),
2591 );
2592}