Universe

Parse and normalize URLs, based on the WHATWG URL Standard, powered by rust-url and WebAssembly.

Example usages

Normalize URLs

#import "@preview/lure:0.1.0": normalize
#normalize("https://ja.wikipedia.org/wiki/アルベルト・アインシュタイン")
// ⇒ https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%AB%E3%83%99%E3%83%AB%E3%83%88%E3%83%BB%E3%82%A2%E3%82%A4%E3%83%B3%E3%82%B7%E3%83%A5%E3%82%BF%E3%82%A4%E3%83%B3

As the following example, you can create a wrapper of link to safely use URLs containing non-ASCII characters, before the official Typst compiler fixes #6128.

#import "@preview/lure:0.1.0": normalize
#let link(dest, ..body) = {
  assert.eq(body.named(), (:))
  assert(body.pos().len() <= 1)

  std.link(
    normalize(dest),
    body.pos().at(0, default: dest.replace(regex("^(mailto|tel)://"), "")),
  )
}

#link("https://law.go.kr/법령/보건의료기본법/제3조")[UTF-8 percent-encode automatically]
#link("https://w3c.github.io/clreq/README.zh-Hans.html#%E8%AE%A8%E8%AE%BA")[Keep it as it is if already encoded]

Unlike percencode, this package will not re-encode.

Convert between absolute and relative URLs

#import "@preview/lure:0.1.0": join, make-relative

#let base = "https://owner.github.io/repo/"

#let absolute = join(base, "/repo/image.png")
#assert.eq(absolute, "https://owner.github.io/repo/image.png")

#let relative = make-relative(base, absolute)
#assert.eq(relative, "image.png")

Parse URLs

#import "@preview/lure:0.1.0": parse, parse-supplementary

// Parse into components
#assert.eq(
  parse("ssh://git@ssh.github.com:443/YDX-2147483647/typst-lure.git"),
  (
    scheme: "ssh",
    cannot-be-a-base: false,
    username: "git",
    password: none,
    host: "ssh.github.com",
    port: 443,
    path: "/YDX-2147483647/typst-lure.git",
    query: none,
    fragment: none,
  ),
)

// Get supplementary information
#assert.eq(
  parse-supplementary("https://typst.app/universe/search/?q=url"),
  (
    origin: ("https", "typst.app", 443),
    is-special: true,
    authority: "typst.app",
    domain: "typst.app",
    port-or-known-default: 443,
    path-segments: ("universe", "search", ""),
    query-pairs: (("q", "url"),),
  ),
)

URLs can be tricky. Please refer to the documentation for detailed explanation of each field.