Skip to content

Commit 79df5a3

Browse files
authored
ci: update golangci-lint configuration (#155)
1 parent 49e33c3 commit 79df5a3

File tree

7 files changed

+90
-77
lines changed

7 files changed

+90
-77
lines changed

.github/workflows/golangci-lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ jobs:
2929
- name: Run golangci-lint
3030
uses: golangci/golangci-lint-action@v6
3131
with:
32-
version: v1.61.0
32+
version: v1.63.4

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ linters:
2323
- misspell
2424
- nolintlint
2525
- prealloc
26+
- reassign
2627
- revive
2728
- staticcheck
2829
- stylecheck

internal/csm/common_node.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ type CommonNode struct {
99

1010
var _ csmNode = (*CommonNode)(nil)
1111

12-
func NewCommonNode(value, min, max int, values []int) *CommonNode {
13-
return &CommonNode{value, min, max, values}
12+
func NewCommonNode(value, lowerBound, upperBound int, values []int) *CommonNode {
13+
return &CommonNode{value, lowerBound, upperBound, values}
1414
}
1515

1616
func (n *CommonNode) Value() int {

internal/csm/day_node.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,21 @@ type DayNode struct {
1717

1818
var _ csmNode = (*DayNode)(nil)
1919

20-
func NewMonthDayNode(value, min, max, n int, dayOfMonthValues []int, month, year csmNode) *DayNode {
20+
func NewMonthDayNode(value, lowerBound, upperBound, n int, dayOfMonthValues []int,
21+
month, year csmNode) *DayNode {
2122
return &DayNode{
22-
c: CommonNode{value, min, max, dayOfMonthValues},
23+
c: CommonNode{value, lowerBound, upperBound, dayOfMonthValues},
2324
weekdayValues: make([]int, 0),
2425
n: n,
2526
month: month,
2627
year: year,
2728
}
2829
}
2930

30-
func NewWeekDayNode(value, min, max, n int, dayOfWeekValues []int, month, year csmNode) *DayNode {
31+
func NewWeekDayNode(value, lowerBound, upperBound, n int, dayOfWeekValues []int,
32+
month, year csmNode) *DayNode {
3133
return &DayNode{
32-
c: CommonNode{value, min, max, make([]int, 0)},
34+
c: CommonNode{value, lowerBound, upperBound, make([]int, 0)},
3335
weekdayValues: dayOfWeekValues,
3436
n: n,
3537
month: month,

quartz/cron.go

Lines changed: 56 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func newCronFieldN(values []int, n int) *cronField {
111111
return &cronField{values: values, n: n}
112112
}
113113

114-
// add increments each element of the underlying values array by the given delta.
114+
// add increments each element of the underlying values slice by the given delta.
115115
func (cf *cronField) add(delta int) {
116116
for i := range cf.values {
117117
cf.values[i] += delta
@@ -123,6 +123,12 @@ func (cf *cronField) String() string {
123123
return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(cf.values)), ","), "[]")
124124
}
125125

126+
// boundary represents inclusive range boundaries for cron field values.
127+
type boundary struct {
128+
lower int
129+
upper int
130+
}
131+
126132
var (
127133
months = []string{"0", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}
128134
days = []string{"0", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}
@@ -181,98 +187,83 @@ func buildCronField(tokens []string) ([]*cronField, error) {
181187
var err error
182188
fields := make([]*cronField, 7)
183189
// second field
184-
fields[0], err = parseField(tokens[0], 0, 59)
190+
fields[0], err = parseField(tokens[0], boundary{0, 59}, nil)
185191
if err != nil {
186192
return nil, err
187193
}
188194
// minute field
189-
fields[1], err = parseField(tokens[1], 0, 59)
195+
fields[1], err = parseField(tokens[1], boundary{0, 59}, nil)
190196
if err != nil {
191197
return nil, err
192198
}
193199
// hour field
194-
fields[2], err = parseField(tokens[2], 0, 23)
200+
fields[2], err = parseField(tokens[2], boundary{0, 23}, nil)
195201
if err != nil {
196202
return nil, err
197203
}
198204
// day-of-month field
199-
fields[3], err = parseDayOfMonthField(tokens[3], 1, 31)
205+
fields[3], err = parseDayOfMonthField(tokens[3], boundary{1, 31}, nil)
200206
if err != nil {
201207
return nil, err
202208
}
203209
// month field
204-
fields[4], err = parseField(tokens[4], 1, 12, months)
210+
fields[4], err = parseField(tokens[4], boundary{1, 12}, months)
205211
if err != nil {
206212
return nil, err
207213
}
208214
// day-of-week field
209-
fields[5], err = parseDayOfWeekField(tokens[5], 1, 7, days)
215+
fields[5], err = parseDayOfWeekField(tokens[5], boundary{1, 7}, days)
210216
if err != nil {
211217
return nil, err
212218
}
213219
fields[5].add(-1)
214220
// year field
215-
fields[6], err = parseField(tokens[6], 1970, 1970*2)
221+
fields[6], err = parseField(tokens[6], boundary{1970, 1970 * 2}, nil)
216222
if err != nil {
217223
return nil, err
218224
}
219225

220226
return fields, nil
221227
}
222228

223-
func parseField(field string, min, max int, translate ...[]string) (*cronField, error) {
224-
var glossary []string
225-
if len(translate) > 0 {
226-
glossary = translate[0]
227-
}
229+
func parseField(field string, bound boundary, names []string) (*cronField, error) {
228230
// any value
229231
if field == "*" || field == "?" {
230232
return newCronField([]int{}), nil
231233
}
232-
// simple value
233-
i, err := strconv.Atoi(field)
234-
if err == nil {
235-
if inScope(i, min, max) {
236-
return newCronField([]int{i}), nil
237-
}
238-
return nil, newInvalidCronFieldError("simple", field)
239-
}
240234
// list values
241235
if strings.ContainsRune(field, listRune) {
242-
return parseListField(field, min, max, glossary)
236+
return parseListField(field, bound, names)
243237
}
244238
// step values
245239
if strings.ContainsRune(field, stepRune) {
246-
return parseStepField(field, min, max, glossary)
240+
return parseStepField(field, bound, names)
247241
}
248242
// range values
249243
if strings.ContainsRune(field, rangeRune) {
250-
return parseRangeField(field, min, max, glossary)
244+
return parseRangeField(field, bound, names)
251245
}
252-
// simple literal value
253-
if glossary != nil {
254-
intVal, err := translateLiteral(glossary, field)
255-
if err != nil {
256-
return nil, err
257-
}
258-
if inScope(intVal, min, max) {
259-
return newCronField([]int{intVal}), nil
260-
}
261-
return nil, newInvalidCronFieldError("literal", field)
246+
// simple value
247+
numeric, err := normalize(field, names)
248+
if err != nil {
249+
return nil, err
250+
}
251+
if inScope(numeric, bound.lower, bound.upper) {
252+
return newCronField([]int{numeric}), nil
262253
}
263254

264-
return nil, newCronParseError(fmt.Sprintf("invalid field %s", field))
255+
return nil, newInvalidCronFieldError("numeric", field)
265256
}
266257

267258
var (
268259
cronLastMonthDayRegex = regexp.MustCompile(`^L(-[0-9]+)?$`)
269260
cronWeekdayRegex = regexp.MustCompile(`^[0-9]+W$`)
270261

271-
cronLastWeekdayRegex = regexp.MustCompile(`^[0-9]*L$`)
272-
cronHashRegex = regexp.MustCompile(`^[0-9]+#[0-9]+$`)
262+
cronLastWeekdayRegex = regexp.MustCompile(`^[a-zA-Z0-9]*L$`)
263+
cronHashRegex = regexp.MustCompile(`^[a-zA-Z0-9]+#[0-9]+$`)
273264
)
274265

275-
func parseDayOfMonthField(field string, min, max int, translate ...[]string) (*cronField, error) {
266+
func parseDayOfMonthField(field string, bound boundary, names []string) (*cronField, error) {
276267
if strings.ContainsRune(field, lastRune) && cronLastMonthDayRegex.MatchString(field) {
277268
if field == string(lastRune) {
278269
return newCronFieldN([]int{}, cronLastDayOfMonthN), nil
@@ -282,7 +273,7 @@ func parseDayOfMonthField(field string, min, max int, translate ...[]string) (*c
282273
return nil, newInvalidCronFieldError("last", field)
283274
}
284275
n, err := strconv.Atoi(values[1])
285-
if err != nil || !inScope(n, 1, 30) {
276+
if err != nil || !inScope(n, bound.lower, bound.upper) {
286277
return nil, newInvalidCronFieldError("last", field)
287278
}
288279
return newCronFieldN([]int{}, -n), nil
@@ -299,24 +290,24 @@ func parseDayOfMonthField(field string, min, max int, translate ...[]string) (*c
299290
return nil, newInvalidCronFieldError("weekday", field)
300291
}
301292
dayOfMonth, err := strconv.Atoi(day)
302-
if err != nil || !inScope(dayOfMonth, min, max) {
293+
if err != nil || !inScope(dayOfMonth, bound.lower, bound.upper) {
303294
return nil, newInvalidCronFieldError("weekday", field)
304295
}
305296
return newCronFieldN([]int{dayOfMonth}, cronWeekdayN), nil
306297
}
307298
}
308299

309-
return parseField(field, min, max, translate...)
300+
return parseField(field, bound, names)
310301
}
311302

312-
func parseDayOfWeekField(field string, min, max int, translate ...[]string) (*cronField, error) {
303+
func parseDayOfWeekField(field string, bound boundary, names []string) (*cronField, error) {
313304
if strings.ContainsRune(field, lastRune) && cronLastWeekdayRegex.MatchString(field) {
314305
day := strings.TrimSuffix(field, string(lastRune))
315306
if day == "" { // Saturday
316307
return newCronFieldN([]int{7}, -1), nil
317308
}
318-
dayOfWeek, err := strconv.Atoi(day)
319-
if err != nil || !inScope(dayOfWeek, min, max) {
309+
dayOfWeek, err := normalize(day, names)
310+
if err != nil || !inScope(dayOfWeek, bound.lower, bound.upper) {
320311
return nil, newInvalidCronFieldError("last", field)
321312
}
322313
return newCronFieldN([]int{dayOfWeek}, -1), nil
@@ -327,8 +318,8 @@ func parseDayOfWeekField(field string, min, max int, translate ...[]string) (*cr
327318
if len(values) != 2 {
328319
return nil, newInvalidCronFieldError("hash", field)
329320
}
330-
dayOfWeek, err := strconv.Atoi(values[0])
331-
if err != nil || !inScope(dayOfWeek, min, max) {
321+
dayOfWeek, err := normalize(values[0], names)
322+
if err != nil || !inScope(dayOfWeek, bound.lower, bound.upper) {
332323
return nil, newInvalidCronFieldError("hash", field)
333324
}
334325
n, err := strconv.Atoi(values[1])
@@ -338,26 +329,26 @@ func parseDayOfWeekField(field string, min, max int, translate ...[]string) (*cr
338329
return newCronFieldN([]int{dayOfWeek}, n), nil
339330
}
340331

341-
return parseField(field, min, max, translate...)
332+
return parseField(field, bound, names)
342333
}
343334

344-
func parseListField(field string, min, max int, glossary []string) (*cronField, error) {
335+
func parseListField(field string, bound boundary, names []string) (*cronField, error) {
345336
t := strings.Split(field, string(listRune))
346337
values, stepValues := extractStepValues(t)
347338
values, rangeValues := extractRangeValues(values)
348-
listValues, err := translateLiterals(glossary, values)
339+
listValues, err := translateLiterals(names, values)
349340
if err != nil {
350341
return nil, err
351342
}
352343
for _, v := range stepValues {
353-
stepField, err := parseStepField(v, min, max, glossary)
344+
stepField, err := parseStepField(v, bound, names)
354345
if err != nil {
355346
return nil, err
356347
}
357348
listValues = append(listValues, stepField.values...)
358349
}
359350
for _, v := range rangeValues {
360-
rangeField, err := parseRangeField(v, min, max, glossary)
351+
rangeField, err := parseRangeField(v, bound, names)
361352
if err != nil {
362353
return nil, err
363354
}
@@ -368,20 +359,20 @@ func parseListField(field string, min, max int, glossary []string) (*cronField,
368359
return newCronField(listValues), nil
369360
}
370361

371-
func parseRangeField(field string, min, max int, glossary []string) (*cronField, error) {
362+
func parseRangeField(field string, bound boundary, names []string) (*cronField, error) {
372363
t := strings.Split(field, string(rangeRune))
373364
if len(t) != 2 {
374365
return nil, newInvalidCronFieldError("range", field)
375366
}
376-
from, err := normalize(t[0], glossary)
367+
from, err := normalize(t[0], names)
377368
if err != nil {
378369
return nil, err
379370
}
380-
to, err := normalize(t[1], glossary)
371+
to, err := normalize(t[1], names)
381372
if err != nil {
382373
return nil, err
383374
}
384-
if !inScope(from, min, max) || !inScope(to, min, max) {
375+
if !inScope(from, bound.lower, bound.upper) || !inScope(to, bound.lower, bound.upper) {
385376
return nil, newInvalidCronFieldError("range", field)
386377
}
387378
rangeValues, err := fillRangeValues(from, to)
@@ -392,45 +383,48 @@ func parseRangeField(field string, min, max int, glossary []string) (*cronField,
392383
return newCronField(rangeValues), nil
393384
}
394385

395-
func parseStepField(field string, min, max int, glossary []string) (*cronField, error) {
386+
func parseStepField(field string, bound boundary, names []string) (*cronField, error) {
396387
t := strings.Split(field, string(stepRune))
397388
if len(t) != 2 {
398389
return nil, newInvalidCronFieldError("step", field)
399390
}
400-
to := max
391+
to := bound.upper
401392
var (
402393
from int
403394
err error
404395
)
405396
switch {
406397
case t[0] == "*":
407-
from = min
398+
from = bound.lower
408399
case strings.ContainsRune(t[0], rangeRune):
409400
trange := strings.Split(t[0], string(rangeRune))
410401
if len(trange) != 2 {
411402
return nil, newInvalidCronFieldError("step", field)
412403
}
413-
from, err = normalize(trange[0], glossary)
404+
from, err = normalize(trange[0], names)
414405
if err != nil {
415406
return nil, err
416407
}
417-
to, err = normalize(trange[1], glossary)
408+
to, err = normalize(trange[1], names)
418409
if err != nil {
419410
return nil, err
420411
}
421412
default:
422-
from, err = normalize(t[0], glossary)
413+
from, err = normalize(t[0], names)
423414
if err != nil {
424415
return nil, err
425416
}
426417
}
418+
427419
step, err := strconv.Atoi(t[1])
428420
if err != nil {
429421
return nil, newInvalidCronFieldError("step", field)
430422
}
431-
if !inScope(from, min, max) || !inScope(step, 1, max) || !inScope(to, min, max) {
423+
if !inScope(from, bound.lower, bound.upper) || !inScope(step, 1, bound.upper) ||
424+
!inScope(to, bound.lower, bound.upper) {
432425
return nil, newInvalidCronFieldError("step", field)
433426
}
427+
434428
stepValues, err := fillStepValues(from, step, to)
435429
if err != nil {
436430
return nil, err

quartz/cron_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,18 +297,34 @@ func TestCronExpressionDayOfWeek(t *testing.T) {
297297
expression: "0 15 10 ? * 5L",
298298
expected: "Thu Oct 31 10:15:00 2024",
299299
},
300+
{
301+
expression: "0 15 10 ? * THUL",
302+
expected: "Thu Oct 31 10:15:00 2024",
303+
},
300304
{
301305
expression: "0 15 10 ? * 2#1",
302306
expected: "Mon Nov 4 10:15:00 2024",
303307
},
308+
{
309+
expression: "0 15 10 ? * MON#1",
310+
expected: "Mon Nov 4 10:15:00 2024",
311+
},
304312
{
305313
expression: "0 15 10 ? * 3#5",
306314
expected: "Tue Mar 31 10:15:00 2026",
307315
},
316+
{
317+
expression: "0 15 10 ? * Tue#5",
318+
expected: "Tue Mar 31 10:15:00 2026",
319+
},
308320
{
309321
expression: "0 15 10 ? * 7#5",
310322
expected: "Sat May 30 10:15:00 2026",
311323
},
324+
{
325+
expression: "0 15 10 ? * sat#5",
326+
expected: "Sat May 30 10:15:00 2026",
327+
},
312328
}
313329

314330
prev := time.Date(2024, 1, 1, 12, 00, 00, 00, time.UTC).UnixNano()

0 commit comments

Comments
 (0)