UNPKG

elliptical-datetime

Version:

Elliptical phrases to handle natural language dates and times

593 lines (530 loc) 16.8 kB
import _defineProperty from 'babel-runtime/helpers/defineProperty'; import _regeneratorRuntime from 'babel-runtime/regenerator'; var _marked = [mapDate].map(_regeneratorRuntime.mark); /** @jsx createElement */ import _ from 'lodash'; import { createElement } from 'elliptical'; import moment from 'moment'; import { DateDuration } from './duration'; import { DigitString, Integer, Ordinal } from 'elliptical-number'; import { TimeOfDay } from './time'; import { Month } from './month'; import { Year } from './year'; import { Weekday } from './weekday'; import { absoluteDate, join, negateDuration, relativeDate, relativeDay, validateDay, possibleDates } from './helpers'; export var InternalDay = { defaultProps: { recurse: true, label: 'day' }, describe: function describe(_ref) { var props = _ref.props; if (props.nullify) return; return createElement( 'choice', null, props.recurse ? createElement( 'placeholder', { label: props.label, arguments: props.phraseArguments || (props.phraseArguments ? [props.phraseArgument] : [props.label]) }, createElement(RecursiveDay, { label: props.label }) ) : null, createElement( 'sequence', null, props.prepositions ? createElement('literal', { text: 'on ', decorate: true }) : null, createElement( 'placeholder', { label: props.label, arguments: props.phraseArguments || (props.phraseArguments ? [props.phraseArgument] : [props.label]), merge: true }, createElement( 'choice', null, createElement(DayAlone, null), createElement(AmbiguousAbsoluteDay, null), createElement(AmbiguousAbsoluteNamedMonth, null) ) ) ) ); } }; export var Day = { id: 'elliptical-datetime:Day', defaultProps: { recurse: true, label: 'day' }, describe: function describe(_ref2) { var props = _ref2.props; return createElement(InternalDay, props); } }; function mapDate(option) { var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, result; return _regeneratorRuntime.wrap(function mapDate$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _iteratorNormalCompletion = true; _didIteratorError = false; _iteratorError = undefined; _context.prev = 3; _iterator = possibleDates(option.result)[Symbol.iterator](); case 5: if (_iteratorNormalCompletion = (_step = _iterator.next()).done) { _context.next = 12; break; } result = _step.value; _context.next = 9; return _.assign({}, option, { result: result }); case 9: _iteratorNormalCompletion = true; _context.next = 5; break; case 12: _context.next = 18; break; case 14: _context.prev = 14; _context.t0 = _context['catch'](3); _didIteratorError = true; _iteratorError = _context.t0; case 18: _context.prev = 18; _context.prev = 19; if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } case 21: _context.prev = 21; if (!_didIteratorError) { _context.next = 24; break; } throw _iteratorError; case 24: return _context.finish(21); case 25: return _context.finish(18); case 26: case 'end': return _context.stop(); } } }, _marked[0], this, [[3, 14, 18, 26], [19,, 21, 25]]); } export var Date = { id: 'elliptical-datetime:Date', defaultProps: { recurse: true, prepositions: false, nullify: false, past: true, future: true, label: 'date' }, filterResult: function filterResult(result, _ref3) { var props = _ref3.props; if (!props.past && moment(result).isBefore(moment())) { return false; } if (!props.future && moment(result).isAfter(moment())) { return false; } // if (result._ambiguousMonth) { // return false // } return true; }, describe: function describe(_ref4) { var props = _ref4.props; return createElement( 'map', { outbound: mapDate, skipIncomplete: true, limit: 1 }, createElement(InternalDate, props) ); } }; export var InternalDate = { defaultProps: { recurse: true, prepositions: false, nullify: false, past: true, future: true, label: 'date' }, describe: function describe(_ref5) { var props = _ref5.props; if (props.nullify) return; return createElement( 'choice', null, createElement( 'placeholder', { label: props.label, arguments: props.phraseArguments || (props.phraseArguments ? [props.phraseArgument] : [props.label]) }, createElement( 'choice', null, createElement(RelativeNamed, null), createElement(RelativeNumbered, { prepositions: props.prepositions }), createElement(DayWithYear, { prepositions: props.prepositions }), createElement(RelativeAdjacent, null), props.recurse ? createElement(RecursiveDate, { label: props.label }) : null ) ), createElement( 'sequence', null, props.prepositions ? createElement('literal', { text: 'on ', decorate: true }) : null, createElement( 'placeholder', { label: props.label, arguments: props.phraseArguments || (props.phraseArguments ? [props.phraseArgument] : [props.label]), merge: true }, createElement( 'choice', null, createElement(RelativeWeekday, null), createElement(AbsoluteDay, null) ) ) ) ); } }; var DayWithYear = { mapResult: function mapResult(result) { var day = result.day; var year = result.year; if (year) { var date = absoluteDate(_.assign({ year: year.year }, day)); return { date: date, _ambiguousCentury: year._ambiguousCentury }; } else { return { date: absoluteDate(day), _ambiguousMonth: day._ambiguousMonth, _ambiguousYear: true }; } }, describe: function describe(_ref6) { var props = _ref6.props; return createElement( 'sequence', null, createElement(Day, { prepositions: props.prepositions, id: 'day', recurse: false, ellipsis: true }), createElement( 'sequence', { merge: true }, createElement('list', { items: [', ', ' in ', ' '], limit: 1 }), createElement(Year, { id: 'year' }) ) ); } }; var ExtraDateDuration = { mapResult: function mapResult(result) { return _defineProperty({}, result.type, result.multiplier || 1); }, describe: function describe() { return createElement( 'sequence', null, createElement( 'placeholder', { label: 'number' }, createElement('literal', { text: 'the ' }) ), createElement( 'placeholder', { label: 'time period', merge: true }, createElement('list', { items: [{ text: 'day', value: { type: 'days' } }, { text: 'fortnight', value: { type: 'days', multiplier: 14 } }, { text: 'week', value: { type: 'days', multiplier: 7 } }, { text: 'month', value: { type: 'months' } }, { text: 'year', value: { type: 'years' } }] }) ) ); } }; var RecursiveDay = { mapResult: function mapResult(result) { var duration = result.direction === -1 ? negateDuration(result.duration) : result.duration; return relativeDay(duration, result.day); }, describe: function describe(_ref8) { var props = _ref8.props; return createElement( 'sequence', null, createElement( 'placeholder', { label: 'offset', merge: true }, createElement( 'sequence', null, createElement( 'choice', { id: 'duration' }, createElement(ExtraDateDuration, null), createElement(DateDuration, null) ), createElement('list', { merge: true, id: 'direction', items: [{ text: ' before', value: -1 }, { text: ' after', value: 1 }, { text: ' from', value: 1 }], limit: 2 }) ) ), createElement('literal', { text: ' ' }), createElement( 'placeholder', { label: 'day', id: 'day' }, createElement(Day, { recurse: false, prepositions: false, label: props.label }) ) ); } }; var RecursiveDate = { mapResult: function mapResult(result) { var duration = result.direction === -1 ? negateDuration(result.duration) : result.duration; return _.assign({}, result.date, { date: relativeDate(duration, result.date.date) }); }, describe: function describe(_ref9) { var props = _ref9.props; return createElement( 'sequence', null, createElement( 'placeholder', { label: 'offset', merge: true }, createElement( 'sequence', null, createElement( 'choice', { id: 'duration' }, createElement(ExtraDateDuration, null), createElement(DateDuration, null) ), createElement('list', { merge: true, id: 'direction', items: [{ text: ' before', value: -1 }, { text: ' after', value: 1 }, { text: ' from', value: 1 }], limit: 2 }) ) ), createElement('literal', { text: ' ' }), createElement(InternalDate, { id: 'date', label: props.label, recurse: false, prepositions: false }) ); } }; var RelativeNamed = { mapResult: function mapResult(result) { return { date: relativeDate(result) }; }, describe: function describe() { return createElement('list', { items: [{ text: 'today', value: { days: 0 } }, { text: 'tomorrow', value: { days: 1 } }, { text: 'yesterday', value: { days: -1 } }, { text: 'now', value: { days: 0 } }, { text: 'right now', value: { days: 0 } }], limit: 3 }); } }; var RelativeNumbered = { mapResult: function mapResult(result) { var duration = result.direction === -1 ? negateDuration(result.duration) : result.duration; return { date: relativeDate(duration) }; }, describe: function describe(_ref10) { var props = _ref10.props; return createElement( 'choice', null, props.prepositions ? createElement( 'sequence', null, createElement('literal', { text: 'in ', id: 'direction', value: 1 }), createElement(DateDuration, { id: 'duration' }) ) : null, createElement( 'sequence', null, createElement(DateDuration, { id: 'duration' }), createElement('literal', { text: ' ago', id: 'direction', value: -1 }) ) ); } }; var RelativeAdjacent = { mapResult: function mapResult(result) { var duration = _defineProperty({}, result.type, result.num * (result.multiplier || 1)); return { date: relativeDate(duration) }; }, describe: function describe() { return createElement( 'placeholder', { label: 'time period' }, createElement( 'sequence', null, createElement('list', { id: 'num', items: [{ text: 'next ', value: 1 }, { text: 'last ', value: -1 }] }), createElement( 'placeholder', { label: 'time period', merge: true }, createElement('list', { items: [{ text: 'week', value: { type: 'days', multiplier: 7 } }, { text: 'month', value: { type: 'months' } }, { text: 'year', value: { type: 'years' } }] }) ) ) ); } }; function dateFromRelative(distance, weekday) { var day = distance * 7 + weekday; return moment().day(day).toDate(); } var RelativeWeekday = { mapResult: function mapResult(result) { var date = dateFromRelative(result.distance || 0, result.weekday); if (result.distance == null) { return { date: date, _ambiguousWeek: true }; } else { return { date: date }; } }, describe: function describe() { return createElement( 'choice', null, createElement( 'sequence', null, createElement('list', { optional: true, id: 'distance', items: [{ text: 'last ', value: -1 }, { text: 'this ', value: 0 }, { text: 'next ', value: 1 }, { text: 'this upcoming ', value: 1 }], limit: 1 }), createElement(Weekday, { id: 'weekday' }) ), createElement( 'sequence', null, createElement('literal', { text: 'the ' }), createElement( 'placeholder', { label: 'relative weekday', merge: true }, createElement( 'sequence', null, createElement(Weekday, { id: 'weekday' }), createElement('list', { id: 'distance', items: [{ text: ' after next', value: 2 }, { text: ' after this', value: 1 }, { text: ' before this', value: -1 }, { text: ' before last', value: -2 }] }) ) ) ) ); } }; function leapYear(year) { return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; } var MonthNumber = { mapResult: function mapResult(result) { return parseInt(result, 10) - 1; }, describe: function describe() { return createElement(DigitString, { maxLength: 2, max: 12, min: 1, label: 'mm' }); } }; var DayNumber = { mapResult: function mapResult(result) { return parseInt(result, 10); }, describe: function describe() { return createElement(DigitString, { maxLength: 2, max: 31, min: 1, label: 'dd' }); } }; var AbsoluteDay = { mapResult: function mapResult(result) { var date = absoluteDate(_.assign({}, result, { year: result.year.year })); return { date: date, _ambiguousCentury: result.year._ambiguousCentury }; }, filterResult: function filterResult(result) { var years = result._ambiguousCentury ? [0, 100, -100] : [0]; return _.some(years, function (year) { var date = _.assign({}, result, { year: result.date.getFullYear() + year }); return validateDay(date); }); }, describe: function describe() { return createElement( 'sequence', null, createElement(AmbiguousAbsoluteDay, { merge: true }), createElement('list', { items: ['/'], limit: 1 }), createElement(Year, { id: 'year' }) ); } }; var DayAlone = { mapResult: function mapResult(result) { return { month: moment().month(), day: result, _ambiguousMonth: true }; }, describe: function describe() { return createElement( 'sequence', null, createElement('literal', { text: 'the ', optional: true, preferred: true, limited: true }), createElement( 'choice', { limit: 1, merge: true }, createElement(Integer, { allowWordForm: true, max: 31, min: 1, limit: 1, allowLeadingZero: false }), createElement(Ordinal, { allowWordForm: true, max: 31, limit: 1 }) ) ); } }; var AmbiguousAbsoluteDay = { describe: function describe() { return createElement( 'filter', { 'function': validateDay }, createElement( 'sequence', null, createElement(MonthNumber, { id: 'month' }), createElement('list', { items: ['/'], limit: 1 }), createElement(DayNumber, { id: 'day' }) ) ); } }; var AmbiguousAbsoluteNamedMonth = { filterResult: function filterResult(result) { return validateDay(result); }, describe: function describe() { return createElement( 'choice', null, createElement( 'sequence', null, createElement(Month, { id: 'month' }), createElement('list', { items: [' ', ' the '], limit: 1 }), createElement( 'choice', { id: 'day', limit: 1 }, createElement(Integer, { allowWordForm: true, max: 31, min: 1, limit: 1 }), createElement(Ordinal, { allowWordForm: true, max: 31, limit: 1 }) ) ), createElement( 'sequence', null, createElement('literal', { text: 'the ' }), createElement( 'choice', { id: 'day', limit: 1 }, createElement(Integer, { allowWordForm: true, max: 31, min: 1, limit: 1 }), createElement(Ordinal, { allowWordForm: true, max: 31, limit: 1 }) ), createElement('list', { items: [' of ', ' '], limit: 1 }), createElement(Month, { id: 'month' }) ) ); } };