Skip to content

Expressions

The Expression system provides type-safe access to GitHub Actions ${{ }} expressions. Instead of writing raw strings, use the typed helpers for better IDE support and lint coverage.

expressions-usage.ts
import {
Expression,
github,
runner,
secrets,
steps,
always,
failure,
contains,
startsWith,
branch,
tag,
} from "@intentius/chant-lexicon-github";
// Combine expressions with logical operators
const isMainBranch = github.ref.eq("refs/heads/main");
const isPR = github.eventName.eq("pull_request");
const mainOrPR = isMainBranch.or(isPR);
// Condition helpers for job/step `if:` fields
const alwaysRun = always(); // ${{ always() }}
const onFailure = failure(); // ${{ failure() }}
// Function helpers
const hasLabel = contains(github.event, "bug");
const isRelease = startsWith(github.ref, "refs/tags/v");
// Convenience helpers
const onMain = branch("main"); // github.ref == 'refs/heads/main'
const onV1Tag = tag("v1"); // startsWith(github.ref, 'refs/tags/v1')
// Access secrets, step outputs, and runner context
const token = secrets("NPM_TOKEN");
const buildOutput = steps("build").outputs("artifact-path");
const osType = runner.os; // ${{ runner.os }}

The Expression class wraps a raw expression string and provides operator methods:

MethodExampleResult
.and(other)github.ref.eq("refs/heads/main").and(isPR)${{ github.ref == 'refs/heads/main' && ... }}
.or(other)isMain.or(isDev)${{ ... || ... }}
.not()isPR.not()${{ !(...) }}
.eq(value)github.ref.eq("refs/heads/main")${{ github.ref == 'refs/heads/main' }}
.ne(value)github.eventName.ne("schedule")${{ github.event_name != 'schedule' }}

The github and runner objects provide typed access to context properties:

import { github, runner } from "@intentius/chant-lexicon-github";
github.ref // ${{ github.ref }}
github.sha // ${{ github.sha }}
github.actor // ${{ github.actor }}
runner.os // ${{ runner.os }}
runner.arch // ${{ runner.arch }}

See Variables for the full reference table.

Access dynamic context values — secrets, matrix, step outputs, job outputs, inputs, vars, env:

import { secrets, matrix, steps, needs, inputs, vars, env } from "@intentius/chant-lexicon-github";
secrets("NPM_TOKEN") // ${{ secrets.NPM_TOKEN }}
matrix("node-version") // ${{ matrix.node-version }}
steps("build").outputs("path") // ${{ steps.build.outputs.path }}
needs("build").outputs("version") // ${{ needs.build.outputs.version }}
inputs("environment") // ${{ inputs.environment }}
vars("API_URL") // ${{ vars.API_URL }}
env("NODE_ENV") // ${{ env.NODE_ENV }}

Status check functions for job and step if: fields:

FunctionExpressionDescription
always()${{ always() }}Always run, regardless of status
failure()${{ failure() }}Run only if a previous step failed
success()${{ success() }}Run only if all previous steps succeeded (default)
cancelled()${{ cancelled() }}Run only if the workflow was cancelled

Use them in if: conditions:

import { Job, Step, failure, always } from "@intentius/chant-lexicon-github";
export const test = new Job({
"runs-on": "ubuntu-latest",
steps: [
new Step({ name: "Test", run: "npm test" }),
new Step({
name: "Upload coverage",
if: always(),
run: "npx codecov",
}),
new Step({
name: "Notify failure",
if: failure(),
run: "curl -X POST $SLACK_WEBHOOK",
}),
],
});

Utility functions that produce expression strings:

FunctionExampleExpression
contains(haystack, needle)contains(github.event, "bug")${{ contains(github.event, 'bug') }}
startsWith(value, prefix)startsWith(github.ref, "refs/tags/")${{ startsWith(github.ref, 'refs/tags/') }}
toJSON(value)toJSON(github.event)${{ toJSON(github.event) }}
fromJSON(json)fromJSON(steps("meta").outputs("matrix"))${{ fromJSON(steps.meta.outputs.matrix) }}
format(template, ...args)format("v{0}.{1}", major, minor)${{ format('v{0}.{1}', ...) }}

Shorthand functions for common checks:

import { branch, tag } from "@intentius/chant-lexicon-github";
branch("main") // github.ref == 'refs/heads/main'
tag("v1") // startsWith(github.ref, 'refs/tags/v1')

These are useful in job if: conditions:

import { Job, Step, branch } from "@intentius/chant-lexicon-github";
export const deploy = new Job({
"runs-on": "ubuntu-latest",
if: branch("main"),
steps: [
new Step({ name: "Deploy", run: "npm run deploy" }),
],
});