iterset.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import IterResult from './iterresult'
  2. import { RRule } from './rrule'
  3. import { DateWithZone } from './datewithzone'
  4. import { iter } from './iter'
  5. import { sort } from './dateutil'
  6. import { QueryMethodTypes, IterResultType } from './types'
  7. export function iterSet<M extends QueryMethodTypes>(
  8. iterResult: IterResult<M>,
  9. _rrule: RRule[],
  10. _exrule: RRule[],
  11. _rdate: Date[],
  12. _exdate: Date[],
  13. tzid: string | undefined
  14. ) {
  15. const _exdateHash: { [k: number]: boolean } = {}
  16. const _accept = iterResult.accept
  17. function evalExdate(after: Date, before: Date) {
  18. _exrule.forEach(function (rrule) {
  19. rrule.between(after, before, true).forEach(function (date) {
  20. _exdateHash[Number(date)] = true
  21. })
  22. })
  23. }
  24. _exdate.forEach(function (date) {
  25. const zonedDate = new DateWithZone(date, tzid).rezonedDate()
  26. _exdateHash[Number(zonedDate)] = true
  27. })
  28. iterResult.accept = function (date) {
  29. const dt = Number(date)
  30. if (isNaN(dt)) return _accept.call(this, date)
  31. if (!_exdateHash[dt]) {
  32. evalExdate(new Date(dt - 1), new Date(dt + 1))
  33. if (!_exdateHash[dt]) {
  34. _exdateHash[dt] = true
  35. return _accept.call(this, date)
  36. }
  37. }
  38. return true
  39. }
  40. if (iterResult.method === 'between') {
  41. evalExdate(iterResult.args.after, iterResult.args.before)
  42. iterResult.accept = function (date) {
  43. const dt = Number(date)
  44. if (!_exdateHash[dt]) {
  45. _exdateHash[dt] = true
  46. return _accept.call(this, date)
  47. }
  48. return true
  49. }
  50. }
  51. for (let i = 0; i < _rdate.length; i++) {
  52. const zonedDate = new DateWithZone(_rdate[i], tzid).rezonedDate()
  53. if (!iterResult.accept(new Date(zonedDate.getTime()))) break
  54. }
  55. _rrule.forEach(function (rrule) {
  56. iter(iterResult, rrule.options)
  57. })
  58. const res = iterResult._result
  59. sort(res)
  60. switch (iterResult.method) {
  61. case 'all':
  62. case 'between':
  63. return res as IterResultType<M>
  64. case 'before':
  65. return ((res.length && res[res.length - 1]) || null) as IterResultType<M>
  66. case 'after':
  67. default:
  68. return ((res.length && res[0]) || null) as IterResultType<M>
  69. }
  70. }