Universe

To-Stuff is a small package of Typst functions for converting string values to native types. This is most useful when loading layout data from an external configuration source, such as a YAML file.

How To Use

Import the module into the current scope, optionally renamed using the as keyword:

#import "@preview/to-stuff:0.1.0"
// Bindings available as to-stuff.alignment(), to-stuff.angle(), etc.

#import "@preview/to-stuff:0.1.0" as to
// Bindings available as to.alignment(), to.angle(), etc.

The module’s let bindings have the same names as their return types, and rely on Typst’s import syntax to scope safely. It is not recommended to load the individual bindings into the current scope, as that may cause collisions with the types themselves.

#import "@preview/to-stuff:0.1.0": *
// NOT RECOMMENDED
// Bindings will collide with built-in types: alignment, angle, etc.

Functions

alignment()

Attempts to convert a value to an alignment.

#alignment(
	str|alignment|dictionary,
	quiet: bool,
) -> none|alignment

value

str or alignment or dictionary (positional, required)

The value that should be converted to an alignment.

  • An alignment is returned unchanged.
  • A string representation of any of the eight alignment values is converted to that value.
    • If the string includes the alignment.… scoping prefix, the conversion fails.
  • A string consisting of two alignment representations joined by a plus sign is converted to the corresponding 2D alignment, provided the two strings do not correspond to alignments on the same axis.
  • A dictionary containing one or more of the keys x and y, and no other keys, is converted.
    • The value of x, if present, must be either a horizontal alignment or a value that would convert to one.
    • The value of y, if present, must be either a vertical alignment or a value that would convert to one.

quiet

bool

Whether to return none if the value could not be converted. If false, invalid values cause a panic.

Default: false

View examples
#import "@preview/to-stuff:0.1.0" as to

#let a = to.alignment("top + right")
// -> right + top

#let b = to.alignment(top + right)
// -> right + top

#let c = to.alignment((x: "right", y: "top"))
// -> right + top

#let d = to.alignment("turnwise")
// panics with: "could not convert to alignment: \"turnwise\""

#let e = to.alignment("top + bottom")
// panics with: "cannot add two vertical alignments: \"top + bottom\""

#let f = to.alignment(quiet: true, "top + bottom")
// -> none

angle()

Attempts to convert a value to an angle.

#angle(
	str|angle,
	quiet: bool,
) -> none|angle

value

str or angle (positional, required)

The value that should be converted to an angle.

  • An angle is returned unchanged.
  • A string representation of a number followed by the letters deg or rad is converted.
    • The number may be positive or negative, and may contain decimal places.

quiet

bool

Whether to return none if the value could not be converted. If false, invalid values cause a panic.

Default: false

View examples
#import "@preview/to-stuff:0.1.0" as to

#let a = to.angle("45deg")
// -> 45deg

#let b = to.angle(45deg)
// -> 45deg

#let c = to.angle("42")
// panics with: "could not convert to angle: \"42\""

#let d = to.angle(quiet: true, "42")
// -> none

color()

Attempts to convert a value to a color.

#angle(
	str|color,
	quiet: bool,
) -> none|color

value

str or color (positional, required)

The value that should be converted to a color.

  • A color is returned unchanged.
  • A string representation of a predefined color value is converted to that built-in color.
  • A string representation of a hash symbol followed by a 6- or 8-digit hexadecimal code is converted to the corresponding RGB or RGBA value.
  • A string representation of a color space function followed by parentheses and arguments is converted.
    • If the string includes the color.… scoping prefix, the conversion fails. This includes the hsl, hsv, and linear-rgb functions.

Note: Color space function arguments are not currently checked for validity before the string is passed to eval(). Invalid function arguments causes a native Typst syntax error rather than a panic; this error cannot be suppressed by setting quiet to true (see below). This may change in a future version.

quiet

bool

Whether to return none if the value could not be converted. If false, invalid values cause a panic.

Default: false

View examples
#import "@preview/to-stuff:0.1.0" as to

#let a = to.color("red")
// -> rgb("#ff4136")

#let b = to.color(red)
// -> rgb("#ff4136")

#let c = to.color("#FF4136FF")
// -> rgb("#ff4136")

#let d = to.color("rgb(255, 65, 54)")
// -> rgb("#ff4136")

#let e = to.color("hsv(135deg,75%,127,100)")
// -> color.hsv(135deg, 75%, 49.8%, 39.22%)

#let f = to.color("indigo")
// panics with: "could not convert to color: \"indigo\""

#let g = to.color(quiet: true, "indigo")
// -> none

direction()

Attempts to convert a value to a direction.

#direction(
	str|direction,
	quiet: bool,
) -> none|direction

value

str or direction (positional, required)

The value that should be converted to a direction.

  • A direction is returned unchanged.
  • A string representation of any of the four direction values is converted to that value.
    • If the string includes the direction.… scoping prefix, the conversion fails.

quiet

bool

Whether to return none if the value could not be converted. If false, invalid values cause a panic.

Default: false

View examples
#import "@preview/to-stuff:0.1.0" as to

#let a = to.direction("rtl")
// -> rtl

#let b = to.direction(rtl)
// -> rtl

#let c = to.direction("btf")
// panics with: "could not convert to direction: \"btf\""

#let d = to.direction(quiet: true, "btf")
// -> none

fraction()

Attempts to convert a value to a fraction.

#fraction(
	str|fraction,
	quiet: bool,
) -> none|fraction

value

str or fraction (positional, required)

The value that should be converted to a fraction.

  • A fraction is returned unchanged.
  • A string representation of a number followed by the letters fr is converted.
    • The number may be positive or negative, and may contain decimal places.

quiet

bool

Whether to return none if the value could not be converted. If false, invalid values cause a panic.

Default: false

View examples
#import "@preview/to-stuff:0.1.0" as to

#let a = to.fraction("2.5fr")
// -> 2.5fr

#let b = to.fraction(2.5fr)
// -> 2.5fr

#let c = to.fraction("42")
// panics with: "could not convert to fraction: \"42\""

#let d = to.fraction(quiet: true, "42")
// -> none

length()

Attempts to convert a value to a length.

#length(
	str|length,
	quiet: bool,
) -> none|length

value

str or length (positional, required)

The value that should be converted to a length.

  • A length is returned unchanged.
  • A string representation of a number followed by the letters pt, mm, cm, in, or em, is converted.
    • The number may be positive or negative, and may contain decimal places.

quiet

bool

Whether to return none if the value could not be converted. If false, invalid values cause a panic.

Default: false

View examples
#import "@preview/to-stuff:0.1.0" as to

#let a = to.length("45pt")
// -> 45pt

#let b = to.length(45pt)
// -> 45pt

#let c = to.length("42")
// panics with: "could not convert to length: \"42\""

#let d = to.length(quiet: true, "42")
// -> none

ratio()

Attempts to convert a value to a ratio.

#ratio(
	str|ratio,
	quiet: bool,
) -> none|ratio

value

str or ratio (positional, required)

The value that should be converted to a ratio.

  • A ratio is returned unchanged.
  • A string representation of a number followed by a percent sign is converted.
    • The number may be positive or negative, and may contain decimal places.

quiet

bool

Whether to return none if the value could not be converted. If false, invalid values cause a panic.

Default: false

View examples
#import "@preview/to-stuff:0.1.0" as to

#let a = to.ratio("45%")
// -> 45%

#let b = to.ratio(45%)
// -> 45%

#let c = to.ratio("42")
// panics with: "could not convert to ratio: \"42\""

#let d = to.ratio(quiet: true, "42")
// -> none

relative()

Attempts to convert a value to a relative.

#relative(
	str|relative|ratio|length|dictionary,
	quiet: bool,
) -> none|relative

value

str or relative or ratio or length or dictionary (positional, required)

The value that should be converted to a relative.

  • A relative is returned unchanged.
  • A ratio is returned as a relative with a length of 0pt.
  • A length is returned as a relative with a ratio of 0%.
  • A string representation of a ratio (see above) is converted.
  • A string representation of a length (see above) is converted.
  • A string consisting of multiple ratios and lengths joined by plus signs or minus signs is converted to a single relative length.
    • All length-like substrings are added.
    • All ratio-like substrings are added.
  • A dictionary containing one or more of the keys ratio and length, and no other keys, is converted.
    • The value of ratio, if present, must be either a ratio or a value that would convert to one.
    • The value of length, if present, must be either a length or a value that would convert to one.

quiet

bool

Whether to return none if the value could not be converted. If false, invalid values cause a panic.

Default: false

View examples
#import "@preview/to-stuff:0.1.0" as to

#let a = to.relative("45pt + 3%")
// -> 3% + 45pt

#let b = to.relative(45pt + 3%)
// -> 3% + 45pt

#let c = to.relative((ratio: "3%", length: "45pt"))
// -> 3% + 45pt

#let d = to.relative("42")
// panics with: "could not convert to relative: \"42\""

#let e = to.relative(quiet: true, "42")
// -> none

stroke()

Attempts to convert a value to a stroke.

#stroke(
	str|stroke|color|length|array|dictionary,
	quiet: bool,
) -> none|stroke

value

str or stroke or color or length or array or dictionary (positional, required)

The value that should be converted to a stroke.

  • A stroke, color or length is returned unchanged.
  • A string representation of a color (see above) is converted.
  • A string representation of a length (see above) is converted.
  • A valid dash pattern is converted.
  • A string representation of one or more valid colors, lengths and/or predefined dash patterns joined by plus signs is converted.
    • All color-like substrings are combined via color.mix().
    • All length-like substrings added.
  • A dictionary that would otherwise be accepted as a valid stroke is converted.

quiet

bool

Whether to return none if the value could not be converted. If false, invalid values cause a panic.

Default: false

View examples
#import "@preview/to-stuff:0.1.0" as to

#let a = to.stroke("red")
// -> rgb("#ff4136")

#let b = to.stroke(45pt)
// -> 45pt

#let c = to.stroke("densely-dashed")
// -> (dash: array(3pt, 2pt), phase: 0pt)

#let d = to.stroke((3pt, 2pt))
// -> (dash: array(3pt, 2pt), phase: 0pt)

#let e = to.stroke((paint: red, thickness: 2pt, dash: "densely-dashed"))
// -> (paint: rgb("#ff4136"), thickness: 2pt, dash: (array: (3pt, 2pt), phase: 0pt))

#let f = to.stroke("2pt + red + densely-dashed + silver + 5pt")
// -> (paint: oklab(77.85%, 0.1, 0.054), thickness: 7pt, dash: (array: (3pt, 2pt), phase: 0pt))

#let g = to.stroke("deep-dish")
// panics with: "could not convert to stroke: \"deep-dish\""

#let h = to.stroke(quiet: true, "deep-dish")
// -> none