lopata 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lopata",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -55,6 +55,46 @@ const SPECIAL_DESCRIPTIONS: Record<string, string> = {
55
55
  '@annually': 'First day of every year',
56
56
  }
57
57
 
58
+ const DOW_NAMES: Record<string, string> = {
59
+ '0': 'Sunday',
60
+ '1': 'Monday',
61
+ '2': 'Tuesday',
62
+ '3': 'Wednesday',
63
+ '4': 'Thursday',
64
+ '5': 'Friday',
65
+ '6': 'Saturday',
66
+ '7': 'Sunday',
67
+ }
68
+ const MONTH_NAMES: Record<string, string> = {
69
+ '1': 'January',
70
+ '2': 'February',
71
+ '3': 'March',
72
+ '4': 'April',
73
+ '5': 'May',
74
+ '6': 'June',
75
+ '7': 'July',
76
+ '8': 'August',
77
+ '9': 'September',
78
+ '10': 'October',
79
+ '11': 'November',
80
+ '12': 'December',
81
+ }
82
+
83
+ function formatTime(hour: string, minute: string): string {
84
+ return `${hour.padStart(2, '0')}:${minute.padStart(2, '0')}`
85
+ }
86
+
87
+ function formatDow(dow: string): string {
88
+ if (dow === '1-5') return 'weekdays'
89
+ if (dow === '0,6' || dow === '6,0') return 'weekends'
90
+ const names = dow.split(',').map(d => DOW_NAMES[d] ?? d)
91
+ return names.join(', ')
92
+ }
93
+
94
+ function formatMonth(month: string): string {
95
+ return month.split(',').map(m => MONTH_NAMES[m] ?? m).join(', ')
96
+ }
97
+
58
98
  function cronToHuman(expression: string): string {
59
99
  const trimmed = expression.trim()
60
100
  const special = SPECIAL_DESCRIPTIONS[trimmed.toLowerCase()]
@@ -64,29 +104,56 @@ function cronToHuman(expression: string): string {
64
104
  if (parts.length !== 5) return expression
65
105
 
66
106
  const [minute, hour, dom, month, dow] = parts
67
- const segments: string[] = []
68
107
 
69
108
  if (minute === '*' && hour === '*' && dom === '*' && month === '*' && dow === '*') {
70
109
  return 'Every minute'
71
110
  }
72
111
 
73
- // Detect common patterns
112
+ // Step patterns: */N
74
113
  if (minute!.startsWith('*/')) {
75
- return `Every ${minute!.slice(2)} minutes`
114
+ const n = minute!.slice(2)
115
+ return n === '1' ? 'Every minute' : `Every ${n} minutes`
76
116
  }
77
117
  if (hour!.startsWith('*/') && minute === '0') {
78
- return `Every ${hour!.slice(2)} hours`
118
+ const n = hour!.slice(2)
119
+ return n === '1' ? 'Every hour' : `Every ${n} hours`
79
120
  }
80
121
 
122
+ const allDates = dom === '*' && month === '*' && dow === '*'
123
+
124
+ // minute=0, hour=* → "Every hour"
125
+ if (minute === '0' && hour === '*' && allDates) {
126
+ return 'Every hour'
127
+ }
128
+
129
+ // minute=N, hour=* → "Every hour at minute N"
130
+ if (minute !== '*' && hour === '*' && allDates) {
131
+ return `Every hour at minute ${minute}`
132
+ }
133
+
134
+ // Build description from time + date constraints
135
+ const segments: string[] = []
136
+
137
+ // Time part
81
138
  if (hour !== '*' && minute !== '*') {
82
- segments.push(`At ${hour!.padStart(2, '0')}:${minute!.padStart(2, '0')}`)
83
- } else if (minute !== '*') {
139
+ segments.push(`At ${formatTime(hour!, minute!)}`)
140
+ } else if (minute !== '*' && hour === '*') {
84
141
  segments.push(`At minute ${minute}`)
142
+ } else if (hour !== '*' && minute === '*') {
143
+ segments.push(`Every minute of hour ${hour}`)
144
+ }
145
+
146
+ // Frequency context
147
+ if (hour !== '*' && minute !== '*') {
148
+ if (dom === '*' && month === '*' && dow === '*') {
149
+ segments.unshift('Every day')
150
+ }
85
151
  }
86
152
 
87
- if (dow !== '*') segments.push(`on day-of-week ${dow}`)
88
- if (dom !== '*') segments.push(`on day ${dom}`)
89
- if (month !== '*') segments.push(`in month ${month}`)
153
+ // Date constraints
154
+ if (dow !== '*') segments.push(`on ${formatDow(dow!)}`)
155
+ if (dom !== '*') segments.push(`on day ${dom} of the month`)
156
+ if (month !== '*') segments.push(`in ${formatMonth(month!)}`)
90
157
 
91
158
  return segments.join(' ') || expression
92
159
  }