Skip to content

Commit

Permalink
fix: every n-th segments #49
Browse files Browse the repository at this point in the history
  • Loading branch information
abichinger committed Mar 16, 2024
1 parent 77b8ef0 commit fca6bba
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 20 deletions.
9 changes: 7 additions & 2 deletions core/src/__tests__/cron.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,22 @@ describe('segments', () => {
expect(cronToArray('*', r(1, 3))).toEqual([])
expect(cronToArray('1,3,5', r(0, 24))).toEqual([1, 3, 5])
expect(cronToArray('*/5', r(0, 11))).toEqual([0, 5, 10])
expect(cronToArray('*/5', r(1, 11))).toEqual([5, 10])
expect(cronToArray('*/5', r(1, 11))).toEqual([1, 6, 11])
expect(cronToArray('10-15', r(0, 59))).toEqual([10, 11, 12, 13, 14, 15])
expect(cronToArray('10-11,20-22,30-33', r(0, 59))).toEqual([10, 11, 20, 21, 22, 30, 31, 32, 33])
expect(cronToArray('5,7-8', r(0, 59))).toEqual([5, 7, 8])
expect(cronToArray('*/10', r(1, 10))).toEqual([1])
expect(cronToArray('2-6/2', r(1, 10))).toEqual([2, 4, 6])
expect(cronToArray('3-5/10', r(1, 10))).toEqual([3])

expect(cronToArray('x', r(0, 59))).toBe(null)
expect(cronToArray('1-60', r(0, 59))).toBe(null)
expect(cronToArray('0-10', r(1, 59))).toBe(null)
expect(cronToArray('60', r(0, 59))).toBe(null)
expect(cronToArray('0', r(1, 10))).toBe(null)
expect(cronToArray('*/90', r(1, 10))).toBe(null)
expect(cronToArray('*/11', r(1, 10))).toBe(null)
expect(cronToArray('2-6/11', r(1, 10))).toBe(null)
})

it('arrayToSegment', () => {
Expand All @@ -40,7 +45,7 @@ describe('segments', () => {
expect(arrayToCron([], r(1, 3))).toEqual('*')
expect(arrayToCron([1, 2, 3], r(1, 3))).toEqual('*')
expect(arrayToCron([0, 5, 10], r(0, 10))).toEqual('*/5')
expect(arrayToCron([7, 14, 21, 28], r(5, 30))).toEqual('*/7')
expect(arrayToCron([5, 12, 19, 26], r(5, 30))).toEqual('*/7')
expect(arrayToCron([0, 5, 10], r(0, 20))).toEqual('0,5,10')
expect(arrayToCron([1, 2, 5, 8, 9, 10], r(1, 10))).toEqual('1-2,5,8-10')
})
Expand Down
52 changes: 34 additions & 18 deletions core/src/cron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,40 +129,45 @@ class RangeSegment implements CronSegment {
}

const _every = (n: number, min: number, max: number) => {
const start = n * Math.floor(min / n)
const res = []
for (let i = start; i <= max; i += n) {
if (i >= min) {
res.push(i)
}
for (let i = min; i <= max; i += n) {
res.push(i)
}
return res
}

class EverySegment implements CronSegment {
static re = /^\*\/\d+$/
static re = /^(\*|\d+-\d+)\/\d+$/

field: FieldWrapper
type: CronType = CronType.EveryX
every: number
start: number
end: number

constructor(field: FieldWrapper, every: number) {
constructor(field: FieldWrapper, every: number, start?: number, end?: number) {
this.field = field
this.every = every
this.start = start ?? field.min
this.end = end ?? field.max
}

toCron() {
return `*/${this.every}`
if (this.start == this.field.min && this.end == this.field.max) {
return `*/${this.every}`
}
return `${this.start}-${this.end}/${this.every}`
}

toArray() {
const { min, max } = this.field
return _every(this.every, min, max)
return _every(this.every, this.start, this.end)
}

get items() {
return {
every: this.field.itemMap[this.every],
start: this.field.itemMap[this.start],
end: this.field.itemMap[this.end],
}
}

Expand All @@ -171,15 +176,22 @@ class EverySegment implements CronSegment {
return null
}

const [, everyStr] = str.split('/')
const [rangeStr, everyStr] = str.split('/')
const every = parseInt(everyStr)
const { min, max } = field

if (every > field.items.length) {
return null
}

const range = str.split('-').map((s) => parseInt(s))
const min = rangeStr == '*' ? field.min : range[0]
const max = rangeStr == '*' ? field.max : range[1]

if (_every(every, min, max).length == 0) {
return null
}

return new EverySegment(field, every)
return new EverySegment(field, every, min, max)
}

static fromArray(arr: number[], field: FieldWrapper) {
Expand All @@ -194,18 +206,22 @@ class EverySegment implements CronSegment {
return null
}

const first = min % step === 0 ? min : (Math.floor(min / step) + 1) * step
if (arr.length !== Math.floor((max - first) / step) + 1) {
// prevent a-b/x segments until localization is ready
if (arr[0] != min) {
return null
}
const end = arr[arr.length - 1]
if (max - end >= step) {
return null
}

for (const value of arr) {
if (value % step !== 0) {
for (let i = 2; i < arr.length; i++) {
if (arr[i] - arr[i - 1] != step) {
return null
}
}

return new EverySegment(field, step)
return new EverySegment(field, step, min, max)
}
}

Expand Down

0 comments on commit fca6bba

Please sign in to comment.