Skip to content

Commit

Permalink
feat(core): implements the every-at cron syntax (#45)
Browse files Browse the repository at this point in the history
* wip for every beginning at changes.

* revert to original

* Initial implementation.

* Initial implementation.

* Final changes for everyAt implementation.

* fix(core): remove node-gyp.

* fix(core): make every-at feature disabled by default with option to enable.

* fix(core): move every-at tests to their own tests.

* feat(core): make the everyAtSyntaxEnabled dynamic

* fix(core): change prop name

* fix(core): make enableEveryAt dynamic & locale tweak

* feat(vuetify): add enableEveryAt prop

* feat(vuetify): add enableEveryAt prop

* feat(light): add enableEveryAt prop

* refactor: rename everyXatY to everyAt

---------

Co-authored-by: brandon.arino@carvana.com <brandon.arino@carvana.com>
Co-authored-by: Andreas Bichinger <andreas.bichinger@gmail.com>
  • Loading branch information
3 people authored Feb 23, 2024
1 parent 21d11c1 commit 4c9f33c
Show file tree
Hide file tree
Showing 13 changed files with 672 additions and 121 deletions.
29 changes: 20 additions & 9 deletions core/src/core.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script>
import multiple from './fields/multiple'
import {MultipleColumns} from './fields/multiple'
import types from './types'
import locale from './locale'
import util from './util'
Expand Down Expand Up @@ -55,6 +55,10 @@ export default {
mergeLocale: {
type: Boolean,
default: true
},
enableEveryAt: {
type: Boolean,
default: false
}
},
data(){
Expand All @@ -67,7 +71,8 @@ export default {
return {
selected: selected,
error: '',
selectedPeriod: this.periods[this.periods.length-1]
selectedPeriod: this.periods[this.periods.length-1],
multiple: new MultipleColumns(this.enableEveryAt)
}
},
Expand Down Expand Up @@ -106,7 +111,7 @@ export default {
}
}
},
watch: {
value: {
handler: function(value){
Expand All @@ -129,7 +134,13 @@ export default {
handler: function(error){
this.$emit('error', error)
}
}
},
enableEveryAt: {
handler: function(enableEveryAt){
this.multiple.enableEveryAt = enableEveryAt
this.selectedToCron(this.selected)
}
}
},
render(){
Expand All @@ -156,7 +167,7 @@ export default {
fieldProps.push({
...field,
cron: this.splitValue[i],
selectedStr: multiple.arrayToStr(values, field).getText(this.computedLocale, this.selectedPeriod.id),
selectedStr: this.multiple.arrayToStr(values, field).getText(this.computedLocale, this.selectedPeriod.id),
events,
attrs,
prefix: getPrefix(this.computedLocale, this.selectedPeriod.id, field.id),
Expand Down Expand Up @@ -199,14 +210,14 @@ export default {
this.error = 'invalid pattern'
return
}
for(var i = 0; i < this.splitValue.length; i++){
let field = this.computedFields[i]
if(!this.selectedPeriod.value.includes(field.id)){
continue
}
let array = multiple.strToArray(this.splitValue[i], field)
let array = this.multiple.strToArray(this.splitValue[i], field)
if(array === null){
this.error = 'invalid pattern'
return
Expand All @@ -225,7 +236,7 @@ export default {
continue
}
let array = selected[field.id]
let str = multiple.arrayToStr(array, field)
let str = this.multiple.arrayToStr(array, field)
if(str === null){
this.error = 'invalid selection'
return
Expand All @@ -237,4 +248,4 @@ export default {
}
}
}
</script>
</script>
2 changes: 1 addition & 1 deletion core/src/fields/every.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function strToArray(str, {min, max}){
if(!re.test(str)){
return null
}

let [, everyStr] = str.split('/')
let every = parseInt(everyStr)

Expand Down
59 changes: 59 additions & 0 deletions core/src/fields/everyAt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// x/y
import types from '../types'
const { EveryAtColumn } = types

let re = /^\d+\/\d+$/

function buildArray(min, max, at, every) {
let res = []
for(let i = at; i <= max; i+=every){
if(i >= min){
res.push(i)
}
}
return res.length > 0 ? res : null
}

function strToArray(str, {min, max}){
if(!re.test(str)){
return null
}

let [atStr, everyStr] = str.split('/')
let at = parseInt(atStr)
let every = parseInt(everyStr)

return buildArray(min, max, at, every)
}

function arrayToStr(arr, field){
let {min, max} = field

if(arr.length < 3){
return null
}

let at = arr[0]
let step = arr[1] - arr[0]

if(step <= 1){
return null
}

let computedArray = buildArray(min, max, at, step)
if (arr.length !== computedArray.length) {
return null
}

let missing = arr.filter((i) => !computedArray.includes(i))
if (missing.length > 0) {
return null
}

return new EveryAtColumn(field, step, at)
}

export default {
strToArray,
arrayToStr
}
80 changes: 52 additions & 28 deletions core/src/fields/multiple.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,70 @@

import any from './any'
import every from './every'
import everyAt from './everyAt'
import range from './range'
import value from './value'

let fieldTypes = [any, every, range, value]

function strToArray(str, field){
let fields = str.split(',')
let res = []
for(let f of fields){
if(f == '*'){
return []

// let fieldTypes = [any, every, everyAt, range, value]

export class MultipleColumns {

constructor(enableEveryAt){
this._enableEveryAt = null
this.enableEveryAt = enableEveryAt
}

get enableEveryAt(){
return this._enableEveryAt
}

set enableEveryAt(value) {
this._enableEveryAt = !!value
}

get fieldTypes() {
if (this.enableEveryAt) {
return [any, every, everyAt, range, value]
} else {
return [any, every, range, value]
}
}

let values = null
for(let fieldType of fieldTypes){
values = fieldType.strToArray(f, field)
if(values !== null){
break
strToArray(str, field){
let fields = str.split(',')
let res = []
for(let f of fields){
if(f == '*'){
return []
}

let values = null
for(let fieldType of this.fieldTypes){
values = fieldType.strToArray(f, field)
if(values !== null){
break
}
}
if(values === null){
return null
}
res.push(...values)
}
if(values === null){
return null
}
res.push(...values)
return Array.from(new Set(res))
}
return Array.from(new Set(res))
}

function arrayToStr(arr, field){
for(let fieldType of fieldTypes){
let value = fieldType.arrayToStr(arr, field)
if(value){
return value
arrayToStr(arr, field){
for(let fieldType of this.fieldTypes){
let value = fieldType.arrayToStr(arr, field)
if(value){
return value
}
}
return null
}
return null
}

export default {
strToArray,
arrayToStr
}
// export MultipleColumns

17 changes: 10 additions & 7 deletions core/src/locale/en.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
export default {
eachPeriod: {
eachPeriod: {
eachField: {
empty: 'every {{field.id}}',
value: '{{value.text}}',
range: '{{start.text}}-{{end.text}}',
everyX: 'every {{every.value}}'
everyX: 'every {{every.value}} {{field.id}}(s)',
everyAt: 'every {{every.value}} {{field.id}}(s), starting at {{at.value}} {{field.id}}(s)'
},
monthField: {
prefix: 'in',
value: '{{value.alt}}',
range: '{{start.alt}}-{{end.alt}}',
everyAt: 'every {{every.value}} {{field.id}}(s), starting in {{at.alt}}'
},
dayField: {
prefix: 'on'
prefix: 'on',
everyAt: 'every {{every.value}} {{field.id}}(s), starting on the {{at.alt}} of the month'
},
dayOfWeekField: {
prefix: 'on',
empty: 'every day of the week',
value: '{{value.alt}}',
range: '{{start.alt}}-{{end.alt}}',
everyX: 'every {{every.value}} day(s) of the week',
everyAt: 'every {{every.value}} day(s) of the week, starting on {{at.alt}}'
},
hourField: {
prefix: 'at'
Expand All @@ -29,9 +34,7 @@ export default {
},
hourPeriod: {
minuteField: {
prefix: 'at',
suffix: 'minute(s)',
empty: 'every'
prefix: 'at'
}
},
monthPeriod: {
Expand All @@ -46,4 +49,4 @@ export default {
},
periodPrefix: 'Every',
periodSuffix: ''
}
}
36 changes: 28 additions & 8 deletions core/src/locale/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ const locales = {
}

/**
*
* @param {string} locale=en
* @returns {object} object with all strings in the requested language
*
* @param {string} locale=en
* @returns {object} object with all strings in the requested language
*/
function getLocale(locale){
if(locales.hasOwnProperty(locale)){
Expand All @@ -20,16 +20,36 @@ function getLocale(locale){
}
}

/** Solution provided by https://stackoverflow.com/a/57518703
*
*
*/
function getLocaleOrdinalSuffix(locale, value) {
const ordRules = new Intl.PluralRules(locale, {type: "ordinal"});
const suffixes = {
one: "st",
two: "nd",
few: "rd",
other: "th"
};
const category = ordRules.select(value);
const suffix = suffixes[category];
return (value + suffix);
}

/**
*
* @param {string} locale
*
* @param {string} locale
* @returns {object} items for minute, hour, day, month and day of week
*/
function defaultItems(locale){
return {
minuteItems: genItems(0, 59, (value) => pad(value, 2)),
hourItems: genItems(0, 23, (value) => pad(value, 2)),
dayItems: genItems(1, 31),
dayItems: genItems(1, 31,
(value) => { return value+''},
(value) => getLocaleOrdinalSuffix(locale, value)
),
monthItems: genItems(1, 12, (value) => {
return new Date(2021, value-1, 1).toLocaleDateString(locale, {month: 'long'})
}, (value) => {
Expand Down Expand Up @@ -57,7 +77,7 @@ export default {
getSuffix: (locale, periodId, fieldId) => {
return traverse(locale, [periodId+'Period', 'eachPeriod'], [fieldId+'Field', 'eachField'], ['suffix']) || ''
},

defaultItems,
getLocale
}
}
Loading

0 comments on commit 4c9f33c

Please sign in to comment.