Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

rrule

Package Overview
Dependencies
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rrule - npm Package Compare versions

Comparing version 2.1.0 to 2.2.0

1543

lib/nlp.js

@@ -20,983 +20,912 @@ /*!

*/
(function (root){
/* global module, define */
;(function (root, factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory()
} else if (typeof define === 'function' && define.amd) {
define([], factory)
} else {
root._getRRuleNLP = factory()
}
}(typeof window === 'object' ? window : this, function () {
// =============================================================================
// Helper functions
// =============================================================================
var serverSide = typeof module !== 'undefined' && module.exports;
var RRule;
/**
* Return true if a value is in an array
*/
var contains = function (arr, val) {
return arr.indexOf(val) !== -1
}
return function (RRule) {
// =============================================================================
// ToText
// =============================================================================
if (serverSide) {
RRule = require('./rrule').RRule;
} else if (root.RRule) {
RRule = root.RRule;
} else if (typeof require !== 'undefined') {
if (!RRule) {RRule = require('rrule');}
} else {
throw new Error('rrule.js is required for rrule/nlp.js to work')
}
/**
*
* @param {RRule} rrule
* Optional:
* @param {Function} gettext function
* @param {Object} language definition
* @constructor
*/
var ToText = function (rrule, gettext, language) {
this.text = ''
this.language = language || ENGLISH
this.gettext = gettext || function (id) {
return id
}
this.rrule = rrule
this.freq = rrule.options.freq
this.options = rrule.options
this.origOptions = rrule.origOptions
//=============================================================================
// Helper functions
//=============================================================================
if (this.origOptions.bymonthday) {
var bymonthday = [].concat(this.options.bymonthday)
var bynmonthday = [].concat(this.options.bynmonthday)
/**
* Return true if a value is in an array
*/
var contains = function(arr, val) {
return arr.indexOf(val) != -1;
};
//=============================================================================
// ToText
//=============================================================================
/**
*
* @param {RRule} rrule
* Optional:
* @param {Function} gettext function
* @param {Object} language definition
* @constructor
*/
var ToText = function(rrule, gettext, language) {
this.gettext = gettext || function(id) {return id};
this.language = language || ENGLISH;
this.text = '';
this.rrule = rrule;
this.freq = rrule.options.freq;
this.options = rrule.options;
this.origOptions = rrule.origOptions;
if (this.origOptions.bymonthday) {
var bymonthday = [].concat(this.options.bymonthday);
var bynmonthday = [].concat(this.options.bynmonthday);
bymonthday.sort();
bynmonthday.sort();
bynmonthday.reverse();
bymonthday.sort()
bynmonthday.sort()
bynmonthday.reverse()
// 1, 2, 3, .., -5, -4, -3, ..
this.bymonthday = bymonthday.concat(bynmonthday);
if (!this.bymonthday.length) {
this.bymonthday = null;
}
}
this.bymonthday = bymonthday.concat(bynmonthday)
if (!this.bymonthday.length) this.bymonthday = null
}
if (this.origOptions.byweekday) {
if (this.origOptions.byweekday) {
var byweekday = !(this.origOptions.byweekday instanceof Array)
? [this.origOptions.byweekday]
: this.origOptions.byweekday;
var days = String(byweekday);
? [this.origOptions.byweekday] : this.origOptions.byweekday
var days = String(byweekday)
this.byweekday = {
allWeeks:byweekday.filter(function (weekday) {
return !Boolean(weekday.n);
}),
someWeeks:byweekday.filter(function (weekday) {
return Boolean(weekday.n);
}),
isWeekdays:(
days.indexOf('MO') != -1 &&
days.indexOf('TU') != -1 &&
days.indexOf('WE') != -1 &&
days.indexOf('TH') != -1 &&
days.indexOf('FR') != -1 &&
days.indexOf('SA') == -1 &&
days.indexOf('SU') == -1
)
};
allWeeks: byweekday.filter(function (weekday) {
return !Boolean(weekday.n)
}),
someWeeks: byweekday.filter(function (weekday) {
return Boolean(weekday.n)
}),
isWeekdays: (
days.indexOf('MO') !== -1 &&
days.indexOf('TU') !== -1 &&
days.indexOf('WE') !== -1 &&
days.indexOf('TH') !== -1 &&
days.indexOf('FR') !== -1 &&
days.indexOf('SA') === -1 &&
days.indexOf('SU') === -1
)
}
var sortWeekDays = function (a, b) {
return a.weekday - b.weekday
}
var sortWeekDays = function(a, b) {
return a.weekday - b.weekday;
};
this.byweekday.allWeeks.sort(sortWeekDays)
this.byweekday.someWeeks.sort(sortWeekDays)
this.byweekday.allWeeks.sort(sortWeekDays);
this.byweekday.someWeeks.sort(sortWeekDays);
if (!this.byweekday.allWeeks.length) {
this.byweekday.allWeeks = null;
}
if (!this.byweekday.someWeeks.length) {
this.byweekday.someWeeks = null;
}
if (!this.byweekday.allWeeks.length) this.byweekday.allWeeks = null
if (!this.byweekday.someWeeks.length) this.byweekday.someWeeks = null
} else {
this.byweekday = null
}
}
else {
this.byweekday = null;
}
};
var common = [
'count', 'until', 'interval',
'byweekday', 'bymonthday', 'bymonth'
]
ToText.IMPLEMENTED = []
ToText.IMPLEMENTED[RRule.HOURLY] = common
ToText.IMPLEMENTED[RRule.DAILY] = ['byhour'].concat(common)
ToText.IMPLEMENTED[RRule.WEEKLY] = common
ToText.IMPLEMENTED[RRule.MONTHLY] = common
ToText.IMPLEMENTED[RRule.YEARLY] = ['byweekno', 'byyearday'].concat(common)
/**
* Test whether the rrule can be fully converted to text.
* @param {RRule} rrule
* @return {Boolean}
*/
ToText.isFullyConvertible = function (rrule) {
var canConvert = true
ToText.IMPLEMENTED = [];
var common = [
'count', 'until', 'interval',
'byweekday', 'bymonthday', 'bymonth'
];
ToText.IMPLEMENTED[RRule.DAILY] = common;
ToText.IMPLEMENTED[RRule.WEEKLY] = common;
ToText.IMPLEMENTED[RRule.MONTHLY] = common;
ToText.IMPLEMENTED[RRule.YEARLY] = ['byweekno', 'byyearday'].concat(common);
if (!(rrule.options.freq in ToText.IMPLEMENTED)) return false
if (rrule.origOptions.until && rrule.origOptions.count) return false
/**
* Test whether the rrule can be fully converted to text.
* @param {RRule} rrule
* @return {Boolean}
*/
ToText.isFullyConvertible = function(rrule) {
var canConvert = true;
for (var key in rrule.origOptions) {
if (contains(['dtstart', 'wkst', 'freq'], key)) return true
if (!contains(ToText.IMPLEMENTED[rrule.options.freq], key)) return false
}
if (!(rrule.options.freq in ToText.IMPLEMENTED)) {
return false;
return canConvert
}
if (rrule.origOptions.until && rrule.origOptions.count) {
return false;
}
for (var key in rrule.origOptions) {
if (contains(['dtstart', 'wkst', 'freq'], key)) {
return true;
}
if (!contains(ToText.IMPLEMENTED[rrule.options.freq], key)) {
canConvert = false;
return false;
}
}
return canConvert;
};
ToText.prototype = {
constructor: ToText,
isFullyConvertible: function () {
return ToText.isFullyConvertible(this.rrule)
},
ToText.prototype = {
/**
* Perform the conversion. Only some of the frequencies are supported.
* If some of the rrule's options aren't supported, they'll
* be omitted from the output an "(~ approximate)" will be appended.
* @return {*}
*/
toString: function () {
var gettext = this.gettext
if (!(this.options.freq in ToText.IMPLEMENTED)) {
return gettext('RRule error: Unable to fully convert this rrule to text')
}
isFullyConvertible: function() {
return ToText.isFullyConvertible(this.rrule);
},
this.text = [gettext('every')]
this[RRule.FREQUENCIES[this.options.freq]]()
if (this.options.until) {
this.add(gettext('until'))
var until = this.options.until
this.add(this.language.monthNames[until.getMonth()])
.add(until.getDate() + ',')
.add(until.getFullYear())
} else if (this.options.count) {
this.add(gettext('for'))
.add(this.options.count)
.add(this.plural(this.options.count)
? gettext('times') : gettext('time'))
}
/**
* Perform the conversion. Only some of the frequencies are supported.
* If some of the rrule's options aren't supported, they'll
* be omitted from the output an "(~ approximate)" will be appended.
* @return {*}
*/
toString: function() {
if (!this.isFullyConvertible()) this.add(gettext('(~ approximate)'))
var gettext = this.gettext;
return this.text.join('')
},
if (!(this.options.freq in ToText.IMPLEMENTED)) {
return gettext(
'RRule error: Unable to fully convert this rrule to text');
}
HOURLY: function () {
var gettext = this.gettext
this.text = [gettext('every')];
if (this.options.interval !== 1) this.add(this.options.interval)
this[RRule.FREQUENCIES[this.options.freq]]();
this.add(this.plural(this.options.interval)
? gettext('hours') : gettext('hour'))
},
if (this.options.until) {
this.add(gettext('until'));
var until = this.options.until;
this.add(this.language.monthNames[until.getMonth()])
.add(until.getDate() + ',')
.add(until.getFullYear());
} else if (this.options.count) {
this.add(gettext('for'))
.add(this.options.count)
.add(this.plural(this.options.count)
? gettext('times')
: gettext('time'));
}
DAILY: function () {
var gettext = this.gettext
if (!this.isFullyConvertible()) {
this.add(gettext('(~ approximate)'));
}
return this.text.join('');
},
if (this.options.interval !== 1) this.add(this.options.interval)
DAILY: function() {
var gettext = this.gettext;
if (this.options.interval != 1) {
this.add(this.options.interval);
}
if (this.byweekday && this.byweekday.isWeekdays) {
this.add(this.plural(this.options.interval)
? gettext('weekdays')
: gettext('weekday'));
this.add(this.plural(this.options.interval)
? gettext('weekdays') : gettext('weekday'))
} else {
this.add(this.plural(this.options.interval)
? gettext('days') : gettext('day'));
this.add(this.plural(this.options.interval)
? gettext('days') : gettext('day'))
}
if (this.origOptions.bymonth) {
this.add(gettext('in'));
this._bymonth();
this.add(gettext('in'))
this._bymonth()
}
if (this.bymonthday) {
this._bymonthday();
this._bymonthday()
} else if (this.byweekday) {
this._byweekday();
this._byweekday()
} else if (this.origOptions.byhour) {
this._byhour()
}
},
},
WEEKLY: function () {
var gettext = this.gettext
WEEKLY: function() {
var gettext = this.gettext;
if (this.options.interval != 1) {
this.add(this.options.interval).add(
this.plural(this.options.interval)
? gettext('weeks')
: gettext('week'));
if (this.options.interval !== 1) {
this.add(this.options.interval)
.add(this.plural(this.options.interval)
? gettext('weeks') : gettext('week'))
}
if (this.byweekday && this.byweekday.isWeekdays) {
if (this.options.interval == 1) {
this.add(this.plural(this.options.interval)
? gettext('weekdays')
: gettext('weekday'));
} else {
this.add(gettext('on')).add(gettext('weekdays'));
}
if (this.options.interval === 1) {
this.add(this.plural(this.options.interval)
? gettext('weekdays') : gettext('weekday'))
} else {
this.add(gettext('on')).add(gettext('weekdays'))
}
} else {
if (this.options.interval === 1) this.add(gettext('week'))
if (this.options.interval == 1) {
this.add(gettext('week'))
}
if (this.origOptions.bymonth) {
this.add(gettext('in'))
this._bymonth()
}
if (this.origOptions.bymonth) {
this.add(gettext('in'));
this._bymonth();
}
if (this.bymonthday) {
this._bymonthday();
} else if (this.byweekday) {
this._byweekday();
}
if (this.bymonthday) {
this._bymonthday()
} else if (this.byweekday) {
this._byweekday()
}
}
},
},
MONTHLY: function () {
var gettext = this.gettext
MONTHLY: function() {
var gettext = this.gettext;
if (this.origOptions.bymonth) {
if (this.options.interval != 1) {
this.add(this.options.interval).add(gettext('months'));
if (this.plural(this.options.interval)) {
this.add(gettext('in'));
}
} else {
//this.add(gettext('MONTH'));
}
this._bymonth();
if (this.options.interval !== 1) {
this.add(this.options.interval).add(gettext('months'))
if (this.plural(this.options.interval)) this.add(gettext('in'))
} else {
// this.add(gettext('MONTH'))
}
this._bymonth()
} else {
if (this.options.interval != 1) {
this.add(this.options.interval);
}
this.add(this.plural(this.options.interval)
? gettext('months')
: gettext('month'));
if (this.options.interval !== 1) this.add(this.options.interval)
this.add(this.plural(this.options.interval)
? gettext('months') : gettext('month'))
}
if (this.bymonthday) {
this._bymonthday();
this._bymonthday()
} else if (this.byweekday && this.byweekday.isWeekdays) {
this.add(gettext('on')).add(gettext('weekdays'));
this.add(gettext('on')).add(gettext('weekdays'))
} else if (this.byweekday) {
this._byweekday();
this._byweekday()
}
},
},
YEARLY: function() {
var gettext = this.gettext;
YEARLY: function () {
var gettext = this.gettext
if (this.origOptions.bymonth) {
if (this.options.interval != 1) {
this.add(this.options.interval);
this.add(gettext('years'));
} else {
// this.add(gettext('YEAR'));
}
this._bymonth();
if (this.options.interval !== 1) {
this.add(this.options.interval)
this.add(gettext('years'))
} else {
// this.add(gettext('YEAR'))
}
this._bymonth()
} else {
if (this.options.interval != 1) {
this.add(this.options.interval);
}
this.add(this.plural(this.options.interval)
? gettext('years')
: gettext('year'));
if (this.options.interval !== 1) this.add(this.options.interval)
this.add(this.plural(this.options.interval)
? gettext('years') : gettext('year'))
}
if (this.bymonthday) {
this._bymonthday();
this._bymonthday()
} else if (this.byweekday) {
this._byweekday();
this._byweekday()
}
if (this.options.byyearday) {
this.add(gettext('on the'))
.add(this.list(this.options.byyearday,
this.nth, gettext('and')))
.add(gettext('day'));
this.add(gettext('on the'))
.add(this.list(this.options.byyearday, this.nth, gettext('and')))
.add(gettext('day'))
}
if (this.options.byweekno) {
this.add(gettext('in'))
.add(this.plural(this.options.byweekno.length)
? gettext('weeks') : gettext('week'))
.add(this.list(this.options.byweekno, null, gettext('and')));
this.add(gettext('in'))
.add(this.plural(this.options.byweekno.length) ? gettext('weeks') : gettext('week'))
.add(this.list(this.options.byweekno, null, gettext('and')))
}
},
},
_bymonthday: function() {
var gettext = this.gettext;
_bymonthday: function () {
var gettext = this.gettext
if (this.byweekday && this.byweekday.allWeeks) {
this.add(gettext('on'))
.add(this.list(this.byweekday.allWeeks,
this.weekdaytext, gettext('or')))
.add(gettext('the'))
.add(this.list(this.bymonthday, this.nth, gettext('or')));
this.add(gettext('on'))
.add(this.list(this.byweekday.allWeeks, this.weekdaytext, gettext('or')))
.add(gettext('the'))
.add(this.list(this.bymonthday, this.nth, gettext('or')))
} else {
this.add(gettext('on the'))
.add(this.list(this.bymonthday, this.nth, gettext('and')));
this.add(gettext('on the'))
.add(this.list(this.bymonthday, this.nth, gettext('and')))
}
//this.add(gettext('DAY'));
},
// this.add(gettext('DAY'))
},
_byweekday: function() {
var gettext = this.gettext;
_byweekday: function () {
var gettext = this.gettext
if (this.byweekday.allWeeks && !this.byweekday.isWeekdays) {
this.add(gettext('on'))
.add(this.list(this.byweekday.allWeeks, this.weekdaytext));
this.add(gettext('on'))
.add(this.list(this.byweekday.allWeeks, this.weekdaytext))
}
if (this.byweekday.someWeeks) {
if (this.byweekday.allWeeks) this.add(gettext('and'))
if (this.byweekday.allWeeks) {
this.add(gettext('and'));
}
this.add(gettext('on the'))
.add(this.list(this.byweekday.someWeeks,
this.weekdaytext,
gettext('and')));
this.add(gettext('on the'))
.add(this.list(this.byweekday.someWeeks, this.weekdaytext, gettext('and')))
}
},
},
_bymonth: function() {
this.add(this.list(this.options.bymonth,
this.monthtext,
this.gettext('and')));
},
_byhour: function () {
var gettext = this.gettext
nth: function(n) {
var nth, npos, gettext = this.gettext;
this.add(gettext('at'))
.add(this.list(this.origOptions.byhour, null, gettext('and')))
},
if (n == -1) {
return gettext('last');
}
_bymonth: function () {
this.add(this.list(this.options.bymonth, this.monthtext, this.gettext('and')))
},
npos = Math.abs(n);
nth: function (n) {
var nth, npos
var gettext = this.gettext
switch(npos) {
case 1:
case 21:
case 31:
nth = npos + gettext('st');
break;
case 2:
case 22:
nth = npos + gettext('nd');
break;
case 3:
case 23:
nth = npos + gettext('rd');
break;
default:
nth = npos + gettext('th');
if (n === -1) return gettext('last')
npos = Math.abs(n)
switch (npos) {
case 1:
case 21:
case 31:
nth = npos + gettext('st')
break
case 2:
case 22:
nth = npos + gettext('nd')
break
case 3:
case 23:
nth = npos + gettext('rd')
break
default:
nth = npos + gettext('th')
}
return n < 0 ? nth + ' ' + gettext('last') : nth;
return n < 0 ? nth + ' ' + gettext('last') : nth
},
},
monthtext: function (m) {
return this.language.monthNames[m - 1]
},
monthtext: function(m) {
return this.language.monthNames[m - 1];
},
weekdaytext: function (wday) {
var weekday = typeof wday === 'number' ? wday : wday.getJsWeekday()
return (wday.n ? this.nth(wday.n) + ' ' : '') +
this.language.dayNames[weekday]
},
weekdaytext: function(wday) {
return (wday.n ? this.nth(wday.n) + ' ' : '')
+ this.language.dayNames[wday.getJsWeekday()];
},
plural: function (n) {
return n % 100 !== 1
},
plural: function(n) {
return n % 100 != 1;
},
add: function (s) {
this.text.push(' ')
this.text.push(s)
return this
},
add: function(s) {
this.text.push(' ');
this.text.push(s);
return this;
},
list: function (arr, callback, finalDelim, delim) {
var delimJoin = function (array, delimiter, finalDelimiter) {
var list = ''
list: function(arr, callback, finalDelim, delim) {
var delimJoin = function (array, delimiter, finalDelimiter) {
var list = '';
for(var i = 0; i < array.length; i++) {
if (i != 0) {
if (i == array.length - 1) {
list += ' ' + finalDelimiter + ' ';
} else {
list += delimiter + ' ';
}
}
list += array[i];
for (var i = 0; i < array.length; i++) {
if (i !== 0) {
if (i === array.length - 1) {
list += ' ' + finalDelimiter + ' '
} else {
list += delimiter + ' '
}
}
return list;
};
list += array[i]
}
return list
}
delim = delim || ',';
callback = callback || (function(o){return o;});
var self = this;
var realCallback = function(arg) {
return callback.call(self, arg);
};
delim = delim || ','
callback = callback || function (o) {
return o
}
var self = this
var realCallback = function (arg) {
return callback.call(self, arg)
}
if (finalDelim) {
return delimJoin(arr.map(realCallback), delim, finalDelim);
return delimJoin(arr.map(realCallback), delim, finalDelim)
} else {
return arr.map(realCallback).join(delim + ' ');
return arr.map(realCallback).join(delim + ' ')
}
}
}
};
//=============================================================================
// fromText
//=============================================================================
/**
* Will be able to convert some of the below described rules from
* text format to a rule object.
*
*
* RULES
*
* Every ([n])
* day(s)
* | [weekday], ..., (and) [weekday]
* | weekday(s)
* | week(s)
* | month(s)
* | [month], ..., (and) [month]
* | year(s)
*
*
* Plus 0, 1, or multiple of these:
*
* on [weekday], ..., (or) [weekday] the [monthday], [monthday], ... (or) [monthday]
*
* on [weekday], ..., (and) [weekday]
*
* on the [monthday], [monthday], ... (and) [monthday] (day of the month)
*
* on the [nth-weekday], ..., (and) [nth-weekday] (of the month/year)
*
*
* Plus 0 or 1 of these:
*
* for [n] time(s)
*
* until [date]
*
* Plus (.)
*
*
* Definitely no supported for parsing:
*
* (for year):
* in week(s) [n], ..., (and) [n]
*
* on the [yearday], ..., (and) [n] day of the year
* on day [yearday], ..., (and) [n]
*
*
* NON-TERMINALS
*
* [n]: 1, 2 ..., one, two, three ..
* [month]: January, February, March, April, May, ... December
* [weekday]: Monday, ... Sunday
* [nth-weekday]: first [weekday], 2nd [weekday], ... last [weekday], ...
* [monthday]: first, 1., 2., 1st, 2nd, second, ... 31st, last day, 2nd last day, ..
* [date]:
* [month] (0-31(,) ([year])),
* (the) 0-31.(1-12.([year])),
* (the) 0-31/(1-12/([year])),
* [weekday]
*
* [year]: 0000, 0001, ... 01, 02, ..
*
* Definitely not supported for parsing:
*
* [yearday]: first, 1., 2., 1st, 2nd, second, ... 366th, last day, 2nd last day, ..
*
* @param {String} text
* @return {Object, Boolean} the rule, or null.
*/
var fromText = function(text, language) {
return new RRule(parseText(text, language))
};
var parseText = function(text, language) {
var ttr = new Parser((language || ENGLISH).tokens);
if(!ttr.start(text)) {
return null;
// =============================================================================
// fromText
// =============================================================================
/**
* Will be able to convert some of the below described rules from
* text format to a rule object.
*
*
* RULES
*
* Every ([n])
* day(s)
* | [weekday], ..., (and) [weekday]
* | weekday(s)
* | week(s)
* | month(s)
* | [month], ..., (and) [month]
* | year(s)
*
*
* Plus 0, 1, or multiple of these:
*
* on [weekday], ..., (or) [weekday] the [monthday], [monthday], ... (or) [monthday]
*
* on [weekday], ..., (and) [weekday]
*
* on the [monthday], [monthday], ... (and) [monthday] (day of the month)
*
* on the [nth-weekday], ..., (and) [nth-weekday] (of the month/year)
*
*
* Plus 0 or 1 of these:
*
* for [n] time(s)
*
* until [date]
*
* Plus (.)
*
*
* Definitely no supported for parsing:
*
* (for year):
* in week(s) [n], ..., (and) [n]
*
* on the [yearday], ..., (and) [n] day of the year
* on day [yearday], ..., (and) [n]
*
*
* NON-TERMINALS
*
* [n]: 1, 2 ..., one, two, three ..
* [month]: January, February, March, April, May, ... December
* [weekday]: Monday, ... Sunday
* [nth-weekday]: first [weekday], 2nd [weekday], ... last [weekday], ...
* [monthday]: first, 1., 2., 1st, 2nd, second, ... 31st, last day, 2nd last day, ..
* [date]:
* [month] (0-31(,) ([year])),
* (the) 0-31.(1-12.([year])),
* (the) 0-31/(1-12/([year])),
* [weekday]
*
* [year]: 0000, 0001, ... 01, 02, ..
*
* Definitely not supported for parsing:
*
* [yearday]: first, 1., 2., 1st, 2nd, second, ... 366th, last day, 2nd last day, ..
*
* @param {String} text
* @return {Object, Boolean} the rule, or null.
*/
var fromText = function (text, language) {
return new RRule(parseText(text, language))
}
var options = {};
var parseText = function (text, language) {
var options = {}
var ttr = new Parser((language || ENGLISH).tokens)
S();
return options;
if (!ttr.start(text)) return null
function S() {
ttr.expect('every');
S()
return options
function S () {
// every [n]
var n;
if(n = ttr.accept('number'))
options.interval = parseInt(n[0]);
var n
if(ttr.isDone())
throw new Error('Unexpected end');
ttr.expect('every')
if ((n = ttr.accept('number'))) options.interval = parseInt(n[0], 10)
if (ttr.isDone()) throw new Error('Unexpected end')
switch(ttr.symbol) {
case 'day(s)':
options.freq = RRule.DAILY;
switch (ttr.symbol) {
case 'day(s)':
options.freq = RRule.DAILY
if (ttr.nextSymbol()) {
ON();
F();
AT()
F()
}
break;
break
// FIXME Note: every 2 weekdays != every two weeks on weekdays.
// DAILY on weekdays is not a valid rule
case 'weekday(s)':
options.freq = RRule.WEEKLY;
// FIXME Note: every 2 weekdays != every two weeks on weekdays.
// DAILY on weekdays is not a valid rule
case 'weekday(s)':
options.freq = RRule.WEEKLY
options.byweekday = [
RRule.MO,
RRule.TU,
RRule.WE,
RRule.TH,
RRule.FR
];
ttr.nextSymbol();
F();
break;
RRule.MO,
RRule.TU,
RRule.WE,
RRule.TH,
RRule.FR
]
ttr.nextSymbol()
F()
break
case 'week(s)':
options.freq = RRule.WEEKLY;
case 'week(s)':
options.freq = RRule.WEEKLY
if (ttr.nextSymbol()) {
ON();
F();
ON()
F()
}
break;
break
case 'month(s)':
options.freq = RRule.MONTHLY;
case 'hour(s)':
options.freq = RRule.HOURLY
if (ttr.nextSymbol()) {
ON();
F();
ON()
F()
}
break;
break
case 'year(s)':
options.freq = RRule.YEARLY;
case 'month(s)':
options.freq = RRule.MONTHLY
if (ttr.nextSymbol()) {
ON();
F();
ON()
F()
}
break;
break
case 'monday':
case 'tuesday':
case 'wednesday':
case 'thursday':
case 'friday':
case 'saturday':
case 'sunday':
options.freq = RRule.WEEKLY;
options.byweekday = [RRule[ttr.symbol.substr(0, 2).toUpperCase()]];
case 'year(s)':
options.freq = RRule.YEARLY
if (ttr.nextSymbol()) {
ON()
F()
}
break
if(!ttr.nextSymbol())
return;
case 'monday':
case 'tuesday':
case 'wednesday':
case 'thursday':
case 'friday':
case 'saturday':
case 'sunday':
options.freq = RRule.WEEKLY
options.byweekday = [RRule[ttr.symbol.substr(0, 2).toUpperCase()]]
if (!ttr.nextSymbol()) return
// TODO check for duplicates
while (ttr.accept('comma')) {
if(ttr.isDone())
throw new Error('Unexpected end');
if (ttr.isDone()) throw new Error('Unexpected end')
var wkd;
if(!(wkd = decodeWKD())) {
throw new Error('Unexpected symbol ' + ttr.symbol
+ ', expected weekday');
}
var wkd
if (!(wkd = decodeWKD())) {
throw new Error('Unexpected symbol ' + ttr.symbol + ', expected weekday')
}
options.byweekday.push(RRule[wkd]);
ttr.nextSymbol();
options.byweekday.push(RRule[wkd])
ttr.nextSymbol()
}
MDAYs();
F();
break;
MDAYs()
F()
break
case 'january':
case 'february':
case 'march':
case 'april':
case 'may':
case 'june':
case 'july':
case 'august':
case 'september':
case 'october':
case 'november':
case 'december':
options.freq = RRule.YEARLY;
options.bymonth = [decodeM()];
case 'january':
case 'february':
case 'march':
case 'april':
case 'may':
case 'june':
case 'july':
case 'august':
case 'september':
case 'october':
case 'november':
case 'december':
options.freq = RRule.YEARLY
options.bymonth = [decodeM()]
if(!ttr.nextSymbol())
return;
if (!ttr.nextSymbol()) return
// TODO check for duplicates
while (ttr.accept('comma')) {
if(ttr.isDone())
throw new Error('Unexpected end');
if (ttr.isDone()) throw new Error('Unexpected end')
var m;
if(!(m = decodeM())) {
throw new Error('Unexpected symbol ' + ttr.symbol
+ ', expected month');
}
var m
if (!(m = decodeM())) {
throw new Error('Unexpected symbol ' + ttr.symbol + ', expected month')
}
options.bymonth.push(m);
ttr.nextSymbol();
options.bymonth.push(m)
ttr.nextSymbol()
}
ON();
F();
break;
ON()
F()
break
default:
throw new Error('Unknown symbol');
default:
throw new Error('Unknown symbol')
}
}
}
function ON() {
function ON () {
var on = ttr.accept('on')
var the = ttr.accept('the')
if (!(on || the)) return
var on = ttr.accept('on');
var the = ttr.accept('the');
if(!(on || the)) {
return;
}
do {
var nth, wkd, m
var nth, wkd, m;
// nth <weekday> | <weekday>
if ((nth = decodeNTH())) {
// ttr.nextSymbol()
// nth <weekday> | <weekday>
if(nth = decodeNTH()) {
//ttr.nextSymbol();
if (wkd = decodeWKD()) {
ttr.nextSymbol();
if (!options.byweekday) {
options.byweekday = [];
}
options.byweekday.push(RRule[wkd].nth(nth));
} else {
if(!options.bymonthday) {
options.bymonthday = [];
}
options.bymonthday.push(nth);
ttr.accept('day(s)');
}
// <weekday>
} else if(wkd = decodeWKD()) {
ttr.nextSymbol();
if(!options.byweekday)
options.byweekday = [];
options.byweekday.push(RRule[wkd]);
} else if(ttr.symbol == 'weekday(s)') {
ttr.nextSymbol();
if(!options.byweekday)
options.byweekday = [];
options.byweekday.push(RRule.MO);
options.byweekday.push(RRule.TU);
options.byweekday.push(RRule.WE);
options.byweekday.push(RRule.TH);
options.byweekday.push(RRule.FR);
} else if(ttr.symbol == 'week(s)') {
ttr.nextSymbol();
var n;
if(!(n = ttr.accept('number'))) {
throw new Error('Unexpected symbol ' + ttr.symbol
+ ', expected week number');
}
options.byweekno = [n[0]];
while(ttr.accept('comma')) {
if(!(n = ttr.accept('number'))) {
throw new Error('Unexpected symbol ' + ttr.symbol
+ '; expected monthday');
}
options.byweekno.push(n[0]);
}
} else if(m = decodeM()) {
ttr.nextSymbol();
if(!options.bymonth)
options.bymonth = [];
options.bymonth.push(m);
if ((wkd = decodeWKD())) {
ttr.nextSymbol()
if (!options.byweekday) options.byweekday = []
options.byweekday.push(RRule[wkd].nth(nth))
} else {
return;
if (!options.bymonthday) options.bymonthday = []
options.bymonthday.push(nth)
ttr.accept('day(s)')
}
// <weekday>
} else if ((wkd = decodeWKD())) {
ttr.nextSymbol()
if (!options.byweekday) options.byweekday = []
options.byweekday.push(RRule[wkd])
} else if (ttr.symbol === 'weekday(s)') {
ttr.nextSymbol()
if (!options.byweekday) options.byweekday = []
options.byweekday.push(RRule.MO)
options.byweekday.push(RRule.TU)
options.byweekday.push(RRule.WE)
options.byweekday.push(RRule.TH)
options.byweekday.push(RRule.FR)
} else if (ttr.symbol === 'week(s)') {
ttr.nextSymbol()
var n
if (!(n = ttr.accept('number'))) {
throw new Error('Unexpected symbol ' + ttr.symbol + ', expected week number')
}
options.byweekno = [n[0]]
while (ttr.accept('comma')) {
if (!(n = ttr.accept('number'))) {
throw new Error('Unexpected symbol ' + ttr.symbol + '; expected monthday')
}
options.byweekno.push(n[0])
}
} else if ((m = decodeM())) {
ttr.nextSymbol()
if (!options.bymonth) options.bymonth = []
options.bymonth.push(m)
} else {
return
}
} while (ttr.accept('comma') || ttr.accept('the') || ttr.accept('on'))
}
} while (ttr.accept('comma') || ttr.accept('the') || ttr.accept('on'));
}
function AT () {
var at = ttr.accept('at')
if (!at) return
function decodeM() {
switch(ttr.symbol) {
case 'january':
return 1;
case 'february':
return 2;
case 'march':
return 3;
case 'april':
return 4;
case 'may':
return 5;
case 'june':
return 6;
case 'july':
return 7;
case 'august':
return 8;
case 'september':
return 9;
case 'october':
return 10;
case 'november':
return 11;
case 'december':
return 12;
default:
return false;
}
}
do {
var n
if (!(n = ttr.accept('number'))) {
throw new Error('Unexpected symbol ' + ttr.symbol + ', expected hour')
}
options.byhour = [n[0]]
while (ttr.accept('comma')) {
if (!(n = ttr.accept('number'))) {
throw new Error('Unexpected symbol ' + ttr.symbol + '; expected hour')
}
options.byhour.push(n[0])
}
} while (ttr.accept('comma') || ttr.accept('at'))
}
function decodeWKD() {
switch(ttr.symbol) {
case 'monday':
case 'tuesday':
case 'wednesday':
case 'thursday':
case 'friday':
case 'saturday':
case 'sunday':
return ttr.symbol.substr(0, 2).toUpperCase();
break;
default:
return false;
function decodeM () {
switch (ttr.symbol) {
case 'january':
return 1
case 'february':
return 2
case 'march':
return 3
case 'april':
return 4
case 'may':
return 5
case 'june':
return 6
case 'july':
return 7
case 'august':
return 8
case 'september':
return 9
case 'october':
return 10
case 'november':
return 11
case 'december':
return 12
default:
return false
}
}
}
function decodeNTH() {
switch(ttr.symbol) {
case 'last':
ttr.nextSymbol();
return -1;
case 'first':
ttr.nextSymbol();
return 1;
case 'second':
ttr.nextSymbol();
return ttr.accept('last') ? -2 : 2;
case 'third':
ttr.nextSymbol();
return ttr.accept('last') ? -3 : 3;
case 'nth':
var v = parseInt(ttr.value[1]);
if(v < -366 || v > 366)
throw new Error('Nth out of range: ' + v);
ttr.nextSymbol();
return ttr.accept('last') ? -v : v;
default:
return false;
function decodeWKD () {
switch (ttr.symbol) {
case 'monday':
case 'tuesday':
case 'wednesday':
case 'thursday':
case 'friday':
case 'saturday':
case 'sunday':
return ttr.symbol.substr(0, 2).toUpperCase()
default:
return false
}
}
}
function MDAYs() {
function decodeNTH () {
switch (ttr.symbol) {
case 'last':
ttr.nextSymbol()
return -1
case 'first':
ttr.nextSymbol()
return 1
case 'second':
ttr.nextSymbol()
return ttr.accept('last') ? -2 : 2
case 'third':
ttr.nextSymbol()
return ttr.accept('last') ? -3 : 3
case 'nth':
var v = parseInt(ttr.value[1], 10)
if (v < -366 || v > 366) throw new Error('Nth out of range: ' + v)
ttr.accept('on');
ttr.accept('the');
ttr.nextSymbol()
return ttr.accept('last') ? -v : v
var nth;
if(!(nth = decodeNTH())) {
return;
default:
return false
}
}
options.bymonthday = [nth];
ttr.nextSymbol();
function MDAYs () {
ttr.accept('on')
ttr.accept('the')
while(ttr.accept('comma')) {
var nth
if (!(nth = decodeNTH())) return
if (!(nth = decodeNTH())) {
throw new Error('Unexpected symbol ' + ttr.symbol
+ '; expected monthday');
}
options.bymonthday = [nth]
ttr.nextSymbol()
options.bymonthday.push(nth);
while (ttr.accept('comma')) {
if (!(nth = decodeNTH())) {
throw new Error('Unexpected symbol ' + ttr.symbol + '; expected monthday')
}
ttr.nextSymbol();
options.bymonthday.push(nth)
ttr.nextSymbol()
}
}
}
function F() {
function F () {
if (ttr.symbol === 'until') {
var date = Date.parse(ttr.text)
if(ttr.symbol == 'until') {
var date = Date.parse(ttr.text);
if (!date) {
throw new Error('Cannot parse until date:' + ttr.text);
}
options.until = new Date(date);
} else if(ttr.accept('for')){
options.count = ttr.value[0];
ttr.expect('number');
/* ttr.expect('times') */
if (!date) throw new Error('Cannot parse until date:' + ttr.text)
options.until = new Date(date)
} else if (ttr.accept('for')) {
options.count = ttr.value[0]
ttr.expect('number')
// ttr.expect('times')
}
}
}
};
// =============================================================================
// Parser
// =============================================================================
//=============================================================================
// Parser
//=============================================================================
var Parser = function (rules) {
this.rules = rules
}
var Parser = function(rules) {
this.rules = rules;
};
Parser.prototype.start = function (text) {
this.text = text
this.done = false
return this.nextSymbol()
}
Parser.prototype.start = function(text) {
this.text = text;
this.done = false;
return this.nextSymbol();
};
Parser.prototype.isDone = function () {
return this.done && this.symbol == null
}
Parser.prototype.isDone = function() {
return this.done && this.symbol == null;
};
Parser.prototype.nextSymbol = function () {
var best, bestSymbol
var p = this
Parser.prototype.nextSymbol = function() {
var p = this, best, bestSymbol;
this.symbol = null
this.value = null
do {
if (this.done) return false
this.symbol = null;
this.value = null;
do {
if(this.done) {
return false;
}
var match, rule
best = null
for (var name in this.rules) {
rule = this.rules[name]
if ((match = rule.exec(p.text))) {
if (best == null || match[0].length > best[0].length) {
best = match
bestSymbol = name
}
}
}
best = null;
if (best != null) {
this.text = this.text.substr(best[0].length)
var match, rule;
for (var name in this.rules) {
rule = this.rules[name];
if(match = rule.exec(p.text)) {
if(best == null || match[0].length > best[0].length) {
best = match;
bestSymbol = name;
}
}
if (this.text === '') this.done = true
}
}
if (best == null) {
this.done = true
this.symbol = null
this.value = null
return
}
} while (bestSymbol === 'SKIP')
if(best != null) {
this.text = this.text.substr(best[0].length);
this.symbol = bestSymbol
this.value = best
return true
}
if(this.text == '') {
this.done = true;
}
}
Parser.prototype.accept = function (name) {
if (this.symbol === name) {
if (this.value) {
var v = this.value
this.nextSymbol()
return v
}
if(best == null) {
this.done = true;
this.symbol = null;
this.value = null;
return;
}
} while(bestSymbol == 'SKIP');
this.nextSymbol()
return true
}
this.symbol = bestSymbol;
this.value = best;
return true;
};
return false
}
Parser.prototype.accept = function(name) {
if(this.symbol == name) {
if(this.value) {
var v = this.value;
this.nextSymbol();
return v;
}
Parser.prototype.expect = function (name) {
if (this.accept(name)) return true
this.nextSymbol();
return true;
}
throw new Error('expected ' + name + ' but found ' + this.symbol)
}
return false;
};
// =============================================================================
// i18n
// =============================================================================
Parser.prototype.expect = function(name) {
if(this.accept(name)) {
return true;
}
throw new Error('expected ' + name + ' but found ' + this.symbol);
};
//=============================================================================
// i18n
//=============================================================================
var ENGLISH = {
dayNames: [
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
],
monthNames: [
"January", "February", "March", "April", "May",
"June", "July", "August", "September", "October",
"November", "December"
],
tokens: {
var ENGLISH = {
dayNames: [
'Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday'
],
monthNames: [
'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October',
'November', 'December'
],
tokens: {
'SKIP': /^[ \r\n\t]+|^\.$/,

@@ -1009,5 +938,7 @@ 'number': /^[1-9][0-9]*/,

'week(s)': /^weeks?/i,
'hour(s)': /^hours?/i,
'month(s)': /^months?/i,
'year(s)': /^years?/i,
'on': /^(on|in)/i,
'at': /^(at)/i,
'the': /^the/i,

@@ -1042,32 +973,18 @@ 'first': /^first/i,

'comma': /^(,\s*|(and|or)\s*)+/i
}
}
};
// =============================================================================
// Export
// =============================================================================
//=============================================================================
// Export
//=============================================================================
var nlp = {
fromText: fromText,
parseText: parseText,
isFullyConvertible: ToText.isFullyConvertible,
toText: function(rrule, gettext, language) {
return new ToText(rrule, gettext, language).toString();
return {
fromText: fromText,
parseText: parseText,
isFullyConvertible: ToText.isFullyConvertible,
toText: function (rrule, gettext, language) {
return new ToText(rrule, gettext, language).toString()
}
}
};
if (serverSide) {
module.exports = nlp
} else {
root['_RRuleNLP'] = nlp;
}
if (typeof define === "function" && define.amd) {
/*global define:false */
define("rrule", [], function () {
return RRule;
});
}
})(this);
}
}))
{
"name": "rrule",
"version": "2.1.0",
"description": "JavaScript library for working with recurrence rules for calendar dates.",
"homepage": "http://jakubroztocil.github.io/rrule/",
"keywords":[
"dates",
"recurrences",
"calendar",
"icalendar",
"rfc"
],
"author": "Jakub Roztocil and Lars Schöning",
"main": "lib/rrule",
"repository" :{
"type": "git",
"url": "git://github.com/jakubroztocil/rrule.git"
},
"scripts": {
"test": "echo Run tests in the browser at tests/index.html"
}
"name": "rrule",
"version": "2.2.0",
"description": "JavaScript library for working with recurrence rules for calendar dates.",
"homepage": "http://jakubroztocil.github.io/rrule/",
"keywords": [
"dates",
"recurrences",
"calendar",
"icalendar",
"rfc"
],
"author": "Jakub Roztocil and Lars Schöning",
"main": "lib/rrule",
"repository": {
"type": "git",
"url": "git://github.com/jakubroztocil/rrule.git"
},
"scripts": {
"test": "standard && mocha"
},
"devDependencies": {
"mocha": "^2.3.4",
"standard": "^5.4.1"
},
"standard": {
"ignore": [
"demo"
]
},
"files": [
"lib",
"README.md"
]
}

@@ -6,4 +6,10 @@ rrule.js

[![NPM version][npm-image]][npm-url]
[![Build Status][travis-image]][travis-url]
[![js-standard-style][js-standard-image]][js-standard-url]
[![Downloads][downloads-image]][downloads-url]
rrule.js supports recurrence rules as defined in the [iCalendar
RFC](http://www.ietf.org/rfc/rfc2445.txt). It is a partial port of the
RFC](http://www.ietf.org/rfc/rfc2445.txt), with a few important
[differences](#differences-from-icalendar-rfc). It is a partial port of the
`rrule` module from the excellent

@@ -20,5 +26,3 @@ [python-dateutil](http://labix.org/python-dateutil/) library. On top of

- [Demo app](http://jakubroztocil.github.io/rrule/)
- [Test suite](http://jakubroztocil.github.io/rrule/tests/index.html)
#### Client Side

@@ -49,3 +53,5 @@

```javascript
var RRule = require('rrule').RRule;
var RRule = require('rrule').RRule
var RRuleSet = require('rrule').RRuleSet
var rrulestr = require('rrule').rrulestr
```

@@ -55,14 +61,15 @@

```javascript
**RRule:**
```js
// Create a rule:
var rule = new RRule({
freq: RRule.WEEKLY,
interval: 5,
byweekday: [RRule.MO, RRule.FR],
dtstart: new Date(2012, 1, 1, 10, 30),
until: new Date(2012, 12, 31)
});
freq: RRule.WEEKLY,
interval: 5,
byweekday: [RRule.MO, RRule.FR],
dtstart: new Date(2012, 1, 1, 10, 30),
until: new Date(2012, 12, 31)
})
// Get all occurrence dates (Date instances):
rule.all();
rule.all()
['Fri Feb 03 2012 10:30:00 GMT+0100 (CET)',

@@ -81,3 +88,3 @@ 'Mon Mar 05 2012 10:30:00 GMT+0100 (CET)',

// The output can be used with RRule.fromString().
rule.toString();
rule.toString()
"FREQ=WEEKLY;DTSTART=20120201T093000Z;INTERVAL=5;UNTIL=20130130T230000Z;BYDAY=MO,FR"

@@ -91,5 +98,68 @@

**RRuleSet:**
```js
var rruleSet = new RRuleSet()
// Add a rrule to rruleSet
rruleSet.rrule(new RRule({
freq: RRule.MONTHLY,
count: 5,
dtstart: new Date(2012, 1, 1, 10, 30)
}))
// Add a date to rruleSet
rruleSet.rdate(new Date(2012, 6, 1, 10, 30))
// Add another date to rruleSet
rruleSet.rdate(new Date(2012, 6, 2, 10, 30))
// Add a exclusion rrule to rruleSet
rruleSet.exrule(new r.RRule({
freq: RRule.MONTHLY,
count: 2,
dtstart: new Date(2012, 2, 1, 10, 30)
}))
// Add a exclusion date to rruleSet
rruleSet.exdate(new Date(2012, 5, 1, 10, 30))
// Get all occurrence dates (Date instances):
rruleSet.all()
['Wed Feb 01 2012 10:30:00 GMT+0800 (CST)',
'Tue May 01 2012 10:30:00 GMT+0800 (CST)',
'Sun Jul 01 2012 10:30:00 GMT+0800 (CST)',
'Mon Jul 02 2012 10:30:00 GMT+0800 (CST)']
// Get a slice:
rruleSet.between(new Date(2012, 2, 1), new Date(2012, 6, 2))
['Tue May 01 2012 10:30:00 GMT+0800 (CST)',
'Sun Jul 01 2012 10:30:00 GMT+0800 (CST)']
// To string
rruleSet.valueOf()
['RRULE:FREQ=MONTHLY;COUNT=5;DTSTART=20120201T023000Z',
'RDATE:20120701T023000Z,20120702T023000Z',
'EXRULE:FREQ=MONTHLY;COUNT=2;DTSTART=20120301T023000Z',
'EXDATE:20120601T023000Z']
// To string
rruleSet.toString()
'["RRULE:FREQ=MONTHLY;COUNT=5;DTSTART=20120201T023000Z","RDATE:20120701T023000Z,20120702T023000Z","EXRULE:FREQ=MONTHLY;COUNT=2;DTSTART=20120301T023000Z","EXDATE:20120601T023000Z"]'
```
**rrulestr:**
```js
// Parse a RRule string, return a RRule object
rrulestr('RRULE:FREQ=MONTHLY;COUNT=5;DTSTART=20120201T023000Z')
// Parse a RRule string, return a RRuleSet object
rrulestr('RRULE:FREQ=MONTHLY;COUNT=5;DTSTART=20120201T023000Z', {forceset: true})
// Parse a RRuleSet string, return a RRuleSet object
rrulestr('RRULE:FREQ=MONTHLY;COUNT=5;DTSTART=20120201T023000Z\nRDATE:20120701T023000Z,20120702T023000Z\nEXRULE:FREQ=MONTHLY;COUNT=2;DTSTART=20120301T023000Z\nEXDATE:20120601T023000Z')
```
For more examples see
[tests/tests.js](https://github.com/jakubroztocil/rrule/blob/master/tests/tests.js)
and [python-dateutil](http://labix.org/python-dateutil/) documentation.
[python-dateutil](http://labix.org/python-dateutil/) documentation.

@@ -314,3 +384,3 @@ ### API

rule.all(function (date, i){return i < 2});
rule.all(function (date, i){return i < 2})
['Fri Feb 03 2012 10:30:00 GMT+0100 (CET)',

@@ -362,6 +432,6 @@ 'Mon Mar 05 2012 10:30:00 GMT+0100 (CET)',]

Returns a string representation of the rule as per the iCalendar RFC.
Only properties explicitely specified in `options` are included:
Only properties explicitly specified in `options` are included:
```javascript
rule.toString();
rule.toString()
"FREQ=WEEKLY;DTSTART=20120201T093000Z;INTERVAL=5;UNTIL=20130130T230000Z;BYDAY=MO,FR"

@@ -385,4 +455,4 @@

RRule.optionsToString({
freq: rule.options.freq,
dtstart: rule.options.dtstart,
freq: rule.options.freq,
dtstart: rule.options.dtstart
})

@@ -464,8 +534,142 @@ "FREQ=WEEKLY;DTSTART=20120201T093000Z"

* * * * *
#### `RRuleSet` Constructor
```javascript
new RRuleSet([noCache=false])
```
The RRuleSet instance allows more complex recurrence setups, mixing multiple
rules, dates, exclusion rules, and exclusion dates.
Default `noCache` argument is `false`, caching of results will be enabled,
improving performance of multiple queries considerably.
##### `RRuleSet.prototype.rrule(rrule)`
Include the given rrule instance in the recurrence set generation.
##### `RRuleSet.prototype.rdate(dt)`
Include the given datetime instance in the recurrence set generation.
##### `RRuleSet.prototype.exrule(rrule)`
Include the given rrule instance in the recurrence set exclusion list. Dates
which are part of the given recurrence rules will not be generated, even if
some inclusive rrule or rdate matches them.
##### `RRuleSet.prototype.exdate(dt)`
Include the given datetime instance in the recurrence set exclusion list. Dates
included that way will not be generated, even if some inclusive rrule or
rdate matches them.
##### `RRuleSet.prototype.all([iterator])`
Same as `RRule.prototype.all`.
##### `RRuleSet.prototype.between(after, before, inc=false [, iterator])`
Same as `RRule.prototype.between`.
##### `RRuleSet.prototype.before(dt, inc=false)`
Same as `RRule.prototype.before`.
##### `RRuleSet.prototype.after(dt, inc=false)`
Same as `RRule.prototype.after`.
* * * * *
#### `rrulestr` Function
```js
rrulestr(rruleStr[, options])
```
The `rrulestr` function is a parser for RFC-like syntaxes. The string passed
as parameter may be a multiple line string, a single line string, or just the
RRULE property value.
Additionally, it accepts the following keyword arguments:
`cache`
If True, the rruleset or rrule created instance will cache its results.
Default is not to cache.
`dtstart`
If given, it must be a datetime instance that will be used when no DTSTART
property is found in the parsed string. If it is not given, and the property
is not found, datetime.now() will be used instead.
`unfold`
If set to True, lines will be unfolded following the RFC specification. It
defaults to False, meaning that spaces before every line will be stripped.
`forceset`
If set to True a rruleset instance will be returned, even if only a single rule
is found. The default is to return an rrule if possible, and an rruleset if necessary.
`compatible`
If set to True, the parser will operate in RFC-compatible mode. Right now it
means that unfold will be turned on, and if a DTSTART is found, it will be
considered the first recurrence instance, as documented in the RFC.
`ignoretz`
If set to True, the date parser will ignore timezone information available in
the DTSTART property, or the UNTIL attribute.
`tzinfos`
If set, it will be passed to the datetime string parser to resolve unknown
timezone settings. For more information about what could be used here, check
the parser documentation.
* * * * *
### Differences From iCalendar RFC
* `RRule` has no `byday` keyword. The equivalent keyword has been replaced by
the `byweekday` keyword, to remove the ambiguity present in the original
keyword.
* Unlike documented in the RFC, the starting datetime, `dtstart`, is
not the first recurrence instance, unless it does fit in the specified rules.
This is in part due to this project being a port of
[python-dateutil](https://labix.org/python-dateutil#head-a65103993a21b717f6702063f3717e6e75b4ba66),
which has the same non-compliant functionality. Note that you can get the
original behavior by using a `RRuleSet` and adding the `dtstart` as an `rdate`.
```javascript
var rruleSet = new RRuleSet()
var start = new Date(2012, 1, 1, 10, 30)
// Add a rrule to rruleSet
rruleSet.rrule(new RRule({
freq: RRule.MONTHLY,
count: 5,
dtstart: start
}))
// Add a date to rruleSet
rruleSet.rdate(start)
```
* Unlike documented in the RFC, every keyword is valid on every frequency (the
RFC documents that `byweekno` is only valid on yearly frequencies, for example).
### Development
rrule.js use [JavaScript Standard Style](https://github.com/feross/standard) coding style.
### Changelog
* 2.2.0-dev
* Added support `RRuleSet`, which allows more complex recurrence setups,
mixing multiple rules, dates, exclusion rules, and exclusion dates.
* Added Millisecond precision
* Millisecond offset extracted from `dtstart` (`dtstart.getTime() % 1000`)
* Each recurrence is returned with the same offset
* Added some NLP support for hourly and byhour.
* Fixed export in nlp.js.
* 2.1.0
* Removed dependency on Underscore.js (thanks @gsf).
* Removed dependency on Underscore.js (thanks, @gsf).
* Various small bugfixes and improvements.

@@ -484,3 +688,3 @@ * 2.0.1

(never actually used).
* `rule.toString()` now includes `DTSTART` (if explicitely specified
* `rule.toString()` now includes `DTSTART` (if explicitly specified
in `options`).

@@ -507,3 +711,3 @@ * Day constants `.clone` is now `.nth`, eg. `RRule.FR.nth(-1)`

* [Jakub Roztocil](http://subtleapps.com/)
* [Jakub Roztocil](http://roztocil.co/)
([@jakubroztocil](http://twitter.com/jakubroztocil))

@@ -517,1 +721,13 @@ * Lars Schöning ([@lyschoening](http://twitter.com/lyschoening))

more details.
[npm-url]: https://npmjs.org/package/rrule
[npm-image]: http://img.shields.io/npm/v/rrule.svg
[travis-url]: https://travis-ci.org/jakubroztocil/rrule
[travis-image]: http://img.shields.io/travis/jakubroztocil/rrule.svg
[downloads-url]: https://npmjs.org/package/rrule
[downloads-image]: http://img.shields.io/npm/dm/rrule.svg?style=flat-square
[js-standard-url]: https://github.com/feross/standard
[js-standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc