UNPKG

elliptical-datetime

Version:

Elliptical phrases to handle natural language dates and times

531 lines (470 loc) 16.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.InternalDate = exports.Date = exports.Day = exports.InternalDay = undefined; var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _elliptical = require('elliptical'); var _moment = require('moment'); var _moment2 = _interopRequireDefault(_moment); var _duration = require('./duration'); var _ellipticalNumber = require('elliptical-number'); var _time = require('./time'); var _month = require('./month'); var _year = require('./year'); var _weekday = require('./weekday'); var _helpers = require('./helpers'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** @jsx createElement */ const InternalDay = exports.InternalDay = { defaultProps: { recurse: true, label: 'day' }, describe({ props }) { if (props.nullify) return; return (0, _elliptical.createElement)( 'choice', null, props.recurse ? (0, _elliptical.createElement)( 'placeholder', { label: props.label, arguments: props.phraseArguments || (props.phraseArguments ? [props.phraseArgument] : [props.label]) }, (0, _elliptical.createElement)(RecursiveDay, { label: props.label }) ) : null, (0, _elliptical.createElement)( 'sequence', null, props.prepositions ? (0, _elliptical.createElement)('literal', { text: 'on ', decorate: true }) : null, (0, _elliptical.createElement)( 'placeholder', { label: props.label, arguments: props.phraseArguments || (props.phraseArguments ? [props.phraseArgument] : [props.label]), merge: true }, (0, _elliptical.createElement)( 'choice', null, (0, _elliptical.createElement)(DayAlone, null), (0, _elliptical.createElement)(AmbiguousAbsoluteDay, null), (0, _elliptical.createElement)(AmbiguousAbsoluteNamedMonth, null) ) ) ) ); } }; const Day = exports.Day = { id: 'elliptical-datetime:Day', defaultProps: { recurse: true, label: 'day' }, describe({ props }) { return (0, _elliptical.createElement)(InternalDay, props); } }; function* mapDate(option) { for (let result of (0, _helpers.possibleDates)(option.result)) { yield _lodash2.default.assign({}, option, { result }); } } const Date = exports.Date = { id: 'elliptical-datetime:Date', defaultProps: { recurse: true, prepositions: false, nullify: false, past: true, future: true, label: 'date' }, filterResult(result, { props }) { if (!props.past && (0, _moment2.default)(result).isBefore((0, _moment2.default)())) { return false; } if (!props.future && (0, _moment2.default)(result).isAfter((0, _moment2.default)())) { return false; } // if (result._ambiguousMonth) { // return false // } return true; }, describe({ props }) { return (0, _elliptical.createElement)( 'map', { outbound: mapDate, skipIncomplete: true, limit: 1 }, (0, _elliptical.createElement)(InternalDate, props) ); } }; const InternalDate = exports.InternalDate = { defaultProps: { recurse: true, prepositions: false, nullify: false, past: true, future: true, label: 'date' }, describe({ props }) { if (props.nullify) return; return (0, _elliptical.createElement)( 'choice', null, (0, _elliptical.createElement)( 'placeholder', { label: props.label, arguments: props.phraseArguments || (props.phraseArguments ? [props.phraseArgument] : [props.label]) }, (0, _elliptical.createElement)( 'choice', null, (0, _elliptical.createElement)(RelativeNamed, null), (0, _elliptical.createElement)(RelativeNumbered, { prepositions: props.prepositions }), (0, _elliptical.createElement)(DayWithYear, { prepositions: props.prepositions }), (0, _elliptical.createElement)(RelativeAdjacent, null), props.recurse ? (0, _elliptical.createElement)(RecursiveDate, { label: props.label }) : null ) ), (0, _elliptical.createElement)( 'sequence', null, props.prepositions ? (0, _elliptical.createElement)('literal', { text: 'on ', decorate: true }) : null, (0, _elliptical.createElement)( 'placeholder', { label: props.label, arguments: props.phraseArguments || (props.phraseArguments ? [props.phraseArgument] : [props.label]), merge: true }, (0, _elliptical.createElement)( 'choice', null, (0, _elliptical.createElement)(RelativeWeekday, null), (0, _elliptical.createElement)(AbsoluteDay, null) ) ) ) ); } }; const DayWithYear = { mapResult(result) { const day = result.day; const year = result.year; if (year) { const date = (0, _helpers.absoluteDate)(_lodash2.default.assign({ year: year.year }, day)); return { date, _ambiguousCentury: year._ambiguousCentury }; } else { return { date: (0, _helpers.absoluteDate)(day), _ambiguousMonth: day._ambiguousMonth, _ambiguousYear: true }; } }, describe({ props }) { return (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)(Day, { prepositions: props.prepositions, id: 'day', recurse: false, ellipsis: true }), (0, _elliptical.createElement)( 'sequence', { merge: true }, (0, _elliptical.createElement)('list', { items: [', ', ' in ', ' '], limit: 1 }), (0, _elliptical.createElement)(_year.Year, { id: 'year' }) ) ); } }; const ExtraDateDuration = { mapResult(result) { return { [result.type]: result.multiplier || 1 }; }, describe() { return (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)( 'placeholder', { label: 'number' }, (0, _elliptical.createElement)('literal', { text: 'the ' }) ), (0, _elliptical.createElement)( 'placeholder', { label: 'time period', merge: true }, (0, _elliptical.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' } }] }) ) ); } }; const RecursiveDay = { mapResult(result) { const duration = result.direction === -1 ? (0, _helpers.negateDuration)(result.duration) : result.duration; return (0, _helpers.relativeDay)(duration, result.day); }, describe({ props }) { return (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)( 'placeholder', { label: 'offset', merge: true }, (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)( 'choice', { id: 'duration' }, (0, _elliptical.createElement)(ExtraDateDuration, null), (0, _elliptical.createElement)(_duration.DateDuration, null) ), (0, _elliptical.createElement)('list', { merge: true, id: 'direction', items: [{ text: ' before', value: -1 }, { text: ' after', value: 1 }, { text: ' from', value: 1 }], limit: 2 }) ) ), (0, _elliptical.createElement)('literal', { text: ' ' }), (0, _elliptical.createElement)( 'placeholder', { label: 'day', id: 'day' }, (0, _elliptical.createElement)(Day, { recurse: false, prepositions: false, label: props.label }) ) ); } }; const RecursiveDate = { mapResult(result) { const duration = result.direction === -1 ? (0, _helpers.negateDuration)(result.duration) : result.duration; return _lodash2.default.assign({}, result.date, { date: (0, _helpers.relativeDate)(duration, result.date.date) }); }, describe({ props }) { return (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)( 'placeholder', { label: 'offset', merge: true }, (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)( 'choice', { id: 'duration' }, (0, _elliptical.createElement)(ExtraDateDuration, null), (0, _elliptical.createElement)(_duration.DateDuration, null) ), (0, _elliptical.createElement)('list', { merge: true, id: 'direction', items: [{ text: ' before', value: -1 }, { text: ' after', value: 1 }, { text: ' from', value: 1 }], limit: 2 }) ) ), (0, _elliptical.createElement)('literal', { text: ' ' }), (0, _elliptical.createElement)(InternalDate, { id: 'date', label: props.label, recurse: false, prepositions: false }) ); } }; const RelativeNamed = { mapResult(result) { return { date: (0, _helpers.relativeDate)(result) }; }, describe() { return (0, _elliptical.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 }); } }; const RelativeNumbered = { mapResult(result) { const duration = result.direction === -1 ? (0, _helpers.negateDuration)(result.duration) : result.duration; return { date: (0, _helpers.relativeDate)(duration) }; }, describe({ props }) { return (0, _elliptical.createElement)( 'choice', null, props.prepositions ? (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)('literal', { text: 'in ', id: 'direction', value: 1 }), (0, _elliptical.createElement)(_duration.DateDuration, { id: 'duration' }) ) : null, (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)(_duration.DateDuration, { id: 'duration' }), (0, _elliptical.createElement)('literal', { text: ' ago', id: 'direction', value: -1 }) ) ); } }; const RelativeAdjacent = { mapResult(result) { const duration = { [result.type]: result.num * (result.multiplier || 1) }; return { date: (0, _helpers.relativeDate)(duration) }; }, describe() { return (0, _elliptical.createElement)( 'placeholder', { label: 'time period' }, (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)('list', { id: 'num', items: [{ text: 'next ', value: 1 }, { text: 'last ', value: -1 }] }), (0, _elliptical.createElement)( 'placeholder', { label: 'time period', merge: true }, (0, _elliptical.createElement)('list', { items: [{ text: 'week', value: { type: 'days', multiplier: 7 } }, { text: 'month', value: { type: 'months' } }, { text: 'year', value: { type: 'years' } }] }) ) ) ); } }; function dateFromRelative(distance, weekday) { const day = distance * 7 + weekday; return (0, _moment2.default)().day(day).toDate(); } const RelativeWeekday = { mapResult(result) { const date = dateFromRelative(result.distance || 0, result.weekday); if (result.distance == null) { return { date, _ambiguousWeek: true }; } else { return { date }; } }, describe() { return (0, _elliptical.createElement)( 'choice', null, (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.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 }), (0, _elliptical.createElement)(_weekday.Weekday, { id: 'weekday' }) ), (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)('literal', { text: 'the ' }), (0, _elliptical.createElement)( 'placeholder', { label: 'relative weekday', merge: true }, (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)(_weekday.Weekday, { id: 'weekday' }), (0, _elliptical.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; } const MonthNumber = { mapResult: result => parseInt(result, 10) - 1, describe: () => (0, _elliptical.createElement)(_ellipticalNumber.DigitString, { maxLength: 2, max: 12, min: 1, label: 'mm' }) }; const DayNumber = { mapResult: result => parseInt(result, 10), describe: () => (0, _elliptical.createElement)(_ellipticalNumber.DigitString, { maxLength: 2, max: 31, min: 1, label: 'dd' }) }; const AbsoluteDay = { mapResult(result) { const date = (0, _helpers.absoluteDate)(_lodash2.default.assign({}, result, { year: result.year.year })); return { date, _ambiguousCentury: result.year._ambiguousCentury }; }, filterResult(result) { let years = result._ambiguousCentury ? [0, 100, -100] : [0]; return _lodash2.default.some(years, year => { const date = _lodash2.default.assign({}, result, { year: result.date.getFullYear() + year }); return (0, _helpers.validateDay)(date); }); }, describe() { return (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)(AmbiguousAbsoluteDay, { merge: true }), (0, _elliptical.createElement)('list', { items: ['/'], limit: 1 }), (0, _elliptical.createElement)(_year.Year, { id: 'year' }) ); } }; const DayAlone = { mapResult(result) { return { month: (0, _moment2.default)().month(), day: result, _ambiguousMonth: true }; }, describe() { return (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)('literal', { text: 'the ', optional: true, preferred: true, limited: true }), (0, _elliptical.createElement)( 'choice', { limit: 1, merge: true }, (0, _elliptical.createElement)(_ellipticalNumber.Integer, { allowWordForm: true, max: 31, min: 1, limit: 1, allowLeadingZero: false }), (0, _elliptical.createElement)(_ellipticalNumber.Ordinal, { allowWordForm: true, max: 31, limit: 1 }) ) ); } }; const AmbiguousAbsoluteDay = { describe() { return (0, _elliptical.createElement)( 'filter', { 'function': _helpers.validateDay }, (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)(MonthNumber, { id: 'month' }), (0, _elliptical.createElement)('list', { items: ['/'], limit: 1 }), (0, _elliptical.createElement)(DayNumber, { id: 'day' }) ) ); } }; const AmbiguousAbsoluteNamedMonth = { filterResult(result) { return (0, _helpers.validateDay)(result); }, describe() { return (0, _elliptical.createElement)( 'choice', null, (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)(_month.Month, { id: 'month' }), (0, _elliptical.createElement)('list', { items: [' ', ' the '], limit: 1 }), (0, _elliptical.createElement)( 'choice', { id: 'day', limit: 1 }, (0, _elliptical.createElement)(_ellipticalNumber.Integer, { allowWordForm: true, max: 31, min: 1, limit: 1 }), (0, _elliptical.createElement)(_ellipticalNumber.Ordinal, { allowWordForm: true, max: 31, limit: 1 }) ) ), (0, _elliptical.createElement)( 'sequence', null, (0, _elliptical.createElement)('literal', { text: 'the ' }), (0, _elliptical.createElement)( 'choice', { id: 'day', limit: 1 }, (0, _elliptical.createElement)(_ellipticalNumber.Integer, { allowWordForm: true, max: 31, min: 1, limit: 1 }), (0, _elliptical.createElement)(_ellipticalNumber.Ordinal, { allowWordForm: true, max: 31, limit: 1 }) ), (0, _elliptical.createElement)('list', { items: [' of ', ' '], limit: 1 }), (0, _elliptical.createElement)(_month.Month, { id: 'month' }) ) ); } };