This is PEG grammar to parse time syntax in crontab.
You can try it by copy-paste parser.js to PEGjs online editor.
Then put test input value to any valid crontab time. For example:
* 1 1-9 1,2 SAT,SUN
This is PEG grammar to parse time syntax in crontab.
You can try it by copy-paste parser.js to PEGjs online editor.
Then put test input value to any valid crontab time. For example:
* 1 1-9 1,2 SAT,SUN
| { | |
| function type(type, value, text) { | |
| return {type, value, text} | |
| } | |
| function flatten(values) { | |
| return [values[0]].concat(values[1].map(v => v[1])) | |
| } | |
| function resolve(result) { | |
| const resolveString = (val) => type("ws", val, val) | |
| const resolveArray = (val) => type("group", val, val.map(v => v.text).join(',')) | |
| let pos = 0 | |
| return result | |
| .map(val => typeof val == "string" ? resolveString(val) : resolveArray(val)) | |
| .map(val => { | |
| const cursor = [pos, pos + val.text.length - 1] | |
| pos += val.text.length | |
| return {...val, cursor} | |
| }) | |
| } | |
| } | |
| start = result:(minute _ hour _ date _ month _ day) { | |
| return resolve(result) | |
| } | |
| minute = common | |
| hour = common | |
| date = common | |
| month = v:(monthTypes ("," monthTypes)*) { | |
| return flatten(v) | |
| } | |
| day = v:(dayTypes ("," dayTypes)*) { | |
| return flatten(v) | |
| } | |
| common = v:(commonTypes ("," commonTypes)*) { | |
| return flatten(v) | |
| } | |
| commonTypes = range / number / any | |
| monthTypes = commonTypes / altMonths | |
| dayTypes = commonTypes / altDays | |
| int = n:([0-9]+) { | |
| return parseInt(n.join('')) | |
| } | |
| days = "MON" / "TUE" / "WED" / "THU" / "FRI" / "SAT" / "SUN" | |
| months = "JAN" / "FEB" / "MAR" / "APR" / "MAY" / "JUN" / "JUL" / "AUG" / "SEP" / "OCT" / "NOV" / "DEC" | |
| number = v:(int step?) { | |
| let text = `${v[0]}` | |
| if (v[1]) text += `/${v[1]}` | |
| return type("number", {number: v[0], step: v[1]}, text) | |
| } | |
| range = v:(int "-" int step?) { | |
| let text = `${v[0]}-${v[2]}` | |
| if (v[3]) text += `/${v[3]}` | |
| return type("range", {from: v[0], to:v[2], step: v[3]}, text) | |
| } | |
| step = v:("/" int) { | |
| return v[1] | |
| } | |
| altDays = v:(days ("," days)*) { | |
| const value = [v[0]].concat(v[1].map(s => s[1])) | |
| return type("days", value, value.join(',')) | |
| } | |
| altMonths = v:(months ("," months)*) { | |
| const value = [v[0]].concat(v[1].map(s => s[1])) | |
| return type("months", value, value.join(',')) | |
| } | |
| any = "*" { | |
| return type("any", true, '*') | |
| } | |
| _ "whitespace" = ws:([ \t]*) { | |
| return ws.join('') | |
| } |