diff --git a/README.md b/README.md index f6deb9b..694a1db 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,66 @@ I have no idea. It's fun and educational. (I'm on a roll with this redefining wo ## Usage +The complier runs on gleam erlang successfully. I think it might work with +Javascript as I don't think I'm using any erlang-specific libraries yet. It +can't compile itself to python yet, but I'm hoping to get there. + +To run it, pass it a properly structured macabre folder as the only argument: + ```sh -gleam run -- some_very_simple_file.gleam # compile to python +gleam run -- some_package_folder +``` + +The package folder should have a structure similar to a normal Gleam project: + +``` +folder +├── gleam.toml +├── build +│ └── +└─ src + ├── .gleam + ├── some_folder + │ ├── something.gleam + │ └── bindings.py + ├── some_file.gleam + └── some_bindings.py +``` + +The `gleam.toml` only supports two keys, name and dependencies: + +```toml +name = "example" + +[dependencies] +macabre_stdlib = "git@github.com:dusty-phillips/macabre_stdlib.git" +``` + +Note that dependencies are currently _not_ hex packages like a normal gleam +project. Rather, they are git repositories. This is mostly because I didn't +feel comfortable cluttering hex with silly dependencies for my silly project. + +The compiler expects git to be installed, and will clone any git repos that are +listed. + +> [!WARNING} It currently downloads everything from scratch every time you +> invoke it, so don't try this on a metered connection! + +Macabre copies the `src/` folder of each package into the build directory and +then builds all dependencies from scratch (every single time). Your source +files are also copied into this folder. + +Your main module will always be `.gleam` where `` is whatever +you put in the `name` in `gleam.toml`. + +Your files are compiled to `build/dev/python`. If your `.gleam` has +a `main` function in it, then the compiler will generate a +`build/dev/python/__main__.py` to call that function. + +Use this command to invoke it: + +```shell +python build/dev/python ``` ## Development @@ -39,14 +97,12 @@ fd .gleam | entr gleam test ## Contributing -Are you insane? - -Sweet, me too. - PRs are welcome. The main entry point is `macabre.gleam`, which handles all file loading and -other side effects. The compiler is pure gleam. Most of the work happens in +other side effects. + +The compiler is pure gleam. Most of the work happens in `transformer.gleam` and `generator.gleam`. The former converts the Gleam AST to a Python AST, the latter generates python code. There are tons of helper functions in various other files. @@ -61,6 +117,7 @@ Some tasks below are marked easy if you want to get started. This is a list of all outstanding `todo` expressions (Gleam todo expressions are ) in the codebase, as of the last time that I updated this list. +- (EASY) Turn this list into github issues - imports with attributes are not handled yet - type imports are not implemented yet - Unlabelled fields in custom types are not generated yet @@ -100,12 +157,7 @@ are ) in the codebase, as of the last time that I updated this list. - glance doesn't have (much of) a typechecker - not currently generating python type hints (e.g. function arguments and return types), but gleam gives us that info so may as well use it -- no concept of a "project", gleam.toml, downloading dependencies -- only compiles one module at a time, doesn't follow imports -- copies the prelude module blindly into the directory that contains that one module instead of a top level -- No standard library - No Result custom type yet (I thought this needed to be in the prelude, but I don't see any result-specific syntax anywhere) -- generate `__main__.py` if a module has a main function - calling functions or constructors with out-of-order positional args doesn't work in python - e.g. `Foo(mystr: String, point: #(Int, Int))` can be called with `Foo(#(1, diff --git a/gleam.toml b/gleam.toml index 203162a..d179003 100644 --- a/gleam.toml +++ b/gleam.toml @@ -19,6 +19,8 @@ argv = ">= 1.0.2 and < 2.0.0" simplifile = ">= 2.0.1 and < 3.0.0" filepath = ">= 1.0.0 and < 2.0.0" glexer = ">= 1.0.1 and < 2.0.0" +tom = ">= 1.0.1 and < 2.0.0" +shellout = ">= 1.6.0 and < 2.0.0" [dev-dependencies] gleescript = ">= 1.4.0 and < 2.0.0" diff --git a/manifest.toml b/manifest.toml index 8d94dbd..3300d7a 100644 --- a/manifest.toml +++ b/manifest.toml @@ -15,6 +15,7 @@ packages = [ { name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" }, { name = "glexer", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "BD477AD657C2B637FEF75F2405FAEFFA533F277A74EF1A5E17B55B1178C228FB" }, { name = "pprint", version = "1.0.3", build_tools = ["gleam"], requirements = ["glam", "gleam_stdlib"], otp_app = "pprint", source = "hex", outer_checksum = "76BBB92E23D12D954BD452686543F29EDE8EBEBB7FC0ACCBCA66EEF276EC3A06" }, + { name = "shellout", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "E2FCD18957F0E9F67E1F497FC9FF57393392F8A9BAEAEA4779541DE7A68DD7E0" }, { name = "simplifile", version = "2.0.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "5FFEBD0CAB39BDD343C3E1CCA6438B2848847DC170BA2386DF9D7064F34DF000" }, { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, { name = "temporary", version = "1.0.0", build_tools = ["gleam"], requirements = ["envoy", "exception", "filepath", "gleam_crypto", "gleam_stdlib", "simplifile"], otp_app = "temporary", source = "hex", outer_checksum = "51C0FEF4D72CE7CA507BD188B21C1F00695B3D5B09D7DFE38240BFD3A8E1E9B3" }, @@ -30,5 +31,7 @@ gleescript = { version = ">= 1.4.0 and < 2.0.0" } gleeunit = { version = ">= 1.2.0 and < 2.0.0" } glexer = { version = ">= 1.0.1 and < 2.0.0" } pprint = { version = ">= 1.0.3 and < 2.0.0" } +shellout = { version = ">= 1.6.0 and < 2.0.0" } simplifile = { version = ">= 2.0.1 and < 3.0.0" } temporary = { version = ">= 1.0.0 and < 2.0.0" } +tom = { version = ">= 1.0.1 and < 2.0.0" } diff --git a/src/compiler.gleam b/src/compiler.gleam index a229dca..39351dd 100644 --- a/src/compiler.gleam +++ b/src/compiler.gleam @@ -4,9 +4,8 @@ import compiler/transformer import glance import gleam/dict import gleam/list -import gleam/option import gleam/result -import gleam/string +import pprint pub fn compile_module(glance_module: glance.Module) -> String { glance_module @@ -15,12 +14,12 @@ pub fn compile_module(glance_module: glance.Module) -> String { } pub fn compile_package(package: package.GleamPackage) -> package.CompiledPackage { + pprint.debug(package.modules) package.CompiledPackage( - base_directory: package.base_directory, - main_module: dict.get(package.modules, package.main_module) + project: package.project, + has_main: dict.get(package.modules, package.project.name <> ".gleam") |> result.try(fn(mod) { mod.functions |> has_main_function }) - |> result.replace(package.main_module |> string.drop_right(6)) - |> option.from_result, + |> result.is_ok, modules: package.modules |> dict.map_values(fn(_key, value) { compile_module(value) }), external_import_files: package.external_import_files, diff --git a/src/compiler/package.gleam b/src/compiler/package.gleam index bdef1cf..7235fa8 100644 --- a/src/compiler/package.gleam +++ b/src/compiler/package.gleam @@ -5,21 +5,20 @@ //// filesystem. //// It does not write to the filesystem. +import compiler/project import errors import filepath +import filesystem import glance import gleam/dict import gleam/list -import gleam/option import gleam/result import gleam/set import gleam/string -import simplifile pub type GleamPackage { GleamPackage( - base_directory: String, - main_module: String, + project: project.Project, modules: dict.Dict(String, glance.Module), external_import_files: set.Set(String), ) @@ -27,8 +26,8 @@ pub type GleamPackage { pub type CompiledPackage { CompiledPackage( - base_directory: String, - main_module: option.Option(String), + project: project.Project, + has_main: Bool, modules: dict.Dict(String, String), external_import_files: set.Set(String), ) @@ -36,40 +35,15 @@ pub type CompiledPackage { /// Load the entry_point file and recursively load and parse any modules it ///returns. -pub fn load_package( - source_directory: String, +pub fn load( + gleam_project: project.Project, ) -> Result(GleamPackage, errors.Error) { - source_directory - |> simplifile.is_directory - |> result.map_error(errors.FileOrDirectoryNotFound(source_directory, _)) - |> result.try(fn(_) { find_entrypoint(source_directory) }) - |> result.try(fn(entrypoint) { - load_module( - GleamPackage( - source_directory, - entrypoint, - dict.new(), - external_import_files: set.new(), - ), - entrypoint, - ) - }) -} - -pub fn find_entrypoint(source_directory: String) -> Result(String, errors.Error) { - let base_name = filepath.base_name(source_directory) - let entrypoint = base_name <> ".gleam" - simplifile.is_file(filepath.join(source_directory, entrypoint)) - |> result.replace(entrypoint) - |> result.map_error(errors.FileOrDirectoryNotFound(entrypoint, _)) -} - -pub fn source_directory(base_directory: String) -> String { - filepath.join(base_directory, "src") -} - -pub fn build_directory(base_directory: String) -> String { - filepath.join(base_directory, "build") + use _ <- result.try(filesystem.is_directory(project.src_dir(gleam_project))) + use package <- result.try(load_module( + GleamPackage(gleam_project, dict.new(), external_import_files: set.new()), + project.entry_point(gleam_project), + )) + Ok(package) } /// Parse the module and add it to the package's modules, if it can be parsed. @@ -82,11 +56,9 @@ fn load_module( Ok(_) -> Ok(package) Error(_) -> { let module_result = - package.base_directory - |> source_directory + project.build_src_dir(package.project) |> filepath.join(module_path) - |> simplifile.read - |> result.map_error(errors.FileReadError(module_path, _)) + |> filesystem.read |> result.try(parse(_, module_path)) case module_result { diff --git a/src/compiler/project.gleam b/src/compiler/project.gleam new file mode 100644 index 0000000..8acbeb4 --- /dev/null +++ b/src/compiler/project.gleam @@ -0,0 +1,145 @@ +// A project rooted at a gleam.toml +// maintains the build directory. +// Copies sources from src/ to build/src +// Downloads dependencies from github to build/packages +// copies sources from build/packages/src/* to build/src +// During compiling, all sources are treated like one "package" +// compiled to build/dev/python + +import errors +import filepath +import filesystem +import git +import gleam/dict +import gleam/list +import gleam/result +import simplifile +import tom + +pub type Project { + Project( + name: String, + packages: dict.Dict(String, String), + base_directory: String, + ) +} + +pub fn load(base_directory: String) -> Result(Project, errors.Error) { + let toml_path = filepath.join(base_directory, "gleam.toml") + use toml_contents <- result.try( + simplifile.read(toml_path) + |> result.map_error(errors.FileReadError(toml_path, _)), + ) + use parsed_toml <- result.try( + tom.parse(toml_contents) + |> result.map_error(errors.TomlParseError(toml_path, _)), + ) + use name <- result.try( + tom.get_string(parsed_toml, ["name"]) + |> result.map_error(errors.TomlFieldError(toml_path, _)), + ) + use packages <- result.try( + load_dependency_list(parsed_toml) + |> result.map_error(errors.TomlFieldError(toml_path, _)), + ) + + Ok(Project(name, packages, base_directory)) +} + +/// The entry_point for a project, relative to the build src directory. +pub fn entry_point(project: Project) -> String { + project.name <> ".gleam" +} + +pub fn src_dir(project: Project) -> String { + project.base_directory |> filepath.join("src") +} + +pub fn build_dir(project: Project) -> String { + project.base_directory + |> filepath.join("build") +} + +pub fn build_src_dir(project: Project) -> String { + project + |> build_dir + |> filepath.join("src") +} + +pub fn build_dev_dir(project: Project) -> String { + project |> build_dir |> filepath.join("dev") +} + +pub fn build_dev_python_dir(project: Project) -> String { + project + |> build_dev_dir + |> filepath.join("python") +} + +pub fn packages_dir(project: Project) -> String { + project + |> build_dir + |> filepath.join("packages") +} + +pub fn package_dir(project: Project, package_name: String) -> String { + project + |> packages_dir + |> filepath.join(package_name) +} + +pub fn package_src_dir(project: Project, package_name: String) -> String { + package_dir(project, package_name) + |> filepath.join("src") +} + +pub fn clone_packages(project: Project) -> Result(Nil, errors.Error) { + let package_directory = packages_dir(project) + use _ <- result.try( + simplifile.create_directory_all(package_directory) + |> result.map_error(errors.MkdirError(package_directory, _)), + ) + project.packages + |> dict.to_list + |> list.map(fn(tuple) { + let #(name, repo) = tuple + git.clone(name, repo, package_directory) + }) + |> result.all + |> result.replace(Nil) +} + +pub fn copy_package_srcs(project: Project) -> Result(Nil, errors.Error) { + let project_src_dir = build_src_dir(project) + use _ <- result.try(filesystem.create_directory(project_src_dir)) + dict.keys(project.packages) + |> list.map(package_src_dir(project, _)) + |> list.map(filesystem.copy_dir(_, project_src_dir)) + |> result.all + |> result.replace(Nil) +} + +pub fn copy_project_srcs(project: Project) -> Result(Nil, errors.Error) { + filesystem.copy_dir(src_dir(project), build_src_dir(project)) +} + +pub fn clean(project: Project) -> Result(Nil, errors.Error) { + project + |> build_dir + |> filesystem.delete +} + +fn load_dependency_list( + toml: dict.Dict(String, tom.Toml), +) -> Result(dict.Dict(String, String), tom.GetError) { + case tom.get_table(toml, ["dependencies"]) { + Ok(dependencies) -> { + use state, key, value <- dict.fold(dependencies, Ok(dict.new())) + use state_dict <- result.try(state) + use string_value <- result.try(tom.get_string(dependencies, [key])) + Ok(dict.insert(state_dict, key, string_value)) + } + Error(tom.NotFound(_)) -> Ok(dict.new()) + Error(tom.WrongType(..) as error) -> Error(error) + } +} diff --git a/src/errors.gleam b/src/errors.gleam index e09cc9c..faea2d8 100644 --- a/src/errors.gleam +++ b/src/errors.gleam @@ -1,21 +1,40 @@ import glance +import gleam/string import internal/errors as internal import simplifile +import tom pub type Error { - FileOrDirectoryNotFound(path: String, error: simplifile.FileError) + CopyFileError(src: String, dst: String, error: simplifile.FileError) + DeleteError(path: String, error: simplifile.FileError) FileReadError(path: String, error: simplifile.FileError) + FileOrDirectoryNotFound(path: String, error: simplifile.FileError) FileWriteError(path: String, error: simplifile.FileError) - DeleteError(path: String, error: simplifile.FileError) - MkdirError(path: String, error: simplifile.FileError) - CopyFileError(src: String, dst: String, error: simplifile.FileError) GlanceParseError(error: glance.Error, module: String, contents: String) + GitCloneError(name: String, error: #(Int, String)) + MkdirError(path: String, error: simplifile.FileError) + TomlFieldError(path: String, error: tom.GetError) + TomlParseError(path: String, error: tom.ParseError) } pub fn format_error(error: Error) -> String { case error { FileOrDirectoryNotFound(filename, _) -> "File or directory not found " <> filename + GitCloneError(name, _) -> "Unable to clone " <> name + TomlParseError(filename, _) -> "Invalid toml file " <> filename + TomlFieldError(filename, tom.NotFound(key)) -> + "Missing toml field in " <> filename <> ": " <> string.join(key, ",") + TomlFieldError(filename, tom.WrongType(key, expected, got)) -> + "Incorrect toml field in " + <> filename + <> ": " + <> string.join(key, ",") + <> "\n(expected: " + <> expected + <> ", got: " + <> got + <> ")" FileReadError(filename, simplifile.Enoent) -> "File not found " <> filename FileReadError(filename, _) -> "Unable to read " <> filename FileWriteError(filename, _) -> "Unable to write " <> filename diff --git a/src/output.gleam b/src/filesystem.gleam similarity index 72% rename from src/output.gleam rename to src/filesystem.gleam index b00522e..1c3e158 100644 --- a/src/output.gleam +++ b/src/filesystem.gleam @@ -1,9 +1,11 @@ +//// Mostly a wrapper of simplifile that translates to errors to errors.Error + import errors import filepath import gleam/io import gleam/list -import gleam/option import gleam/result +import pprint import python_prelude import simplifile @@ -12,6 +14,11 @@ pub fn write(contents: String, filename: String) -> Result(Nil, errors.Error) { |> result.map_error(errors.FileWriteError(filename, _)) } +pub fn read(filename: String) -> Result(String, errors.Error) { + simplifile.read(filename) + |> result.map_error(errors.FileReadError(filename, _)) +} + pub fn replace_extension(filename: String) -> String { filename |> filepath.strip_extension <> ".py" } @@ -41,16 +48,16 @@ pub fn write_prelude_file(build_directory: String) -> Result(Nil, errors.Error) } pub fn write_py_main( - build_directory: String, - main_module: option.Option(String), + has_main: Bool, + build_dir: String, + module: String, ) -> Result(Nil, errors.Error) { - case main_module { - option.Some(module) -> { - build_directory - |> filepath.join("__main__.py") + pprint.debug(has_main) + case has_main { + True -> + filepath.join(build_dir, "__main__.py") |> write(python_prelude.dunder_main(module), _) - } - option.None -> Ok(Nil) + False -> Ok(Nil) } } @@ -64,11 +71,21 @@ pub fn delete(path: String) -> Result(Nil, errors.Error) { simplifile.delete_all([path]) |> result.map_error(errors.DeleteError(path, _)) } +pub fn is_directory(path) -> Result(Bool, errors.Error) { + simplifile.is_directory(path) + |> result.map_error(errors.FileOrDirectoryNotFound(path, _)) +} + pub fn create_directory(path) -> Result(Nil, errors.Error) { - simplifile.create_directory(path) + simplifile.create_directory_all(path) |> result.map_error(errors.MkdirError(path, _)) } +pub fn copy_dir(src: String, dest: String) -> Result(Nil, errors.Error) { + simplifile.copy_directory(src, dest) + |> result.map_error(errors.CopyFileError(src, dest, _)) +} + pub fn copy_externals( build_directory: String, source_directory: String, diff --git a/src/git.gleam b/src/git.gleam new file mode 100644 index 0000000..c25dc80 --- /dev/null +++ b/src/git.gleam @@ -0,0 +1,13 @@ +import errors +import gleam/result +import shellout + +pub fn clone( + name: String, + repo: String, + from_dir: String, +) -> Result(Nil, errors.Error) { + shellout.command("git", ["clone", repo, name], from_dir, []) + |> result.map_error(errors.GitCloneError(name, _)) + |> result.replace(Nil) +} diff --git a/src/macabre.gleam b/src/macabre.gleam index f2387d4..1b88175 100644 --- a/src/macabre.gleam +++ b/src/macabre.gleam @@ -1,25 +1,19 @@ import argv import compiler import compiler/package +import compiler/project import errors import filepath +import filesystem import gleam/dict import gleam/io -import gleam/result +import gleam/result.{try} import gleam/set -import output pub fn main() { case argv.load().arguments { [] -> usage("Not enough arguments") - [directory] -> - directory - |> package.load_package - |> result.map(compiler.compile_package) - |> result.try(write_package) - |> result.map_error(output.write_error) - |> result.unwrap_both - // both nil + [directory] -> build(directory) [_, _, ..] -> usage("Too many arguments") } } @@ -28,31 +22,51 @@ pub fn usage(message: String) -> Nil { io.println("Usage: macabre \n\n" <> message) } +pub fn build(directory: String) -> Nil { + { + use gleam_project <- try(project.load(directory)) + use _ <- try(project.clean(gleam_project)) + use _ <- try(project.clone_packages(gleam_project)) + use _ <- try(project.copy_package_srcs(gleam_project)) + use _ <- try(project.copy_project_srcs(gleam_project)) + use gleam_package <- try(package.load(gleam_project)) + let compiled_package = compiler.compile_package(gleam_package) + use _ <- result.try(write_package(compiled_package)) + Ok(Nil) + } + |> result.map_error(filesystem.write_error) + |> result.unwrap_both +} + pub fn write_package( package: package.CompiledPackage, ) -> Result(Nil, errors.Error) { - let build_directory = package.build_directory(package.base_directory) - let source_directory = package.source_directory(package.base_directory) - output.delete(build_directory) - |> result.try(fn(_) { output.create_directory(build_directory) }) - |> result.try(fn(_) { output.write_prelude_file(build_directory) }) - |> result.try(fn(_) { - output.write_py_main(build_directory, package.main_module) + let build_directory = project.build_dev_python_dir(package.project) + let source_directory = project.build_src_dir(package.project) + filesystem.delete(build_directory) + |> try(fn(_) { filesystem.create_directory(build_directory) }) + |> try(fn(_) { filesystem.write_prelude_file(build_directory) }) + |> try(fn(_) { + filesystem.write_py_main( + package.has_main, + build_directory, + package.project.name, + ) }) - |> result.try(fn(_) { - output.copy_externals( + |> try(fn(_) { + filesystem.copy_externals( build_directory, source_directory, package.external_import_files |> set.to_list, ) }) - |> result.try(fn(_) { + |> try(fn(_) { dict.fold(package.modules, Ok(Nil), fn(state, name, module) { - result.try(state, fn(_) { + try(state, fn(_) { build_directory |> filepath.join(name) - |> output.replace_extension() - |> output.write(module, _) + |> filesystem.replace_extension() + |> filesystem.write(module, _) }) }) }) diff --git a/test/compiler/directory_structure_tests.gleam b/test/compiler/directory_structure_tests.gleam index de0ca6f..51e9748 100644 --- a/test/compiler/directory_structure_tests.gleam +++ b/test/compiler/directory_structure_tests.gleam @@ -1,5 +1,6 @@ import compiler import compiler/package +import compiler/project import filepath import gleam/dict import gleam/list @@ -8,6 +9,7 @@ import gleam/set import gleam/string import gleeunit/should import macabre +import pprint import simplifile import temporary @@ -26,7 +28,7 @@ pub type ProjectFiles { base_dir: String, src_dir: String, build_dir: String, - main_path: String, + package_src_dir: String, ) } @@ -34,19 +36,20 @@ fn init_folders( use_function: fn(ProjectFiles) -> a, ) -> Result(a, simplifile.FileError) { use dir <- temporary.create(temporary.directory()) - let project_name = filepath.base_name(dir) let src = filepath.join(dir, "src") - let build = filepath.join(dir, "build") - let main_path = filepath.join(src, project_name <> ".gleam") + let package_src_dir = filepath.join(dir, "build/src") + let build = filepath.join(dir, "build/dev/python") simplifile.create_directory_all(src) |> should.be_ok + simplifile.create_directory_all(build) + |> should.be_ok let project_files = ProjectFiles( base_dir: dir, src_dir: src, build_dir: build, - main_path: main_path, + package_src_dir: package_src_dir, ) use_function(project_files) } @@ -58,7 +61,7 @@ pub fn package_compile_test_with_nested_folders_test() { // src/foo/bindings.py use project_files <- init_folders() simplifile.write( - to: project_files.main_path, + to: filepath.join(project_files.src_dir, "nested_sample.gleam"), contents: "import foo/bar @external(python, \"baz\", \"baz\") @@ -94,17 +97,35 @@ pub fn package_compile_test_with_nested_folders_test() { ) |> should.be_ok + simplifile.write( + to: filepath.join(project_files.base_dir, "gleam.toml"), + contents: "name = \"nested_sample\"", + ) + |> should.be_ok + + let gleam_project = + project.load(project_files.base_dir) + |> should.be_ok + + project.copy_project_srcs(gleam_project) + |> should.be_ok + + simplifile.read_directory(project_files.package_src_dir) + |> should.be_ok + |> list.sort(string.compare) + |> should.equal(["baz.py", "foo", "nested_sample.gleam"]) + simplifile.read_directory(filepath.join(project_files.package_src_dir, "foo")) + |> should.be_ok + |> list.sort(string.compare) + |> should.equal(["bar.gleam", "bindings.py"]) + let gleam_package = - package.load_package(project_files.base_dir) + package.load(gleam_project) |> should.be_ok // load - should.equal(gleam_package.base_directory, project_files.base_dir) - should.equal( - gleam_package.main_module, - filepath.base_name(project_files.main_path), - ) + should.equal(gleam_project.base_directory, project_files.base_dir) gleam_package.modules |> dict.size |> should.equal(2) @@ -112,13 +133,6 @@ pub fn package_compile_test_with_nested_folders_test() { // --- compile let compiled_package = compiler.compile_package(gleam_package) - should.equal(compiled_package.base_directory, project_files.base_dir) - should.equal( - compiled_package.main_module, - option.Some( - filepath.base_name(project_files.main_path) |> string.drop_right(6), - ), - ) compiled_package.modules |> dict.size |> should.equal(2) @@ -131,11 +145,7 @@ pub fn package_compile_test_with_nested_folders_test() { |> should.be_ok |> list.sort(string.compare) |> should.equal([ - filepath.base_name(project_files.main_path) |> string.drop_right(6) <> ".py", - "__main__.py", - "baz.py", - "foo", - "gleam_builtins.py", + "__main__.py", "baz.py", "foo", "gleam_builtins.py", "nested_sample.py", ]) project_files.build_dir