> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mira.party/llms.txt
> Use this file to discover all available pages before exploring further.

# Operators & pipes

> Conditionals, maths, randomness and text formatting inside a script.

Variables give you values. Operators let you *do something* with them.

There are two shapes:

<CodeGroup>
  ```javascript Pipe — transforms one value theme={null}
  {guild.members|comma}
  {user.name|upper}
  {count|plural: member, members}
  ```

  ```javascript Operator — takes arguments theme={null}
  {if: {user.bot}==True && beep boop && welcome!}
  {rng: 1, 100}
  {random: hey, hi, yo}
  ```
</CodeGroup>

Pipes read left-to-right and are usually what you want for formatting. Operators are for logic.

## Conditionals

`{if: condition && then && else}` — the `else` half is optional.

```javascript theme={null}
{description: {if: {guild.boosts}>0 && thanks to our {guild.boosters} boosters && nobody's boosting yet :(}}
```

`{unless: ...}` is the same thing inverted. Aliases: `ifnot`, `ifn`, `not`.

### Comparisons

| Operator          | Meaning                           |
| ----------------- | --------------------------------- |
| `==` `!=`         | Equal / not equal                 |
| `>` `<` `>=` `<=` | Numeric comparison                |
| `contains`        | Substring match, case-insensitive |
| `not contains`    | Inverse of the above              |

Numbers are compared numerically when both sides look like numbers, and as text otherwise.

### Combining conditions

`and` / `&` and `or` / `|` both work, and `and` binds tighter than `or` — the same as most languages. Prefix any single condition with `!` to negate it.

```javascript theme={null}
{if: {user.level}>=10 and !{user.bot} && you're in && not yet}
{if: {guild.vanity} or {guild.boosts}>14 && nice server && }
```

### Truthiness

A bare value with no comparison is checked for truthiness:

```javascript theme={null}
{if: {guild.vanity} && we have a vanity && we don't}
```

These all count as **false**: empty, `0`, `false`, `none`, `null`, `never`, `permanent`, `forever`, `no reason provided`, `n/a`, `nothing`, `nobody`, `nowhere`. That last group exists so `{if: {reason} && ...}` behaves how you'd expect when no reason was given.

## Text formatting

| Pipe                  | Aliases | Input → Output                                  |
| --------------------- | ------- | ----------------------------------------------- |
| `\|upper`             | `u`     | `hey` → `HEY`                                   |
| `\|lower`             | `l`     | `HEY` → `hey`                                   |
| `\|title`             | `t`     | `hey there` → `Hey There`                       |
| `\|capitalize`        | `cap`   | `hey there` → `Hey there`                       |
| `\|length`            | `len`   | `hey` → `3`                                     |
| `\|replace: old, new` | `repl`  | `!{user.name\|replace: _, }` strips underscores |
| `\|default: fallback` | `or`    | Used when the value is empty or falsy           |

```javascript theme={null}
{description: welcome {user.display_name|title}, from {user.name|default: parts unknown}}
```

## Numbers

| Pipe        | Aliases                  | Input → Output                      |
| ----------- | ------------------------ | ----------------------------------- |
| `\|comma`   | `fmt`                    | `1247` → `1,247`                    |
| `\|human`   | `h`, `humanize`, `short` | `1247` → `1.2k`, `2400000` → `2.4m` |
| `\|ordinal` | `ord`                    | `3` → `3rd`                         |
| `\|plural`  | `plur`, `p`              | `1` → \`\`, `2` → `s`               |

`plural` also takes explicit words:

```javascript theme={null}
{description: {guild.boosts} {guild.boosts|plural: boost, boosts}}
{description: you're the {user.join_position|ordinal} member}
{footer: {guild.members|human} members}
```

### Arithmetic

| Operator      | Example                     | Result     |
| ------------- | --------------------------- | ---------- |
| `{add: a, b}` | `{add: {user.level}, 1}`    | Sum        |
| `{sub: a, b}` | `{sub: 100, {user.xp}}`     | Difference |
| `{div: a, b}` | `{div: {guild.members}, 2}` | Quotient   |
| `{floor: n}`  | `{floor: 4.9}`              | `4`        |
| `{ceil: n}`   | `{ceil: 4.1}`               | `5`        |
| `{round: n}`  | `{round: 4.5}`              | `5`        |

## Randomness

<CodeGroup>
  ```javascript Pick one theme={null}
  {random: hey, hello, yo, sup}
  ```

  ```javascript Random number theme={null}
  {rng: 1, 100}
  ```

  ```javascript Repeat text theme={null}
  {repeat: 🎉, 5}
  ```
</CodeGroup>

`random` aliases: `rand`, `r`, `choice`. `rng` aliases: `randint`, `ri`, `random.randint`. `repeat` aliases: `mul`, `multiply`.

Randomness is evaluated **each time the message is sent**, so a welcome message with `{random: ...}` in it varies per member — which is the point.

```javascript theme={null}
!welcome add #general {content: {random: welcome, glad you made it, hey} {user.mention}} {color: dominant}
```

## Boolean helpers

Two pipes exist purely to feed `{if:}`:

| Pipe                 | Aliases            | Result           |
| -------------------- | ------------------ | ---------------- |
| `\|contains: needle` | `has`              | `true` or empty  |
| `\|not`              | `negate`, `invert` | Flips truthiness |

```javascript theme={null}
{if: {user.roles|contains: Booster} && thanks for boosting && }
{if: {guild.vanity|not} && set a vanity url && }
```

## Worked example

A level-up message that reads differently at milestones, formats numbers properly and picks a random opener:

```javascript theme={null}
!level message {content: {user.mention}} {title: {random: level up!, ding!, nice one}} {description: you're now level **{user.level}**{if: {user.level}>=50 &&  — that's genuinely impressive && }.

{user.required_xp|comma} xp until level {user.next_level}.} {color: dominant} {footer: {user.join_position|ordinal} member of {guild.name}}
```

<Warning>
  Operators are resolved **after** variables. So `{if: {user.level}>=10 && ...}` works because `{user.level}` has already become a number by the time the `if` runs. If a variable doesn't exist, its raw text is what gets compared — which is usually falsy, but worth knowing when a condition behaves oddly.
</Warning>

## Nesting

Operators nest freely, and `&&` is only treated as a separator at the top level — so an inner operator's own `&&` won't break the outer one.

```javascript theme={null}
{if: {guild.boosts}>0 && {random: thanks!, appreciated!} — {guild.boosts} {guild.boosts|plural: boost, boosts} && no boosts yet}
```

Keep it readable. If a script starts looking like code, it's usually a sign the message wants splitting into two.
