+4
-1
.gitignore
+4
-1
.gitignore
+61
apps/backend/lib/comet/aturi.ex
+61
apps/backend/lib/comet/aturi.ex
···
1
+
defmodule Comet.AtURI do
2
+
use TypedStruct
3
+
4
+
@did "did:(?:plc|web):[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]"
5
+
@handle "(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?"
6
+
@nsid "[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z0-9]{0,62})?)"
7
+
8
+
@authority "(?<authority>(?:#{@did})|(?:#{@handle}))"
9
+
@collection "(?<collection>#{@nsid})"
10
+
@rkey "(?<rkey>[a-zA-Z0-9.-_:~]{1,512})"
11
+
12
+
@re ~r"^at://#{@authority}(?:/#{@collection}(?:/#{@rkey})?)?$"
13
+
14
+
typedstruct do
15
+
field :authority, String.t(), enforce: true
16
+
field :collection, String.t() | nil
17
+
field :rkey, String.t() | nil
18
+
end
19
+
20
+
@spec new(String.t()) :: {:ok, t()} | :error
21
+
def new(string) when is_binary(string) do
22
+
case Regex.named_captures(@re, string) do
23
+
%{} = captures -> {:ok, from_named_captures(captures)}
24
+
nil -> :error
25
+
end
26
+
end
27
+
28
+
@spec new!(String.t()) :: t()
29
+
def new!(string) when is_binary(string) do
30
+
case new(string) do
31
+
{:ok, uri} -> uri
32
+
:error -> raise ArgumentError, message: "Malformed at:// URI"
33
+
end
34
+
end
35
+
36
+
@spec match?(String.t()) :: boolean()
37
+
def match?(string), do: Regex.match?(@re, string)
38
+
39
+
@spec to_string(t()) :: String.t()
40
+
def to_string(%__MODULE__{} = uri) do
41
+
"at://#{uri.authority}/#{uri.collection}/#{uri.rkey}"
42
+
|> String.trim_trailing("/")
43
+
end
44
+
45
+
defp from_named_captures(%{"authority" => authority, "collection" => "", "rkey" => ""}),
46
+
do: %__MODULE__{authority: authority}
47
+
48
+
defp from_named_captures(%{"authority" => authority, "collection" => collection, "rkey" => ""}),
49
+
do: %__MODULE__{authority: authority, collection: collection}
50
+
51
+
defp from_named_captures(%{
52
+
"authority" => authority,
53
+
"collection" => collection,
54
+
"rkey" => rkey
55
+
}),
56
+
do: %__MODULE__{authority: authority, collection: collection, rkey: rkey}
57
+
end
58
+
59
+
defimpl String.Chars, for: Comet.AtURI do
60
+
def to_string(%Comet.AtURI{} = uri), do: Comet.AtURI.to_string(uri)
61
+
end