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

# Logic & comparisons

> Conditional operators and comparison logic in penscript

Conditional logic is the foundation of dynamic behavior in penscript. These operators control which content appears, which rules apply, and which branches a workflow follows.

## Conditional: `:if`

Evaluates a condition and returns one of two branches.

```json theme={null}
{
  ":if": "{data.is_active}",
  ":then": "Active",
  ":else": "Inactive"
}

// Scope: { "data": { "is_active": true } }
// Result: "Active"
```

The condition can be a variable, an inline expression, or another operator:

```json theme={null}
{
  ":if": { ":cmp": "{data.count}", ":gt": 0 },
  ":then": "There are {data.count} items",
  ":else": "No items"
}

// Scope: { "data": { "count": 3 } }
// Result: "There are 3 items"
```

Multiple conditions can be passed as an array — all must be true for the `:then` branch:

```json theme={null}
{
  ":if": [
    { ":cmp": "{data.age}", ":gte": 18 },
    { ":in": ["{data.country}", ["BE", "FR", "LU"]] }
  ],
  ":then": "Eligible",
  ":else": "Not eligible"
}
```

The return values can be any type — strings, numbers, objects, arrays, or nested operators:

```json theme={null}
{
  ":if": "{data.premium_member}",
  ":then": ["feature_a", "feature_b", "feature_c"],
  ":else": "{data.default_features}"
}

// Scope: { "data": { "premium_member": true } }
// Result: ["feature_a", "feature_b", "feature_c"]
```

## Switch: `:case`

Matches a value against a list of options. Returns the result for the first match, or the `:else` fallback if nothing matches.

```json theme={null}
{
  ":case": "{data.status}",
  ":when": [
    ["pending", "Status is pending"],
    ["done", "Status is done"],
    ["error", "Status is error"]
  ],
  ":else": "Status is unknown"
}

// Scope: { "data": { "status": "done" } }
// Result: "Status is done"
```

Cleaner than nested `:if` chains when you have multiple known values to match against.

## Comparison: `:cmp`

Compares a value against one or more thresholds. Returns `true` or `false`.

**Supported modifiers:**

| Modifier       | Meaning                  |
| -------------- | ------------------------ |
| `:eq`          | Equal to                 |
| `:neq`         | Not equal to             |
| `:gt`          | Greater than             |
| `:gte` / `:ge` | Greater than or equal to |
| `:lt`          | Less than                |
| `:lte` / `:le` | Less than or equal to    |

**Single threshold:**

```json theme={null}
{ ":cmp": "{data.count}", ":gt": 0 }
// Scope: { "data": { "count": 5 } }
// Result: true

{ ":cmp": "{data.count}", ":eq": 3 }
// Scope: { "data": { "count": 5 } }
// Result: false
```

**Multiple thresholds** — all must be satisfied:

```json theme={null}
{ ":cmp": "{data.count}", ":gt": 0, ":lt": 10 }
// Scope: { "data": { "count": 5 } }
// Result: true   (5 > 0 AND 5 < 10)

{ ":cmp": "{data.age}", ":gte": 18, ":lte": 65 }
// Range check: is the value between 18 and 65 inclusive?
```

Most commonly used as the condition inside `:if`:

```json theme={null}
{
  ":if": { ":cmp": "{data.score}", ":gte": 50 },
  ":then": "Passed",
  ":else": "Failed"
}
```

Works with numbers, dates, and values produced by pipes like `| age`.

## Equality: `:eq`

Tests whether all values in a list are equal to each other.

```json theme={null}
{ ":eq": ["{data.a}", "{data.b}", 42] }

// Scope: { "data": { "a": 42, "b": 42 } }
// Result: true

{ ":eq": [1, 2] }
// Result: false
```

Useful for validating that multiple fields contain the same value (e.g., password confirmation, duplicate detection).

## Uniqueness: `:distinct`

Returns `true` if all values in the list are different from each other.

```json theme={null}
{ ":distinct": [1, 2, 3] }
// Result: true

{ ":distinct": [1, 1, 2] }
// Result: false
```

Useful for dynamic validation — ensuring all generated fields have unique values:

```json theme={null}
{
  "required": {
    ":distinct": ["{@index}", { ":sum": ["{@array.length}", -1] }]
  }
}
```

## Membership: `:in` / `:nin`

Tests whether a value exists (or doesn't exist) in a given list.

**`:in`** — value is in the list:

```json theme={null}
{ ":in": ["{data.role}", ["admin", "manager"]] }

// Scope: { "data": { "role": "admin" } }
// Result: true
```

**`:nin`** — value is NOT in the list:

```json theme={null}
{ ":nin": ["{data.role}", ["banned", "suspended"]] }

// Scope: { "data": { "role": "user" } }
// Result: true
```

Works naturally with `:if` for access control and routing:

```json theme={null}
{
  ":if": { ":in": ["{data.country}", ["FR", "BE", "CH"]] },
  ":then": "French-speaking region",
  ":else": "Other region"
}

// Scope: { "data": { "country": "BE" } }
// Result: "French-speaking region"
```

## Boolean Helpers

### `:not`

Negates a boolean value.

```json theme={null}
{ ":not": "{data.is_blocked}" }

// Scope: { "data": { "is_blocked": true } }
// Result: false
```

### `:every`

Returns `true` if every item in an array satisfies a condition. The condition is evaluated for each item with `@item` as the current element.

```json theme={null}
{
  ":every": [
    "{data.scores}",
    { ":cmp": "@item", ":ge": 10 }
  ]
}

// Scope: { "data": { "scores": [10, 12, 15] } }
// Result: true   (all scores ≥ 10)
```

### `:some`

Returns `true` if at least one item satisfies a condition.

```json theme={null}
{
  ":some": [
    "{data.users}",
    { ":eq": ["@item.role", "admin"] }
  ]
}

// Scope: {
//   "data": {
//     "users": [
//       { "id": 1, "role": "user" },
//       { "id": 2, "role": "admin" }
//     ]
//   }
// }
// Result: true   (at least one admin exists)
```

## Logical Constants

Explicit boolean and null values for use in expressions where you need to return a fixed value.

```json theme={null}
{ ":true": null }       // → true
{ ":false": null }      // → false
{ ":null": null }       // → null
{ ":undefined": null }  // → undefined
```

These are typically used inside `:if` branches or `:map` transformations when you need to produce a specific constant value programmatically.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Variables & scope" icon="brackets-curly" href="/penscript/variables">
    Variable references and scope
  </Card>

  <Card title="Numbers & calculations" icon="calculator" href="/penscript/numbers">
    Arithmetic and formatting
  </Card>

  <Card title="Loops & arrays" icon="repeat" href="/penscript/arrays">
    Working with collections
  </Card>

  <Card title="How penscript works" icon="gears" href="/penscript/how_it_works">
    Expression modes and composition
  </Card>
</CardGroup>
