Skip to content

Commit

Permalink
v1.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lpil committed Dec 22, 2024
1 parent 19dfe22 commit 89285aa
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 130 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v1.3.0 - 2024-12-22

- Updated for `gleam_stdlib` v0.51.0.

## v1.2.0 - 2024-12-08

- Updated dependency constraints.
Expand Down
4 changes: 2 additions & 2 deletions gleam.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
name = "gleam_package_interface"
version = "1.2.0"
version = "1.3.0"

description = "Work with Gleam's package interfaces"
licences = ["Apache-2.0"]
repository = { type = "github", user = "gleam-lang", repo = "package-interface-decoder" }
links = [{ title = "Website", href = "https://gleam.run" }]

[dependencies]
gleam_stdlib = ">= 0.38.0 and < 2.0.0"
gleam_stdlib = ">= 0.50.0 and < 2.0.0"
gleam_json = ">= 1.0.0 and < 3.0.0"

[dev-dependencies]
Expand Down
13 changes: 7 additions & 6 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@

packages = [
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
{ name = "birdie", version = "1.2.4", build_tools = ["gleam"], requirements = ["argv", "edit_distance", "filepath", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "justin", "rank", "simplifile", "trie_again"], otp_app = "birdie", source = "hex", outer_checksum = "769AE13AB5B5B84E724E9966037DCCB5BD63B2F43C52EF80B4BF3351F64E469E" },
{ name = "birdie", version = "1.2.5", build_tools = ["gleam"], requirements = ["argv", "edit_distance", "filepath", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "justin", "rank", "simplifile", "trie_again"], otp_app = "birdie", source = "hex", outer_checksum = "2531AD6AC71C89DFB7ECC8839C3DAB858963ECA425E9308302D3B93B8AE0FEAD" },
{ name = "edit_distance", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "edit_distance", source = "hex", outer_checksum = "A1E485C69A70210223E46E63985FA1008B8B2DDA9848B7897469171B29020C05" },
{ name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" },
{ name = "glam", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "66EC3BCD632E51EED029678F8DF419659C1E57B1A93D874C5131FE220DFAD2B2" },
{ name = "glance", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "E155BA1A787FD11827048355021C0390D2FE9A518485526F631A9D472858CC6D" },
{ name = "gleam_community_ansi", version = "1.4.1", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "4CD513FC62523053E62ED7BAC2F36136EC17D6A8942728250A9A00A15E340E4B" },
{ name = "glance", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "784CE3B5658CF589B2E811031992FDADDFA9C7FD2A51F1140EE019F121D6D0EB" },
{ name = "gleam_community_ansi", version = "1.4.2", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "479DEDC748D08B310C9FEB9C4CBEC46B95C874F7F4F2844304D6D20CA78A8BB5" },
{ name = "gleam_community_colour", version = "1.4.1", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "386CB9B01B33371538672EEA8A6375A0A0ADEF41F17C86DDCB81C92AD00DA610" },
{ name = "gleam_erlang", version = "0.33.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "A1D26B80F01901B59AABEE3475DD4C18D27D58FA5C897D922FCB9B099749C064" },
{ name = "gleam_json", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "0A57FB5666E695FD2BEE74C0428A98B0FC11A395D2C7B4CDF5E22C5DD32C74C6" },
{ name = "gleam_stdlib", version = "0.45.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "206FCE1A76974AECFC55AEBCD0217D59EDE4E408C016E2CFCCC8FF51278F186E" },
{ name = "gleam_json", version = "2.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "093214EB186A88D301795A94F0A8128C2E24CF1423997ED31A6C6CC67FC3E1A1" },
{ name = "gleam_regexp", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "A3655FDD288571E90EE9C4009B719FEF59FA16AFCDF3952A76A125AF23CF1592" },
{ name = "gleam_stdlib", version = "0.51.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "14AFA8D3DDD7045203D422715DBB822D1725992A31DF35A08D97389014B74B68" },
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
{ name = "glexer", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "25E87F25706749E40C3CDC72D2E52AEA12260B23D14FD9E09A1B524EF393485E" },
{ name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" },
Expand All @@ -25,6 +26,6 @@ packages = [
birdie = { version = ">= 1.0.0 and < 2.0.0" }
glam = { version = ">= 2.0.0 and < 3.0.0" }
gleam_json = { version = ">= 1.0.0 and < 3.0.0" }
gleam_stdlib = { version = ">= 0.38.0 and < 2.0.0" }
gleam_stdlib = { version = ">= 0.50.0 and < 2.0.0" }
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
simplifile = { version = ">= 2.0.0 and < 3.0.0" }
271 changes: 150 additions & 121 deletions src/gleam/package_interface.gleam
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import gleam/dict.{type Dict}
import gleam/dynamic.{type DecodeErrors, type Decoder, type Dynamic}
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import gleam/result

// --- TYPES -------------------------------------------------------------------

Expand Down Expand Up @@ -344,149 +343,179 @@ pub type Type {

// --- DECODERS ----------------------------------------------------------------

pub fn decoder(dynamic: Dynamic) -> Result(Package, DecodeErrors) {
dynamic.decode4(
Package,
dynamic.field("name", dynamic.string),
dynamic.field("version", dynamic.string),
dynamic.field("gleam-version-constraint", dynamic.optional(dynamic.string)),
dynamic.field("modules", string_dict(module_decoder)),
)(dynamic)
pub fn decoder() -> Decoder(Package) {
use name <- decode.field("name", decode.string)
use version <- decode.field("version", decode.string)
use gleam_version_constraint <- decode.field(
"gleam-version-constraint",
decode.optional(decode.string),
)
use modules <- decode.field(
"modules",
decode.dict(decode.string, module_decoder()),
)
Package(name:, version:, gleam_version_constraint:, modules:)
|> decode.success
}

pub fn module_decoder(dynamic: Dynamic) -> Result(Module, DecodeErrors) {
dynamic.decode5(
Module,
dynamic.field("documentation", dynamic.list(dynamic.string)),
dynamic.field("type-aliases", string_dict(type_alias_decoder)),
dynamic.field("types", string_dict(type_definition_decoder)),
dynamic.field("constants", string_dict(constant_decoder)),
dynamic.field("functions", string_dict(function_decoder)),
)(dynamic)
pub fn module_decoder() -> Decoder(Module) {
use documentation <- decode.field("documentation", decode.list(decode.string))
use type_aliases <- decode.field(
"type-aliases",
decode.dict(decode.string, type_alias_decoder()),
)
use types <- decode.field(
"types",
decode.dict(decode.string, type_definition_decoder()),
)
use constants <- decode.field(
"constants",
decode.dict(decode.string, constant_decoder()),
)
use functions <- decode.field(
"functions",
decode.dict(decode.string, function_decoder()),
)
Module(documentation:, type_aliases:, types:, constants:, functions:)
|> decode.success
}

pub fn type_alias_decoder(dynamic: Dynamic) -> Result(TypeAlias, DecodeErrors) {
dynamic.decode4(
TypeAlias,
dynamic.field("documentation", dynamic.optional(dynamic.string)),
dynamic.field("deprecation", dynamic.optional(deprecation_decoder)),
dynamic.field("parameters", dynamic.int),
dynamic.field("alias", type_decoder),
)(dynamic)
pub fn type_alias_decoder() -> Decoder(TypeAlias) {
use documentation <- decode.field(
"documentation",
decode.optional(decode.string),
)
use deprecation <- decode.field(
"deprecation",
decode.optional(deprecation_decoder()),
)
use parameters <- decode.field("parameters", decode.int)
use alias <- decode.field("alias", type_decoder())
TypeAlias(documentation:, deprecation:, parameters:, alias:)
|> decode.success
}

pub fn type_definition_decoder(
dynamic: Dynamic,
) -> Result(TypeDefinition, DecodeErrors) {
dynamic.decode4(
TypeDefinition,
dynamic.field("documentation", dynamic.optional(dynamic.string)),
dynamic.field("deprecation", dynamic.optional(deprecation_decoder)),
dynamic.field("parameters", dynamic.int),
dynamic.field("constructors", dynamic.list(constructor_decoder)),
)(dynamic)
pub fn type_definition_decoder() -> Decoder(TypeDefinition) {
use documentation <- decode.field(
"documentation",
decode.optional(decode.string),
)
use deprecation <- decode.field(
"deprecation",
decode.optional(deprecation_decoder()),
)
use parameters <- decode.field("parameters", decode.int)
use constructors <- decode.field(
"constructors",
decode.list(constructor_decoder()),
)
TypeDefinition(documentation:, deprecation:, parameters:, constructors:)
|> decode.success
}

pub fn constant_decoder(dynamic: Dynamic) -> Result(Constant, DecodeErrors) {
dynamic.decode4(
Constant,
dynamic.field("documentation", dynamic.optional(dynamic.string)),
dynamic.field("deprecation", dynamic.optional(deprecation_decoder)),
dynamic.field("implementations", implementations_decoder),
dynamic.field("type", type_decoder),
)(dynamic)
pub fn constant_decoder() -> Decoder(Constant) {
use documentation <- decode.field(
"documentation",
decode.optional(decode.string),
)
use deprecation <- decode.field(
"deprecation",
decode.optional(deprecation_decoder()),
)
use implementations <- decode.field(
"implementations",
implementations_decoder(),
)
use type_ <- decode.field("type", type_decoder())
Constant(documentation:, deprecation:, implementations:, type_:)
|> decode.success
}

pub fn function_decoder(dynamic: Dynamic) -> Result(Function, DecodeErrors) {
dynamic.decode5(
Function,
dynamic.field("documentation", dynamic.optional(dynamic.string)),
dynamic.field("deprecation", dynamic.optional(deprecation_decoder)),
dynamic.field("implementations", implementations_decoder),
dynamic.field("parameters", dynamic.list(parameter_decoder)),
dynamic.field("return", type_decoder),
)(dynamic)
pub fn function_decoder() -> Decoder(Function) {
use documentation <- decode.field(
"documentation",
decode.optional(decode.string),
)
use deprecation <- decode.field(
"deprecation",
decode.optional(deprecation_decoder()),
)
use implementations <- decode.field(
"implementations",
implementations_decoder(),
)
use parameters <- decode.field("parameters", decode.list(parameter_decoder()))
use return <- decode.field("return", type_decoder())
Function(documentation:, deprecation:, implementations:, parameters:, return:)
|> decode.success
}

pub fn deprecation_decoder(
dynamic: Dynamic,
) -> Result(Deprecation, DecodeErrors) {
dynamic.decode1(Deprecation, dynamic.field("message", dynamic.string))(
dynamic,
)
pub fn deprecation_decoder() -> Decoder(Deprecation) {
use message <- decode.field("message", decode.string)
decode.success(Deprecation(message:))
}

pub fn constructor_decoder(
dynamic: Dynamic,
) -> Result(TypeConstructor, DecodeErrors) {
dynamic.decode3(
TypeConstructor,
dynamic.field("documentation", dynamic.optional(dynamic.string)),
dynamic.field("name", dynamic.string),
dynamic.field("parameters", dynamic.list(parameter_decoder)),
)(dynamic)
pub fn constructor_decoder() -> Decoder(TypeConstructor) {
use documentation <- decode.field(
"documentation",
decode.optional(decode.string),
)
use name <- decode.field("name", decode.string)
use parameters <- decode.field("parameters", decode.list(parameter_decoder()))
decode.success(TypeConstructor(documentation:, name:, parameters:))
}

pub fn implementations_decoder(
dynamic: Dynamic,
) -> Result(Implementations, DecodeErrors) {
dynamic.decode3(
Implementations,
dynamic.field("gleam", dynamic.bool),
dynamic.field("uses-erlang-externals", dynamic.bool),
dynamic.field("uses-javascript-externals", dynamic.bool),
)(dynamic)
pub fn implementations_decoder() -> Decoder(Implementations) {
use gleam <- decode.field("gleam", decode.bool)
use uses_erlang_externals <- decode.field(
"uses-erlang-externals",
decode.bool,
)
use uses_javascript_externals <- decode.field(
"uses-javascript-externals",
decode.bool,
)
decode.success(Implementations(
gleam:,
uses_erlang_externals:,
uses_javascript_externals:,
))
}

pub fn parameter_decoder(dynamic: Dynamic) -> Result(Parameter, DecodeErrors) {
dynamic.decode2(
Parameter,
dynamic.field("label", dynamic.optional(dynamic.string)),
dynamic.field("type", type_decoder),
)(dynamic)
pub fn parameter_decoder() -> Decoder(Parameter) {
use label <- decode.field("label", decode.optional(decode.string))
use type_ <- decode.field("type", type_decoder())
decode.success(Parameter(label:, type_:))
}

pub fn type_decoder(dynamic: Dynamic) -> Result(Type, DecodeErrors) {
use kind <- result.try(dynamic.field("kind", dynamic.string)(dynamic))
pub fn type_decoder() -> Decoder(Type) {
use kind <- decode.field("kind", decode.string)
case kind {
"variable" ->
dynamic.decode1(Variable, dynamic.field("id", dynamic.int))(dynamic)
"variable" -> {
use id <- decode.field("id", decode.int)
decode.success(Variable(id:))
}

"tuple" ->
dynamic.decode1(
Tuple,
dynamic.field("elements", dynamic.list(type_decoder)),
)(dynamic)
"tuple" -> {
use elements <- decode.field("elements", decode.list(type_decoder()))
decode.success(Tuple(elements:))
}

"named" ->
dynamic.decode4(
Named,
dynamic.field("name", dynamic.string),
dynamic.field("package", dynamic.string),
dynamic.field("module", dynamic.string),
dynamic.field("parameters", dynamic.list(type_decoder)),
)(dynamic)
"named" -> {
use name <- decode.field("name", decode.string)
use package <- decode.field("package", decode.string)
use module <- decode.field("module", decode.string)
use parameters <- decode.field("parameters", decode.list(type_decoder()))
decode.success(Named(name:, package:, module:, parameters:))
}

"fn" ->
dynamic.decode2(
Fn,
dynamic.field("parameters", dynamic.list(type_decoder)),
dynamic.field("return", type_decoder),
)(dynamic)
"fn" -> {
use parameters <- decode.field("parameters", decode.list(type_decoder()))
use return <- decode.field("return", type_decoder())
decode.success(Fn(parameters:, return:))
}

unknown_tag ->
Error([
dynamic.DecodeError(
expected: "one of variable, tuple, named, fn",
found: unknown_tag,
path: ["kind"],
),
])
_unknown_tag ->
decode.failure(Variable(id: 0), "String of variable, tuple, named, or fn")
}
}

// --- UTILITY FUNCTIONS -------------------------------------------------------

fn string_dict(values: Decoder(a)) -> Decoder(Dict(String, a)) {
dynamic.dict(dynamic.string, values)
}
2 changes: 1 addition & 1 deletion test/gleam_package_interface_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub fn main() {

pub fn decoding_a_module_interface_test() {
let assert Ok(raw_package) = simplifile.read("./priv/interface.json")
let assert Ok(package) = json.decode(raw_package, package_interface.decoder)
let assert Ok(package) = json.parse(raw_package, package_interface.decoder())

pretty_package(package)
|> birdie.snap(title: "Decoding a module interface")
Expand Down

0 comments on commit 89285aa

Please sign in to comment.