Files
skills/docs/foundation/timing/cron/src/macros/macros.md
2026-05-29 08:20:56 +01:00

3.0 KiB

expandMacro

(no submodules)

Purpose

expandMacro recognises the conventional crontab macro shortcuts — @yearly/@annually, @monthly, @weekly, @daily/@midnight, @hourly — and expands them to their canonical 5-field cron equivalents. Macro expansion runs before field tokenization so the orchestrator only has to know about the structural 5/6/7-field shape. The function is deliberately conservative: it never silently rewrites non-macro input, and it explicitly rejects @reboot (which has no wall-clock semantics in a persistent process) with a typed CRON.UNSUPPORTED_SYNTAX error.

Features

  • Seven supported macros mapped to their POSIX-compatible 5-field expansions.
  • Case-insensitive (@DAILY and @daily are both accepted).
  • Whitespace-tolerant (leading and trailing whitespace stripped).
  • Returns null for non-macro inputs so the orchestrator can fall through to the standard field tokenizer.
  • Throws CronError(CRON.UNSUPPORTED_SYNTAX) for @reboot.
  • Throws CronError(CRON.INVALID_EXPRESSION) for unknown @ shortcuts.

Usage: Basic Example

import { expandMacro } from "@suaveplan/cron";

console.log(expandMacro("@daily"));   // "0 0 * * *"
console.log(expandMacro("@hourly"));  // "0 * * * *"
console.log(expandMacro("0 * * * *")); // null — not a macro

Usage: Advanced Example

import { expandMacro, CRON_CODES, CronError } from "@suaveplan/cron";

function canonicalise(input: string): string {
    try {
        return expandMacro(input) ?? input;
    } catch (err) {
        if (err instanceof CronError && err.code === CRON_CODES.UNSUPPORTED_SYNTAX) {
            // Persistent process — fall back to "every 24 hours".
            return "0 0 * * *";
        }
        throw err;
    }
}

console.log(canonicalise("@reboot")); // "0 0 * * *"
console.log(canonicalise("@weekly")); // "0 0 * * 0"

API Reference

  • expandMacro(expr: string): string | null — returns the 5-field expansion for a recognised macro, null for non-macro input, and throws CronError for unknown or unsupported @ shortcuts.
  • macroTable(): Readonly<Record<string, string>> — returns the frozen canonical lookup table used internally. Useful for documentation generation and admin UIs that render the supported macro set.

Implementation Notes

The macro table is Object.freezed at module load to guard against accidental mutation. Lookup is by lower-cased trimmed key so the function is O(1). @reboot is explicitly intercepted before the table lookup because its semantics differ fundamentally from the other macros — it fires at process start, not at a wall-clock instant, and is therefore not representable as a 5-field expansion. Returning null for non-macro input (rather than throwing) is deliberate so the orchestrator can unconditionally invoke expandMacro before its own field tokenizer without paying for exception construction on the hot path.