@kermank/nldp
Version:
A modular date/time parser for converting natural language into dates and times
114 lines • 4.96 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ordinalWeeksRule = void 0;
const luxon_1 = require("luxon");
const MONTHS = {
january: 1, february: 2, march: 3, april: 4, may: 5, june: 6,
july: 7, august: 8, september: 9, october: 10, november: 11, december: 12
};
function getWeekRange(date, weekStartsOn = 1) {
// Convert Luxon's weekday (1-7, Monday=1) to 0-6 format relative to weekStartsOn
const weekday = ((date.weekday % 7) - weekStartsOn + 7) % 7;
const start = date.minus({ days: weekday }).startOf('day');
const end = start.plus({ days: 6 }).endOf('day');
return { start, end };
}
function findNthWeekOfMonth(year, month, n, weekStartsOn = 1) {
const firstDayOfMonth = luxon_1.DateTime.utc(year, month, 1);
const lastDayOfMonth = firstDayOfMonth.endOf('month');
// Convert Luxon's weekday (1-7, Monday=1) to 0-6 format relative to weekStartsOn
// For weekStartsOn = 0 (Sunday), we want Sunday=0, Monday=1, ..., Saturday=6
// For weekStartsOn = 1 (Monday), we want Monday=0, Tuesday=1, ..., Sunday=6
const firstDayWeekday = ((firstDayOfMonth.weekday % 7) - weekStartsOn + 7) % 7;
if (n > 0) {
// For first week, if the first day of month is after our week start day,
// we need to go back to the previous week's start
let weekStart = firstDayOfMonth;
if (firstDayWeekday > 0) {
weekStart = weekStart.minus({ days: firstDayWeekday });
}
// If we're too far back (in previous month), move to next week
if (weekStart.month !== month) {
weekStart = weekStart.plus({ weeks: 1 });
}
// Move to the nth week
weekStart = weekStart.plus({ weeks: n - 1 });
// If we've gone past the end of the month, return null
if (weekStart > lastDayOfMonth)
return null;
return weekStart;
}
else {
// Count from end
let weekStart = lastDayOfMonth;
const lastDayWeekday = ((weekStart.weekday % 7) - weekStartsOn + 7) % 7;
// Move to the start of the last week
weekStart = weekStart.minus({ days: lastDayWeekday });
// Move backwards by weeks based on n
weekStart = weekStart.minus({ weeks: (-n - 1) });
// If we've gone before the start of the month, return null
if (weekStart < firstDayOfMonth)
return null;
return weekStart;
}
}
function createOrdinalWeekComponent(start, end, span, originalText, preferences) {
return {
type: 'range',
span,
value: { start, end },
confidence: 1,
metadata: {
originalText,
dateType: 'ordinal',
rangeType: 'ordinalWeek'
}
};
}
exports.ordinalWeeksRule = {
name: 'ordinal-weeks',
patterns: [
{
regex: /^(first|1st|second|2nd|third|3rd|fourth|4th|fifth|5th|last|second\s+to\s+last|third\s+to\s+last)\s+week\s+(?:of|in)\s+(january|february|march|april|may|june|july|august|september|october|november|december)$/i,
parse: (matches, preferences) => {
var _a, _b;
const [fullMatch, ordinal, month] = matches;
// Convert ordinal to number
let n;
if (ordinal === 'last') {
n = -1;
}
else if (ordinal === 'second to last') {
n = -2;
}
else if (ordinal === 'third to last') {
n = -3;
}
else {
n = {
'first': 1, '1st': 1,
'second': 2, '2nd': 2,
'third': 3, '3rd': 3,
'fourth': 4, '4th': 4,
'fifth': 5, '5th': 5
}[ordinal.toLowerCase()] || 0;
}
if (n === 0)
return null;
const monthNum = MONTHS[month.toLowerCase()];
if (!monthNum)
return null;
const year = ((_a = preferences.referenceDate) === null || _a === void 0 ? void 0 : _a.year) || luxon_1.DateTime.now().year;
const weekStartsOn = (_b = preferences.weekStartsOn) !== null && _b !== void 0 ? _b : 1;
const targetDate = findNthWeekOfMonth(year, monthNum, n, weekStartsOn);
if (!targetDate)
return null;
const { start, end } = getWeekRange(targetDate, weekStartsOn);
const matchStart = matches.index + (fullMatch.startsWith(' ') ? 1 : 0);
const matchEnd = matchStart + fullMatch.trim().length;
return createOrdinalWeekComponent(start, end, { start: matchStart, end: matchEnd }, fullMatch.trim(), preferences);
}
}
]
};
//# sourceMappingURL=ordinal-weeks.js.map