elliptical-datetime
Version:
Elliptical phrases to handle natural language dates and times
593 lines (530 loc) • 16.8 kB
JavaScript
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' })
)
);
}
};