Packages
caffeine_lang
0.0.19
6.3.1
6.3.0
6.2.2
6.2.1
6.2.0
6.1.2
6.1.1
6.1.0
6.0.0
5.6.0
5.5.0
5.4.4
5.4.3
5.4.2
5.4.1
5.4.0
5.3.0
5.2.0
5.1.1
5.1.0
5.0.12
5.0.11
5.0.10
5.0.8
5.0.7
5.0.6
5.0.5
5.0.4
5.0.1
5.0.0
4.10.0
4.9.0
4.8.3
4.8.2
4.8.1
4.8.0
4.7.9
4.7.8
4.7.7
4.7.6
4.7.5
4.6.7
4.6.6
4.6.5
4.6.4
4.6.3
4.6.2
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.7
4.3.6
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.0.2
1.0.1
0.1.0
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.2
0.0.1
A compiler for generating reliability artifacts from service expectation definitions.
Current section
Files
Jump to
Current section
Files
src/caffeine_lang/phase_1/parser/utils/glaml_helpers.gleam
import glaml
import gleam/dict
import gleam/int
import gleam/list
import gleam/result
// ==== Public ====
/// Parses a specification file into a list of glaml documents according to the given parse function.
pub fn parse_specification(
file_path: String,
params: dict.Dict(String, String),
parse_fn: fn(glaml.Node, dict.Dict(String, String)) -> Result(a, String),
key: String,
) -> Result(List(a), String) {
// TODO: consider enforcing constraints on file path, however for now, unnecessary.
// parse the YAML file
use doc <- result.try(
glaml.parse_file(file_path)
|> result.map_error(fn(_) { "Failed to parse YAML file: " <> file_path }),
)
let parse_fn_two = fn(doc, _params) {
iteratively_parse_collection(
glaml.document_root(doc),
params,
parse_fn,
key,
)
}
// parse the intermediate representation, here just the sli_types
case doc {
[first, ..] -> parse_fn_two(first, params)
_ -> Error("Empty YAML file: " <> file_path)
}
}
/// Extracts a string from a glaml node.
pub fn extract_string_from_node(
node: glaml.Node,
key: String,
) -> Result(String, String) {
use query_template_node <- result.try(case glaml.select_sugar(node, key) {
Ok(node) -> Ok(node)
Error(_) -> Error("Missing " <> key)
})
case query_template_node {
glaml.NodeStr(value) -> Ok(value)
_ -> Error("Expected " <> key <> " to be a string")
}
}
/// Extracts a float from a glaml node.
pub fn extract_float_from_node(
node: glaml.Node,
key: String,
) -> Result(Float, String) {
use query_template_node <- result.try(case glaml.select_sugar(node, key) {
Ok(node) -> Ok(node)
Error(_) -> Error("Missing " <> key)
})
case query_template_node {
glaml.NodeFloat(value) -> Ok(value)
_ -> Error("Expected " <> key <> " to be a float")
}
}
/// Extracts an integer from a glaml node.
pub fn extract_int_from_node(
node: glaml.Node,
key: String,
) -> Result(Int, String) {
use query_template_node <- result.try(case glaml.select_sugar(node, key) {
Ok(node) -> Ok(node)
Error(_) -> Error("Missing " <> key)
})
case query_template_node {
glaml.NodeInt(value) -> Ok(value)
_ -> Error("Expected " <> key <> " to be an integer")
}
}
/// Extracts a boolean from a glaml node
pub fn extract_bool_from_node(
node: glaml.Node,
key: String,
) -> Result(Bool, String) {
use query_template_node <- result.try(case glaml.select_sugar(node, key) {
Ok(node) -> Ok(node)
Error(_) -> Error("Missing " <> key)
})
case query_template_node {
glaml.NodeBool(value) -> Ok(value)
_ -> Error("Expected " <> key <> " to be a boolean")
}
}
/// Extracts a list of strings from a glaml node.
pub fn extract_string_list_from_node(
node: glaml.Node,
key: String,
) -> Result(List(String), String) {
use list_node <- result.try(case glaml.select_sugar(node, key) {
Ok(node) -> Ok(node)
Error(_) -> Error("Missing " <> key)
})
// Try to access the first element to validate it's a list structure
case glaml.select_sugar(list_node, "#0") {
Ok(_) -> do_extract_string_list(list_node, 0)
Error(_) -> {
// Check if it's a non-list node that would cause the wrong error
case list_node {
glaml.NodeStr(_) ->
Error("Expected " <> key <> " list item to be a string")
_ -> Error("Expected " <> key <> " to be a list")
}
}
}
}
/// Extracts a dictionary of string key-value pairs from a glaml node.
/// Returns an empty dict if the key is missing (allowing optional empty dicts).
pub fn extract_dict_strings_from_node(
node: glaml.Node,
key: String,
) -> Result(dict.Dict(String, String), String) {
case glaml.select_sugar(node, key) {
Ok(dict_node) -> {
case dict_node {
glaml.NodeMap(entries) -> {
entries
|> list.try_map(fn(entry) {
case entry {
#(glaml.NodeStr(dict_key), glaml.NodeStr(value)) ->
Ok(#(dict_key, value))
_ ->
Error("Expected " <> key <> " entries to be string key-value pairs")
}
})
|> result.map(dict.from_list)
}
_ -> Error("Expected " <> key <> " to be a map")
}
}
Error(_) -> {
// If the key is missing, return an empty dict (allows optional empty instantiation)
Ok(dict.new())
}
}
}
// ==== Private ====
/// Iteratively parses a collection of nodes.
fn iteratively_parse_collection(
root: glaml.Node,
params: dict.Dict(String, String),
actual_parse_fn: fn(glaml.Node, dict.Dict(String, String)) ->
Result(a, String),
key: String,
) -> Result(List(a), String) {
use services_node <- result.try(
glaml.select_sugar(root, key)
|> result.map_error(fn(_) { "Missing " <> key }),
)
do_parse_collection(services_node, 0, params, actual_parse_fn)
}
/// Internal parser for list of nodes, iterates over the list.
fn do_parse_collection(
services: glaml.Node,
index: Int,
params: dict.Dict(String, String),
actual_parse_fn: fn(glaml.Node, dict.Dict(String, String)) ->
Result(a, String),
) -> Result(List(a), String) {
case glaml.select_sugar(services, "#" <> int.to_string(index)) {
Ok(service_node) -> {
use service <- result.try(actual_parse_fn(service_node, params))
use rest <- result.try(do_parse_collection(
services,
index + 1,
params,
actual_parse_fn,
))
Ok([service, ..rest])
}
// TODO: fix this super hacky way of iterating over SLOs.
Error(_) -> Ok([])
}
}
/// Internal helper for extracting string lists from glaml nodes.
fn do_extract_string_list(
list_node: glaml.Node,
index: Int,
) -> Result(List(String), String) {
case glaml.select_sugar(list_node, "#" <> int.to_string(index)) {
Ok(item_node) -> {
case item_node {
glaml.NodeStr(value) -> {
use rest <- result.try(do_extract_string_list(list_node, index + 1))
Ok([value, ..rest])
}
_ -> Error("Expected list item to be a string")
}
}
Error(_) -> Ok([])
}
}