79 lines
3.0 KiB
Markdown
79 lines
3.0 KiB
Markdown
# expandMacro
|
|
|
|
<!-- begin:auto-docs -->
|
|
_(no submodules)_
|
|
<!-- end:auto-docs -->
|
|
## 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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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.freeze`d 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.
|