RFC 6570 Level 4 URI Template parser and expander for MoonBit
Dependencies
moon add Magic486/moon-uri-template///|
test "expand one scalar" {
let template = UriTemplate::parse("hello/{name}")
let variables : Map[String, UriValue] = {
"name": Scalar("MoonBit"),
}
assert_eq(template.expand(variables), "hello/MoonBit")
}///|
test "expand a repository issues URI" {
let template = UriTemplate::parse(
"/repos/{owner}/{repo}/issues{?page,labels*}",
)
let variables : Map[String, UriValue] = {
"owner": Scalar("moonbitlang"),
"repo": Scalar("core"),
"page": Scalar("2"),
"labels": List(["bug", "help wanted"]),
}
assert_eq(
template.expand(variables),
"/repos/moonbitlang/core/issues?page=2&labels=bug&labels=help%20wanted",
)
}///|
pub(all) enum UriValue {
Scalar(String)
List(Array[String])
Assoc(Array[(String, String)])
}///|
test "prefix length counts Unicode code points" {
let template = UriTemplate::parse("{value:2}")
let variables : Map[String, UriValue] = {
"value": Scalar("月兔Moon"),
}
assert_eq(template.expand(variables), "%E6%9C%88%E5%85%94")
}///|
test "explode a list into repeated query parameters" {
let template = UriTemplate::parse("{?labels*}")
let variables : Map[String, UriValue] = {
"labels": List(["bug", "help wanted"]),
}
assert_eq(template.expand(variables), "?labels=bug&labels=help%20wanted")
}///|
test "expand an associative value" {
let template = UriTemplate::parse("{?filters*}")
let variables : Map[String, UriValue] = {
"filters": Assoc([("state", "open"), ("author", "月兔")]),
}
assert_eq(template.expand(variables), "?state=open&author=%E6%9C%88%E5%85%94")
}///|
test "parse with application-specific limits" {
let template = UriTemplate::parse_with_limits(
"/users/{name}{?page}",
max_template_length=128,
max_expressions=2,
max_variables_per_expression=4,
)
assert_true(template.variables() == ["name", "page"])
}///|
test "handle a syntax error with its source offset" {
let rejected = try UriTemplate::parse("{unclosed") catch {
SyntaxError(offset~, message=_) => offset == 0
_ => false
} noraise {
_ => false
}
assert_true(rejected)
}{
"owner": "moonbitlang",
"repo": "core",
"page": "2",
"labels": ["bug", "help wanted"]
}moon run cmd/uri-template -- validate '/repos/{owner}/{repo}{?page}'
moon run cmd/uri-template -- variables '/repos/{owner}/{repo}{?page}'
moon run cmd/uri-template -- inspect '/repos/{owner}/{repo}{?page}'
moon run cmd/uri-template -- expand \
'/repos/{owner}/{repo}/issues{?page,labels*}' \
--variables examples/variables.json/repos/moonbitlang/core/issues?page=2&labels=bug&labels=help%20wantedpowershell -NoProfile -ExecutionPolicy Bypass \
-File tools/generate_conformance_tests.ps1
moon test --target allmoon check --warn-list +73
moon test --target all
moon fmt --check
moon infopub(all) suberror UriTemplateError {
SyntaxError(offset~ : Int, message~ : String)
InvalidValue(variable~ : String, message~ : String)
ParseLimitExceeded(kind~ : String, limit~ : Int)
OutputLimitExceeded(limit~ : Int)
} derive(Debug)impl Show for UriTemplateErrorpub struct UriTemplate {
source : String
parts : Array[TemplatePart]
variables : Array[String]
level : Int
}fn UriTemplate::expand(self : UriTemplate, variables : Map[String, UriValue]) -> String raise UriTemplateErrorfn UriTemplate::expand_with_limit(self : UriTemplate, variables : Map[String, UriValue], max_output_length~ : Int) -> String raise UriTemplateErrorfn UriTemplate::parse_with_limits(source : StringView, max_template_length~ : Int, max_expressions~ : Int, max_variables_per_expression~ : Int) -> UriTemplate raise UriTemplateErrorlet DEFAULT_MAX_EXPRESSIONS : Intlet DEFAULT_MAX_OUTPUT_LENGTH : Intlet DEFAULT_MAX_TEMPLATE_LENGTH : Intlet DEFAULT_MAX_VARIABLES_PER_EXPRESSION : Intfn is_valid(source : StringView) -> BoolRFC 6570 Level 4 URI Template parser and expander for MoonBit
Dependencies