Skip to content

Module hb_singleton.erl

A parser that translates AO-Core HTTP API requests in TABM format into an ordered list of messages to evaluate.

Description

The details of this format are described in docs/ao-core-http-api.md.

Syntax overview:

       Singleton: Message containing keys and a <code>path</code> field,
                  which may also contain a query string of key-value pairs.
       Path:
           - /Part1/Part2/.../PartN/ => [Part1, Part2, ..., PartN]
           - /ID/Part2/.../PartN => [ID, Part2, ..., PartN]
       Part: (Key + Resolution), Device?, #{ K => V}?
           - Part => #{ path => Part }
           - <code>Part&Key=Value => #{ path => Part, Key => Value }</code>
           - <code>Part&Key => #{ path => Part, Key => true }</code>
           - <code>Part&k1=v1&k2=v2 => #{ path => Part, k1 => `<<"v1">></code>, k2 => <code><<"v2">></code> }'
           - <code>Part~Device => {as, Device, #{ path => Part }}</code>
           - <code>Part~D&K1=V1 => {as, D, #{ path => Part, K1 => `<<"v1">></code> }}'
           - <code>pt&k1+int=1 => #{ path => pt, k1 => 1 }</code>
           - <code>pt~d&k1+int=1 => {as, d, #{ path => pt, k1 => 1 }}</code>
           - <code>(/nested/path) => Resolution of the path /nested/path</code>
           - <code>(/nested/path&k1=v1) => (resolve /nested/path)#{k1 => v1}</code>
           - <code>(/nested/path~D&K1=V1) => (resolve /nested/path)#{K1 => V1}</code>
           - <code>pt&k1+res=(/a/b/c) => #{ path => pt, k1 => (resolve /a/b/c) }</code>
       Key:
           - key: <code><<"value">></code> => #{ key => <code><<"value">></code>, ... } for all messages
           - n.key: <code><<"value">></code> => #{ key => <code><<"value">></code>, ... } for Nth message
           - key+int: 1 => #{ key => 1, ... }
           - key+res: /nested/path => #{ key => (resolve /nested/path), ... }
           - N.Key+res=(/a/b/c) => #{ Key => (resolve /a/b/c), ... }

Data Types

ao_message()


ao_message() = map() | binary()

tabm_message()


tabm_message() = map()

Function Index

all_path_parts/2*Extract all of the parts from the binary, given (a list of) separators.
append_path/2*
apply_types/2*Step 3: Apply types to values and remove specifiers.
basic_hashpath_test/0*
basic_hashpath_to_test/0*
build_messages/3*Step 5: Merge the base message with the scoped messages.
decode_string/1*Attempt Cowboy URL decode, then sanitize the result.
do_build/4*
from/2Normalize a singleton TABM message into a list of executable AO-Core messages.
group_scoped/2*Step 4: Group headers/query by N-scope.
inlined_keys_test/0*
inlined_keys_to_test/0*
maybe_join/2*Join a list of items with a separator, or return the first item if there is only one item.
maybe_subpath/2*Check if the string is a subpath, returning it in parsed form, or the original string with a specifier.
maybe_typed/3*Parse a key's type (applying it to the value) and device name if present.
multiple_inlined_keys_test/0*
multiple_inlined_keys_to_test/0*
multiple_messages_test/0*
multiple_messages_to_test/0*
normalize_base/1*Normalize the base path.
parse_explicit_message_test/0*
parse_full_path/1*Parse the relative reference into path, query, and fragment.
parse_inlined_key_val/2*Extrapolate the inlined key-value pair from a path segment.
parse_part/2*Parse a path part into a message or an ID.
parse_part_mods/3*Parse part modifiers: 1.
parse_scope/1*Get the scope of a key.
part/2*Extract the characters from the binary until a separator is found.
part/4*
path_messages/2*Step 2: Decode, split and sanitize the path.
path_parts/2*Split the path into segments, filtering out empty segments and segments that are too long.
path_parts_test/0*
scoped_key_test/0*
scoped_key_to_test/0*
simple_to_test/0*
single_message_test/0*
subpath_in_inlined_test/0*
subpath_in_inlined_to_test/0*
subpath_in_key_test/0*
subpath_in_key_to_test/0*
subpath_in_path_test/0*
subpath_in_path_to_test/0*
to/1Convert a list of AO-Core message into TABM message.
to_suite_test_/0*
type/1*
typed_key_test/0*
typed_key_to_test/0*

Function Details

all_path_parts/2 *

all_path_parts(Sep, Bin) -> any()

Extract all of the parts from the binary, given (a list of) separators.

append_path/2 *

append_path(PathPart, Message) -> any()

apply_types/2 *

apply_types(Msg, Opts) -> any()

Step 3: Apply types to values and remove specifiers.

basic_hashpath_test/0 *

basic_hashpath_test() -> any()

basic_hashpath_to_test/0 *

basic_hashpath_to_test() -> any()

build_messages/3 *

build_messages(Msgs, ScopedModifications, Opts) -> any()

Step 5: Merge the base message with the scoped messages.

decode_string/1 *

decode_string(B) -> any()

Attempt Cowboy URL decode, then sanitize the result.

do_build/4 *

do_build(I, Rest, ScopedKeys, Opts) -> any()

from/2

from(RawMsg, Opts) -> any()

Normalize a singleton TABM message into a list of executable AO-Core messages.

group_scoped/2 *

group_scoped(Map, Msgs) -> any()

Step 4: Group headers/query by N-scope. N.Key => applies to Nth step. Otherwise => global

inlined_keys_test/0 *

inlined_keys_test() -> any()

inlined_keys_to_test/0 *

inlined_keys_to_test() -> any()

maybe_join/2 *

maybe_join(Items, Sep) -> any()

Join a list of items with a separator, or return the first item if there is only one item. If there are no items, return an empty binary.

maybe_subpath/2 *

maybe_subpath(Str, Opts) -> any()

Check if the string is a subpath, returning it in parsed form, or the original string with a specifier.

maybe_typed/3 *

maybe_typed(Key, Value, Opts) -> any()

Parse a key's type (applying it to the value) and device name if present. We allow characters as type indicators because some URL-string encoders (e.g. Chrome) will encode `+` characters in a form that query-string parsers interpret as characters.

multiple_inlined_keys_test/0 *

multiple_inlined_keys_test() -> any()

multiple_inlined_keys_to_test/0 *

multiple_inlined_keys_to_test() -> any()

multiple_messages_test/0 *

multiple_messages_test() -> any()

multiple_messages_to_test/0 *

multiple_messages_to_test() -> any()

normalize_base/1 *

normalize_base(Rest) -> any()

Normalize the base path.

parse_explicit_message_test/0 *

parse_explicit_message_test() -> any()

parse_full_path/1 *

parse_full_path(RelativeRef) -> any()

Parse the relative reference into path, query, and fragment.

parse_inlined_key_val/2 *

parse_inlined_key_val(Bin, Opts) -> any()

Extrapolate the inlined key-value pair from a path segment. If the key has a value, it may provide a type (as with typical keys), but if a value is not provided, it is assumed to be a boolean true.

parse_part/2 *

parse_part(ID, Opts) -> any()

Parse a path part into a message or an ID. Applies the syntax rules outlined in the module doc, in the following order: 1. ID 2. Part subpath resolutions 3. Inlined key-value pairs 4. Device specifier

parse_part_mods/3 *

parse_part_mods(X1, Msg, Opts) -> any()

Parse part modifiers: 1. ~Device => {as, Device, Msg} 2. &K=V => Msg#{ K => V }

parse_scope/1 *

parse_scope(KeyBin) -> any()

Get the scope of a key. Adds 1 to account for the base message.

part/2 *

part(Sep, Bin) -> any()

Extract the characters from the binary until a separator is found. The first argument of the function is an explicit separator character, or a list of separator characters. Returns a tuple with the separator, the accumulated characters, and the rest of the binary.

part/4 *

part(Seps, X2, Depth, CurrAcc) -> any()

path_messages/2 *

path_messages(RawBin, Opts) -> any()

Step 2: Decode, split and sanitize the path. Split by / but avoid subpath components, such that their own path parts are not dissociated from their parent path.

path_parts/2 *

path_parts(Sep, PathBin) -> any()

Split the path into segments, filtering out empty segments and segments that are too long.

path_parts_test/0 *

path_parts_test() -> any()

scoped_key_test/0 *

scoped_key_test() -> any()

scoped_key_to_test/0 *

scoped_key_to_test() -> any()

simple_to_test/0 *

simple_to_test() -> any()

single_message_test/0 *

single_message_test() -> any()

subpath_in_inlined_test/0 *

subpath_in_inlined_test() -> any()

subpath_in_inlined_to_test/0 *

subpath_in_inlined_to_test() -> any()

subpath_in_key_test/0 *

subpath_in_key_test() -> any()

subpath_in_key_to_test/0 *

subpath_in_key_to_test() -> any()

subpath_in_path_test/0 *

subpath_in_path_test() -> any()

subpath_in_path_to_test/0 *

subpath_in_path_to_test() -> any()

to/1


to(Messages::[ao_message()]) -> tabm_message()


Convert a list of AO-Core message into TABM message.

to_suite_test_/0 *

to_suite_test_() -> any()

type/1 *

type(Value) -> any()

typed_key_test/0 *

typed_key_test() -> any()

typed_key_to_test/0 *

typed_key_to_test() -> any()