Skip to content

Commit

Permalink
Support for '@' expressions (#318)
Browse files Browse the repository at this point in the history
* parse special expressions

* normalize and validate

* added '@' expressions to  Readme

* catch empty expression

* added tests

* Tweak Feature item for nicknames

---------

Co-authored-by: Brady Holt <[email protected]>
  • Loading branch information
HB9HIL and bradymholt authored May 6, 2024
1 parent 98c68af commit d546f8a
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 2 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ This library was ported from the original C# implementation called [cron-express
- Zero dependencies
- Supports all cron expression special characters including * / , - ? L W, #
- Supports 5, 6 (w/ seconds or year), or 7 (w/ seconds and year) part cron expressions
- Supports [Quartz Job Scheduler](http://www.quartz-scheduler.org/) cron expressions
- [Quartz Job Scheduler](http://www.quartz-scheduler.org/) cron expressions are supported
- Supports time specification _nicknames_ (@yearly, @annually, @monthly, @weekly, @daily)
- i18n support with 30+ languages

## Demo
Expand Down Expand Up @@ -90,6 +91,10 @@ cronstrue.toString("* * * ? * 2-6/2", { dayOfWeekStartIndexZero: false });

cronstrue.toString("* * * 6-8 *", { monthStartIndexZero: true });
> "Every minute, July through September"

cronstrue.toString("@monthly");
> "At 12:00 AM, on day 1 of the month"

```

For more usage examples, including a demonstration of how cRonstrue can handle some very complex cron expressions, you can [reference the unit tests](https://github.com/bradymholt/cRonstrue/blob/main/test/cronstrue.ts).
Expand Down
32 changes: 31 additions & 1 deletion src/cronParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,43 @@ export class CronParser {
* @returns {string[]}
*/
parse(): string[] {
let parsed = this.extractParts(this.expression);
let parsed: string[];

var expression = this.expression ?? '';

if (expression.startsWith('@')) {
var special = this.parseSpecial(this.expression);
parsed = this.extractParts(special);

} else {
parsed = this.extractParts(this.expression);
}

this.normalize(parsed);
this.validate(parsed);

return parsed;
}

parseSpecial(expression: string): string {
const specialExpressions: { [key: string]: string } = {
'@yearly': '0 0 1 1 *',
'@annually': '0 0 1 1 *',
'@monthly': '0 0 1 * *',
'@weekly': '0 0 * * 0',
'@daily': '0 0 * * *',
'@midnight': '0 0 * * *',
'@hourly': '0 * * * *'
};

const special = specialExpressions[expression];
if (!special) {
throw new Error('Unknown special expression.');
}

return special;
}

protected extractParts(expression: string) {
if (!this.expression) {
throw new Error("cron expression is empty");
Expand Down
4 changes: 4 additions & 0 deletions test/cronParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,9 @@ describe("CronParser", function () {
it("dayOfWeek dangling comma", function () {
assert.equal(new CronParser("*/5 * * * * ,2").parse()[5], "2");
});

it("should parse cron @ expression", function () {
assert.equal(new CronParser("@weekly").parse().length, 7);
});
});
});
30 changes: 30 additions & 0 deletions test/cronstrue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,36 @@ describe("Cronstrue", function () {
});
});

describe("@ expressions", function () {
it("@yearly", function () {
assert.equal(cronstrue.toString(this.test?.title as string), "At 12:00 AM, on day 1 of the month, only in January");
});

it("@annually", function () {
assert.equal(cronstrue.toString(this.test?.title as string), "At 12:00 AM, on day 1 of the month, only in January");
});

it("@monthly", function () {
assert.equal(cronstrue.toString(this.test?.title as string), "At 12:00 AM, on day 1 of the month");
});

it("@weekly", function () {
assert.equal(cronstrue.toString(this.test?.title as string), "At 12:00 AM, only on Sunday");
});

it("@daily", function () {
assert.equal(cronstrue.toString(this.test?.title as string), "At 12:00 AM");
});

it("@midnight", function () {
assert.equal(cronstrue.toString(this.test?.title as string), "At 12:00 AM");
});

it("@hourly", function () {
assert.equal(cronstrue.toString(this.test?.title as string), "Every hour");
});
});

describe("verbose", function () {
it("30 4 1 * *", function () {
assert.equal(cronstrue.toString(this.test?.title as string, { verbose: true }), "At 04:30 AM, on day 1 of the month");
Expand Down

0 comments on commit d546f8a

Please sign in to comment.