Skip to content

Commit

Permalink
Add ordinal date parser (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
liamcain authored Feb 5, 2022
1 parent 2068fab commit 6d2c138
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 2 deletions.
20 changes: 18 additions & 2 deletions src/parser.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import chrono, { Chrono } from "chrono-node";
import chrono, { Chrono, Parser } from "chrono-node";
import type { Moment } from "moment";

import { DayOfWeek } from "./settings";
import { getLastDayOfMonth, getLocaleWeekStart, getWeekNumber } from "./utils";
import {
ORDINAL_NUMBER_PATTERN,
getLastDayOfMonth,
getLocaleWeekStart,
getWeekNumber,
parseOrdinalNumberPattern,
} from "./utils";

export interface NLDResult {
formattedString: string;
Expand Down Expand Up @@ -34,6 +40,16 @@ function getConfiguredChrono(): Chrono {
};
},
});

localizedChrono.parsers.push({
pattern: () => new RegExp(ORDINAL_NUMBER_PATTERN),
extract: (_context, match) => {
return {
day: parseOrdinalNumberPattern(match[0]),
month: window.moment().month(),
};
},
} as Parser);
return localizedChrono;
}

Expand Down
84 changes: 84 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,87 @@ export async function getOrCreateDailyNote(date: Moment): Promise<TFile | null>
}
return createDailyNote(date);
}

// Source `chrono`:
// https://github.com/wanasit/chrono/blob/47f11da6b656cd5cb61f246e8cca706983208ded/src/utils/pattern.ts#L8
// Copyright (c) 2014, Wanasit Tanakitrungruang
type DictionaryLike = string[] | { [word: string]: unknown } | Map<string, unknown>;

function extractTerms(dictionary: DictionaryLike): string[] {
let keys: string[];
if (dictionary instanceof Array) {
keys = [...dictionary];
} else if (dictionary instanceof Map) {
keys = Array.from((dictionary as Map<string, unknown>).keys());
} else {
keys = Object.keys(dictionary);
}

return keys;
}
function matchAnyPattern(dictionary: DictionaryLike): string {
const joinedTerms = extractTerms(dictionary)
.sort((a, b) => b.length - a.length)
.join("|")
.replace(/\./g, "\\.");

return `(?:${joinedTerms})`;
}

const ORDINAL_WORD_DICTIONARY: { [word: string]: number } = {
first: 1,
second: 2,
third: 3,
fourth: 4,
fifth: 5,
sixth: 6,
seventh: 7,
eighth: 8,
ninth: 9,
tenth: 10,
eleventh: 11,
twelfth: 12,
thirteenth: 13,
fourteenth: 14,
fifteenth: 15,
sixteenth: 16,
seventeenth: 17,
eighteenth: 18,
nineteenth: 19,
twentieth: 20,
"twenty first": 21,
"twenty-first": 21,
"twenty second": 22,
"twenty-second": 22,
"twenty third": 23,
"twenty-third": 23,
"twenty fourth": 24,
"twenty-fourth": 24,
"twenty fifth": 25,
"twenty-fifth": 25,
"twenty sixth": 26,
"twenty-sixth": 26,
"twenty seventh": 27,
"twenty-seventh": 27,
"twenty eighth": 28,
"twenty-eighth": 28,
"twenty ninth": 29,
"twenty-ninth": 29,
thirtieth: 30,
"thirty first": 31,
"thirty-first": 31,
};

export const ORDINAL_NUMBER_PATTERN = `(?:${matchAnyPattern(
ORDINAL_WORD_DICTIONARY
)}|[0-9]{1,2}(?:st|nd|rd|th)?)`;

export function parseOrdinalNumberPattern(match: string): number {
let num = match.toLowerCase();
if (ORDINAL_WORD_DICTIONARY[num] !== undefined) {
return ORDINAL_WORD_DICTIONARY[num];
}

num = num.replace(/(?:st|nd|rd|th)$/i, "");
return parseInt(num);
}

0 comments on commit 6d2c138

Please sign in to comment.