timelang 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -230,8 +230,23 @@ var lexer = moo.compile({
230
230
  "sat",
231
231
  "sun"
232
232
  ],
233
+ // Ago keyword for relative dates
234
+ kw_ago: ["ago"],
235
+ // Weekend and night keywords
236
+ kw_weekend: ["weekend"],
237
+ kw_tonight: ["tonight"],
238
+ kw_night: ["night"],
239
+ kw_fortnight: ["fortnight", "fortnights"],
233
240
  // Other keywords
234
- otherKeyword: ["fiscal", "fy", "daily", "weekly", "monthly", "yearly", "annually", "ago", "hence", "later"]
241
+ otherKeyword: ["fiscal", "fy", "daily", "weekly", "monthly", "yearly", "annually", "hence", "later", "earlier"],
242
+ // Business keywords
243
+ kw_business: ["business"],
244
+ // EOD/COB keywords
245
+ kw_eod: ["eod"],
246
+ kw_cob: ["cob"],
247
+ kw_close: ["close"],
248
+ // Week keyword (for "week 1" patterns)
249
+ kw_week: ["week"]
235
250
  })
236
251
  // Keywords are matched against lowercase input
237
252
  },
@@ -284,6 +299,13 @@ var makeRelative = (direction, duration) => ({
284
299
  direction,
285
300
  duration
286
301
  });
302
+ var makeRelativeDate = (direction, duration, baseDate, time2) => ({
303
+ nodeType: "relativeDate",
304
+ direction,
305
+ duration,
306
+ baseDate,
307
+ time: time2
308
+ });
287
309
  var makeTitled = (title, expression, titleStart, titleEnd) => ({
288
310
  nodeType: "titled",
289
311
  title: title.trim(),
@@ -519,10 +541,14 @@ var grammar = {
519
541
  { "name": "expression", "symbols": ["range"], "postprocess": first },
520
542
  { "name": "expression", "symbols": ["span"], "postprocess": first },
521
543
  { "name": "expression", "symbols": ["relative"], "postprocess": first },
544
+ { "name": "expression", "symbols": ["relativeDate"], "postprocess": first },
545
+ { "name": "expression", "symbols": ["lastDayOfMonthExpr"], "postprocess": first },
546
+ { "name": "expression", "symbols": ["date"], "postprocess": first },
522
547
  { "name": "expression", "symbols": ["fuzzy"], "postprocess": first },
523
548
  { "name": "expression", "symbols": ["forDuration"], "postprocess": first },
524
549
  { "name": "expression", "symbols": ["duration"], "postprocess": first },
525
- { "name": "expression", "symbols": ["date"], "postprocess": first },
550
+ { "name": "lastDayOfMonthExpr", "symbols": ["lastRelative", "_", "dayUnit", "_", "ofConnector", "_", "month"], "postprocess": (d) => makeDate({ month: d[6], lastDayOfMonth: true }) },
551
+ { "name": "lastDayOfMonthExpr", "symbols": ["lastRelative", "_", "dayUnit", "_", "ofConnector", "_", "theConnector", "_", "monthUnit"], "postprocess": (d) => makeDate({ lastDayOfMonth: true, monthFromRef: true }) },
526
552
  { "name": "forDuration", "symbols": ["forConnector", "_", "duration"], "postprocess": (d) => d[2] },
527
553
  { "name": "range", "symbols": ["date", "_", "toConnector", "_", "date"], "postprocess": (d) => makeRange(d[0], d[4]) },
528
554
  { "name": "range", "symbols": ["fromConnector", "_", "date", "_", "toConnector", "_", "date"], "postprocess": (d) => makeRange(d[2], d[6]) },
@@ -604,6 +630,30 @@ var grammar = {
604
630
  { "name": "relative", "symbols": ["inConnector", "_", "theConnector", "_", "pastRelative", "_", "unit"], "postprocess": (d) => makeRelative("past", makeDuration(1, d[6])) },
605
631
  { "name": "relative", "symbols": ["inConnector", "_", "theConnector", "_", "comingRelative", "_", "unit"], "postprocess": (d) => makeRelative("future", makeDuration(1, d[6])) },
606
632
  { "name": "relative", "symbols": ["inConnector", "_", "theConnector", "_", "upcomingRelative", "_", "unit"], "postprocess": (d) => makeRelative("future", makeDuration(1, d[6])) },
633
+ { "name": "relativeDate", "symbols": ["duration", "_", "agoConnector"], "postprocess": (d) => makeRelativeDate("past", d[0]) },
634
+ { "name": "relativeDate", "symbols": ["duration", "_", "agoConnector", "_", "atConnector", "_", "time"], "postprocess": (d) => makeRelativeDate("past", d[0], void 0, d[6]) },
635
+ { "name": "relativeDate", "symbols": ["duration", "_", "agoConnector", "_", "atConnector", "_", "timeWord"], "postprocess": (d) => makeRelativeDate("past", d[0], void 0, { special: d[6] }) },
636
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "duration"], "postprocess": (d) => makeRelativeDate("future", d[2]) },
637
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "duration", "_", "atConnector", "_", "time"], "postprocess": (d) => makeRelativeDate("future", d[2], void 0, d[6]) },
638
+ { "name": "relativeDate", "symbols": ["inConnector", "_", "duration", "_", "atConnector", "_", "timeWord"], "postprocess": (d) => makeRelativeDate("future", d[2], void 0, { special: d[6] }) },
639
+ { "name": "relativeDate", "symbols": ["duration", "_", "fromConnector", "_", "now"], "postprocess": (d) => makeRelativeDate("future", d[0]) },
640
+ { "name": "relativeDate", "symbols": ["duration", "_", "fromConnector", "_", "now", "_", "atConnector", "_", "time"], "postprocess": (d) => makeRelativeDate("future", d[0], void 0, d[8]) },
641
+ { "name": "relativeDate", "symbols": ["duration", "_", "fromConnector", "_", "now", "_", "atConnector", "_", "timeWord"], "postprocess": (d) => makeRelativeDate("future", d[0], void 0, { special: d[8] }) },
642
+ { "name": "relativeDate", "symbols": ["duration", "_", "fromConnector", "_", "today"], "postprocess": (d) => makeRelativeDate("future", d[0], makeDate({ special: "today" })) },
643
+ { "name": "relativeDate", "symbols": ["duration", "_", "fromConnector", "_", "today", "_", "atConnector", "_", "time"], "postprocess": (d) => makeRelativeDate("future", d[0], makeDate({ special: "today" }), d[8]) },
644
+ { "name": "relativeDate", "symbols": ["duration", "_", "fromConnector", "_", "tomorrow"], "postprocess": (d) => makeRelativeDate("future", d[0], makeDate({ special: "tomorrow" })) },
645
+ { "name": "relativeDate", "symbols": ["duration", "_", "fromConnector", "_", "tomorrow", "_", "atConnector", "_", "time"], "postprocess": (d) => makeRelativeDate("future", d[0], makeDate({ special: "tomorrow" }), d[8]) },
646
+ { "name": "relativeDate", "symbols": ["duration", "_", "fromConnector", "_", "yesterday"], "postprocess": (d) => makeRelativeDate("future", d[0], makeDate({ special: "yesterday" })) },
647
+ { "name": "relativeDate", "symbols": ["duration", "_", "henceConnector"], "postprocess": (d) => makeRelativeDate("future", d[0]) },
648
+ { "name": "relativeDate", "symbols": ["duration", "_", "laterConnector"], "postprocess": (d) => makeRelativeDate("future", d[0]) },
649
+ { "name": "relativeDate", "symbols": ["duration", "_", "beforeConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("past", d[0], d[4]) },
650
+ { "name": "relativeDate", "symbols": ["duration", "_", "afterConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("future", d[0], d[4]) },
651
+ { "name": "relativeDate", "symbols": ["theConnector", "_", "dayUnit", "_", "beforeConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("past", makeDuration(1, "day"), d[6]) },
652
+ { "name": "relativeDate", "symbols": ["theConnector", "_", "dayUnit", "_", "afterConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("future", makeDuration(1, "day"), d[6]) },
653
+ { "name": "relativeDate", "symbols": ["dayUnit", "_", "beforeConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("past", makeDuration(1, "day"), d[4]) },
654
+ { "name": "relativeDate", "symbols": ["dayUnit", "_", "afterConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("future", makeDuration(1, "day"), d[4]) },
655
+ { "name": "relativeDate", "symbols": ["wordNumber", "_", "unit", "_", "beforeConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("past", makeDuration(parseWordNumber(d[0]), d[2]), d[6]) },
656
+ { "name": "relativeDate", "symbols": ["wordNumber", "_", "unit", "_", "afterConnector", "_", "date"], "postprocess": (d) => makeRelativeDate("future", makeDuration(parseWordNumber(d[0]), d[2]), d[6]) },
607
657
  { "name": "fuzzy", "symbols": ["quarter"], "postprocess": (d) => makeFuzzy({ period: "quarter", quarter: parseQuarter(d[0].value) }) },
608
658
  { "name": "fuzzy", "symbols": ["quarter", "_", "year"], "postprocess": (d) => makeFuzzy({ period: "quarter", quarter: parseQuarter(d[0].value), year: d[2] }) },
609
659
  { "name": "fuzzy", "symbols": ["half"], "postprocess": (d) => makeFuzzy({ period: "half", half: parseHalf(d[0].value) }) },
@@ -686,8 +736,29 @@ var grammar = {
686
736
  { "name": "fuzzy", "symbols": ["lateModifier", "_", "thisRelative", "_", "unit"], "postprocess": (d) => makeFuzzy({ period: d[4], modifier: "late", relative: "this" }) },
687
737
  { "name": "fuzzy", "symbols": ["beginningConnector", "_", "ofConnector", "_", "theConnector", "_", "unit"], "postprocess": (d) => makeFuzzy({ period: d[6], modifier: "beginning" }) },
688
738
  { "name": "fuzzy", "symbols": ["middleConnector", "_", "ofConnector", "_", "theConnector", "_", "unit"], "postprocess": (d) => makeFuzzy({ period: d[6], modifier: "middle" }) },
689
- { "name": "fuzzy", "symbols": ["lastRelative", "_", "unit", "_", "ofConnector", "_", "month"], "postprocess": (d) => makeFuzzy({ period: "month", month: d[6], modifier: "late" }) },
690
- { "name": "fuzzy", "symbols": ["ordinalWord", "_", "unit", "_", "ofConnector", "_", "month"], "postprocess": (d) => makeFuzzy({ period: "month", month: d[6], modifier: parseOrdinalWord(d[0]) <= 2 ? "early" : parseOrdinalWord(d[0]) >= 4 ? "late" : "mid" }) },
739
+ { "name": "fuzzy", "symbols": ["lastRelative", "_", "unit", "_", "ofConnector", "_", "month"], "postprocess": (d, _, reject) => {
740
+ if (d[2].toLowerCase() === "day" || d[2].toLowerCase() === "days") return reject;
741
+ return makeFuzzy({ period: "month", month: d[6], modifier: "late" });
742
+ } },
743
+ { "name": "fuzzy", "symbols": ["ordinalWord", "_", "unit", "_", "ofConnector", "_", "month"], "postprocess": (d, _, reject) => {
744
+ if (d[2].toLowerCase() === "day" || d[2].toLowerCase() === "days") return reject;
745
+ return makeFuzzy({ period: "month", month: d[6], modifier: parseOrdinalWord(d[0]) <= 2 ? "early" : parseOrdinalWord(d[0]) >= 4 ? "late" : "mid" });
746
+ } },
747
+ { "name": "fuzzy", "symbols": ["weekendKeyword"], "postprocess": (d) => makeFuzzy({ period: "weekend", relative: "this" }) },
748
+ { "name": "fuzzy", "symbols": ["theConnector", "_", "weekendKeyword"], "postprocess": (d) => makeFuzzy({ period: "weekend", relative: "this" }) },
749
+ { "name": "fuzzy", "symbols": ["thisRelative", "_", "weekendKeyword"], "postprocess": (d) => makeFuzzy({ period: "weekend", relative: "this" }) },
750
+ { "name": "fuzzy", "symbols": ["nextRelative", "_", "weekendKeyword"], "postprocess": (d) => makeFuzzy({ period: "weekend", relative: "next" }) },
751
+ { "name": "fuzzy", "symbols": ["lastRelative", "_", "weekendKeyword"], "postprocess": (d) => makeFuzzy({ period: "weekend", relative: "last" }) },
752
+ { "name": "fuzzy", "symbols": ["tonightKeyword"], "postprocess": (d) => makeFuzzy({ period: "tonight" }) },
753
+ { "name": "fuzzy", "symbols": ["nightKeyword"], "postprocess": (d) => makeFuzzy({ period: "night" }) },
754
+ { "name": "fuzzy", "symbols": ["lastRelative", "_", "nightKeyword"], "postprocess": (d) => makeFuzzy({ period: "night", relative: "last" }) },
755
+ { "name": "fuzzy", "symbols": ["tomorrow", "_", "nightKeyword"], "postprocess": (d) => makeFuzzy({ period: "night", relative: "tomorrow" }) },
756
+ { "name": "fuzzy", "symbols": ["weekday", "_", "nightKeyword"], "postprocess": (d) => makeFuzzy({ period: "night", weekday: d[0] }) },
757
+ { "name": "fuzzy", "symbols": ["fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight" }) },
758
+ { "name": "fuzzy", "symbols": ["nextRelative", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", relative: "next" }) },
759
+ { "name": "fuzzy", "symbols": ["lastRelative", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", relative: "last" }) },
760
+ { "name": "fuzzy", "symbols": ["inConnector", "_", "wordNumber", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", count: parseWordNumber(d[2]) }) },
761
+ { "name": "fuzzy", "symbols": ["inConnector", "_", "number", "_", "fortnightKeyword"], "postprocess": (d) => makeFuzzy({ period: "fortnight", count: d[2] }) },
691
762
  { "name": "duration", "symbols": ["number", "_", "unit"], "postprocess": (d) => makeDuration(d[0], d[2]) },
692
763
  { "name": "duration", "symbols": ["wordNumber", "_", "unit"], "postprocess": (d) => makeDuration(parseWordNumber(d[0]), d[2]) },
693
764
  { "name": "duration", "symbols": ["abbreviatedDuration"], "postprocess": (d) => d[0] },
@@ -715,6 +786,7 @@ var grammar = {
715
786
  return makeDuration(value, unitMap[match[2]]);
716
787
  } },
717
788
  { "name": "date", "symbols": ["specialDay"], "postprocess": (d) => makeDate({ special: d[0] }) },
789
+ { "name": "date", "symbols": ["ordinalWeekdayOfMonth"], "postprocess": first },
718
790
  { "name": "date", "symbols": ["relativeWeekday"], "postprocess": first },
719
791
  { "name": "date", "symbols": ["weekday"], "postprocess": (d) => makeDate({ weekday: d[0] }) },
720
792
  { "name": "date", "symbols": ["monthDayYear"], "postprocess": first },
@@ -729,6 +801,7 @@ var grammar = {
729
801
  { "name": "date", "symbols": ["monthOnly"], "postprocess": first },
730
802
  { "name": "date", "symbols": ["yearOnly"], "postprocess": first },
731
803
  { "name": "date", "symbols": ["timeOnly"], "postprocess": first },
804
+ { "name": "date", "symbols": ["dayOnly"], "postprocess": first },
732
805
  { "name": "monthDayCompact", "symbols": [lexer.has("monthDayCompact") ? { type: "monthDayCompact" } : monthDayCompact], "postprocess": (d) => {
733
806
  const parsed = parseMonthDayCompact(d[0].value);
734
807
  return makeDate({ month: parsed.month, day: parsed.day });
@@ -745,6 +818,8 @@ var grammar = {
745
818
  } },
746
819
  { "name": "timeOnly", "symbols": ["time"], "postprocess": (d) => makeDate({ time: d[0], timeOnly: true }) },
747
820
  { "name": "timeOnly", "symbols": ["timeWord"], "postprocess": (d) => makeDate({ time: { special: d[0] }, timeOnly: true }) },
821
+ { "name": "dayOnly", "symbols": ["theConnector", "_", "dayNumber"], "postprocess": (d) => makeDate({ day: d[2], dayOnly: true }) },
822
+ { "name": "dayOnly", "symbols": ["onConnector", "_", "theConnector", "_", "dayNumber"], "postprocess": (d) => makeDate({ day: d[4], dayOnly: true }) },
748
823
  { "name": "specialDay", "symbols": ["today"], "postprocess": (d) => "today" },
749
824
  { "name": "specialDay", "symbols": ["tomorrow"], "postprocess": (d) => "tomorrow" },
750
825
  { "name": "specialDay", "symbols": ["yesterday"], "postprocess": (d) => "yesterday" },
@@ -753,7 +828,7 @@ var grammar = {
753
828
  { "name": "specialDay", "symbols": ["dayUnit", "_", "afterConnector", "_", "tomorrow"], "postprocess": (d) => "dayAfterTomorrow" },
754
829
  { "name": "specialDay", "symbols": ["theConnector", "_", "dayUnit", "_", "beforeConnector", "_", "yesterday"], "postprocess": (d) => "dayBeforeYesterday" },
755
830
  { "name": "specialDay", "symbols": ["dayUnit", "_", "beforeConnector", "_", "yesterday"], "postprocess": (d) => "dayBeforeYesterday" },
756
- { "name": "dayUnit", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d) => d[0].value === "day" ? d[0] : null },
831
+ { "name": "dayUnit", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => d[0].value === "day" ? d[0] : reject },
757
832
  { "name": "relativeWeekday", "symbols": ["nextRelative", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], relative: "next" }) },
758
833
  { "name": "relativeWeekday", "symbols": ["lastRelative", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], relative: "last" }) },
759
834
  { "name": "relativeWeekday", "symbols": ["thisRelative", "_", "weekday"], "postprocess": (d) => makeDate({ weekday: d[2], relative: "this" }) },
@@ -768,6 +843,14 @@ var grammar = {
768
843
  { "name": "monthDay", "symbols": ["theConnector", "_", "dayNumber", "_", "ofConnector", "_", "month"], "postprocess": (d) => makeDate({ month: d[6], day: d[2] }) },
769
844
  { "name": "monthDay", "symbols": ["month", "_", "ordinalWord"], "postprocess": (d) => makeDate({ month: d[0], day: parseOrdinalWord(d[2]) }) },
770
845
  { "name": "monthDay", "symbols": ["month", "_", "theConnector", "_", "dayNumber"], "postprocess": (d) => makeDate({ month: d[0], day: d[4] }) },
846
+ { "name": "ordinalWeekdayOfMonth", "symbols": ["ordinalWord", "_", "weekday", "_", "ofConnector", "_", "month"], "postprocess": (d) => makeDate({ ordinalWeekday: parseOrdinalWord(d[0]), weekday: d[2], month: d[6] }) },
847
+ { "name": "ordinalWeekdayOfMonth", "symbols": ["lastRelative", "_", "weekday", "_", "ofConnector", "_", "month"], "postprocess": (d) => makeDate({ ordinalWeekday: -1, weekday: d[2], month: d[6] }) },
848
+ { "name": "ordinalWeekdayOfMonth", "symbols": ["ordinalWord", "_", "weekday", "_", "ofConnector", "_", "theConnector", "_", "monthUnit"], "postprocess": (d) => makeDate({ ordinalWeekday: parseOrdinalWord(d[0]), weekday: d[2], monthFromRef: true }) },
849
+ { "name": "ordinalWeekdayOfMonth", "symbols": ["lastRelative", "_", "weekday", "_", "ofConnector", "_", "theConnector", "_", "monthUnit"], "postprocess": (d) => makeDate({ ordinalWeekday: -1, weekday: d[2], monthFromRef: true }) },
850
+ { "name": "ordinalWeekdayOfMonth", "symbols": ["ordinalWord", "_", "dayUnit", "_", "ofConnector", "_", "month"], "postprocess": (d) => makeDate({ month: d[6], day: parseOrdinalWord(d[0]) }) },
851
+ { "name": "ordinalWeekdayOfMonth", "symbols": ["lastRelative", "_", "dayUnit", "_", "ofConnector", "_", "month"], "postprocess": (d) => makeDate({ month: d[6], day: -1, lastDayOfMonth: true }) },
852
+ { "name": "ordinalWeekdayOfMonth", "symbols": ["lastRelative", "_", "dayUnit", "_", "ofConnector", "_", "theConnector", "_", "monthUnit"], "postprocess": (d) => makeDate({ lastDayOfMonth: true, monthFromRef: true }) },
853
+ { "name": "ordinalWeekdayOfMonth", "symbols": ["ordinalWord", "_", "dayUnit", "_", "ofConnector", "_", "nextRelative", "_", "monthUnit"], "postprocess": (d) => makeDate({ ordinalWeekday: parseOrdinalWord(d[0]), dayOfMonth: true, nextMonth: true }) },
771
854
  { "name": "monthDayYear", "symbols": ["monthDay", "_", "year"], "postprocess": (d) => ({ ...d[0], year: d[2] }) },
772
855
  { "name": "monthDayYear", "symbols": ["monthDay", lexer.has("comma") ? { type: "comma" } : comma, "_", "year"], "postprocess": (d) => ({ ...d[0], year: d[3] }) },
773
856
  { "name": "dateFormat", "symbols": [lexer.has("integer") ? { type: "integer" } : integer, lexer.has("dash") ? { type: "dash" } : dash, lexer.has("integer") ? { type: "integer" } : integer, lexer.has("dash") ? { type: "dash" } : dash, lexer.has("integer") ? { type: "integer" } : integer], "postprocess": (d) => {
@@ -861,6 +944,11 @@ var grammar = {
861
944
  if (val === "year" || val === "years" || val === "yr" || val === "yrs") return val;
862
945
  return reject;
863
946
  } },
947
+ { "name": "monthUnit", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => {
948
+ const val = d[0].value.toLowerCase();
949
+ if (val === "month" || val === "months" || val === "mo" || val === "mos") return val;
950
+ return reject;
951
+ } },
864
952
  { "name": "wordNumber", "symbols": [lexer.has("wordNumber") ? { type: "wordNumber" } : wordNumber], "postprocess": (d) => d[0].value },
865
953
  { "name": "ordinalWord", "symbols": [lexer.has("ordinalWord") ? { type: "ordinalWord" } : ordinalWord], "postprocess": (d) => d[0].value },
866
954
  { "name": "ordinalWord", "symbols": [lexer.has("unit") ? { type: "unit" } : unit], "postprocess": (d, _, reject) => {
@@ -897,6 +985,9 @@ var grammar = {
897
985
  { "name": "beginningConnector", "symbols": [lexer.has("kw_beginning") ? { type: "kw_beginning" } : kw_beginning], "postprocess": first },
898
986
  { "name": "startConnector", "symbols": [lexer.has("kw_start") ? { type: "kw_start" } : kw_start], "postprocess": first },
899
987
  { "name": "middleConnector", "symbols": [lexer.has("kw_middle") ? { type: "kw_middle" } : kw_middle], "postprocess": first },
988
+ { "name": "agoConnector", "symbols": [lexer.has("kw_ago") ? { type: "kw_ago" } : kw_ago], "postprocess": first },
989
+ { "name": "henceConnector", "symbols": [lexer.has("otherKeyword") ? { type: "otherKeyword" } : otherKeyword], "postprocess": (d, _, reject) => d[0].value === "hence" ? d[0] : reject },
990
+ { "name": "laterConnector", "symbols": [lexer.has("otherKeyword") ? { type: "otherKeyword" } : otherKeyword], "postprocess": (d, _, reject) => d[0].value === "later" ? d[0] : reject },
900
991
  { "name": "earlyModifier", "symbols": [lexer.has("kw_early") ? { type: "kw_early" } : kw_early], "postprocess": first },
901
992
  { "name": "midModifier", "symbols": [lexer.has("kw_mid") ? { type: "kw_mid" } : kw_mid], "postprocess": first },
902
993
  { "name": "lateModifier", "symbols": [lexer.has("kw_late") ? { type: "kw_late" } : kw_late], "postprocess": first },
@@ -913,6 +1004,10 @@ var grammar = {
913
1004
  { "name": "now", "symbols": [lexer.has("kw_now") ? { type: "kw_now" } : kw_now], "postprocess": first },
914
1005
  { "name": "noon", "symbols": [lexer.has("kw_noon") ? { type: "kw_noon" } : kw_noon], "postprocess": first },
915
1006
  { "name": "midnight", "symbols": [lexer.has("kw_midnight") ? { type: "kw_midnight" } : kw_midnight], "postprocess": first },
1007
+ { "name": "weekendKeyword", "symbols": [lexer.has("kw_weekend") ? { type: "kw_weekend" } : kw_weekend], "postprocess": first },
1008
+ { "name": "tonightKeyword", "symbols": [lexer.has("kw_tonight") ? { type: "kw_tonight" } : kw_tonight], "postprocess": first },
1009
+ { "name": "nightKeyword", "symbols": [lexer.has("kw_night") ? { type: "kw_night" } : kw_night], "postprocess": first },
1010
+ { "name": "fortnightKeyword", "symbols": [lexer.has("kw_fortnight") ? { type: "kw_fortnight" } : kw_fortnight], "postprocess": first },
916
1011
  { "name": "_$ebnf$1", "symbols": [] },
917
1012
  { "name": "_$ebnf$1", "symbols": ["_$ebnf$1", lexer.has("ws") ? { type: "ws" } : ws], "postprocess": (d) => d[0].concat([d[1]]) },
918
1013
  { "name": "_", "symbols": ["_$ebnf$1"], "postprocess": nuller }
@@ -1170,6 +1265,114 @@ function convertMonthDay(node, opts) {
1170
1265
  }
1171
1266
  return date;
1172
1267
  }
1268
+ function convertOrdinalWeekdayOfMonth(node, opts) {
1269
+ const ref = opts.referenceDate;
1270
+ const ordinal2 = node.ordinalWeekday;
1271
+ const weekdayName = node.weekday.toLowerCase();
1272
+ const weekdayNum = WEEKDAY_MAP[weekdayName] ?? 0;
1273
+ let month2;
1274
+ let year;
1275
+ if (node.monthFromRef) {
1276
+ month2 = ref.getUTCMonth();
1277
+ year = ref.getUTCFullYear();
1278
+ } else if (node.nextMonth) {
1279
+ month2 = ref.getUTCMonth() + 1;
1280
+ year = ref.getUTCFullYear();
1281
+ if (month2 > 11) {
1282
+ month2 = 0;
1283
+ year++;
1284
+ }
1285
+ } else {
1286
+ month2 = typeof node.month === "number" ? node.month - 1 : ref.getUTCMonth();
1287
+ year = ref.getUTCFullYear();
1288
+ if (month2 < ref.getUTCMonth()) {
1289
+ year++;
1290
+ }
1291
+ }
1292
+ if (ordinal2 === -1) {
1293
+ const lastDay2 = new Date(Date.UTC(year, month2 + 1, 0));
1294
+ let day2 = lastDay2.getUTCDate();
1295
+ let date2 = new Date(Date.UTC(year, month2, day2));
1296
+ while (date2.getUTCDay() !== weekdayNum) {
1297
+ day2--;
1298
+ date2 = new Date(Date.UTC(year, month2, day2));
1299
+ }
1300
+ return date2;
1301
+ }
1302
+ let count = 0;
1303
+ for (let day2 = 1; day2 <= 31; day2++) {
1304
+ const date2 = new Date(Date.UTC(year, month2, day2));
1305
+ if (date2.getUTCMonth() !== month2) {
1306
+ break;
1307
+ }
1308
+ if (date2.getUTCDay() === weekdayNum) {
1309
+ count++;
1310
+ if (count === ordinal2) {
1311
+ return date2;
1312
+ }
1313
+ }
1314
+ }
1315
+ const lastDay = new Date(Date.UTC(year, month2 + 1, 0));
1316
+ let day = lastDay.getUTCDate();
1317
+ let date = new Date(Date.UTC(year, month2, day));
1318
+ while (date.getUTCDay() !== weekdayNum) {
1319
+ day--;
1320
+ date = new Date(Date.UTC(year, month2, day));
1321
+ }
1322
+ return date;
1323
+ }
1324
+ function convertLastDayOfMonth(node, opts) {
1325
+ const ref = opts.referenceDate;
1326
+ let month2;
1327
+ let year;
1328
+ if (node.monthFromRef) {
1329
+ month2 = ref.getUTCMonth();
1330
+ year = ref.getUTCFullYear();
1331
+ } else if (node.nextMonth) {
1332
+ month2 = ref.getUTCMonth() + 1;
1333
+ year = ref.getUTCFullYear();
1334
+ if (month2 > 11) {
1335
+ month2 = 0;
1336
+ year++;
1337
+ }
1338
+ } else {
1339
+ month2 = typeof node.month === "number" ? node.month - 1 : ref.getUTCMonth();
1340
+ year = ref.getUTCFullYear();
1341
+ if (month2 < ref.getUTCMonth()) {
1342
+ year++;
1343
+ }
1344
+ }
1345
+ return new Date(Date.UTC(year, month2 + 1, 0));
1346
+ }
1347
+ function convertDayOnly(node, opts) {
1348
+ const ref = opts.referenceDate;
1349
+ const day = node.day;
1350
+ const refDay = ref.getUTCDate();
1351
+ const refMonth = ref.getUTCMonth();
1352
+ const refYear = ref.getUTCFullYear();
1353
+ let month2 = refMonth;
1354
+ let year = refYear;
1355
+ if (day < refDay) {
1356
+ month2 = refMonth + 1;
1357
+ if (month2 > 11) {
1358
+ month2 = 0;
1359
+ year++;
1360
+ }
1361
+ }
1362
+ let date = new Date(Date.UTC(year, month2, day));
1363
+ while (date.getUTCDate() !== day) {
1364
+ month2++;
1365
+ if (month2 > 11) {
1366
+ month2 = 0;
1367
+ year++;
1368
+ }
1369
+ date = new Date(Date.UTC(year, month2, day));
1370
+ }
1371
+ if (node.time) {
1372
+ applyTime(date, node.time);
1373
+ }
1374
+ return date;
1375
+ }
1173
1376
  function convertRelativePeriod(node, opts) {
1174
1377
  const ref = opts.referenceDate;
1175
1378
  const period = node.period.toLowerCase();
@@ -1229,6 +1432,9 @@ function convertDateNode(node, opts) {
1229
1432
  if (node.timeOnly && node.time) {
1230
1433
  return convertTimeOnly(node, opts);
1231
1434
  }
1435
+ if (node.ordinalWeekday !== void 0 && node.weekday !== void 0) {
1436
+ return convertOrdinalWeekdayOfMonth(node, opts);
1437
+ }
1232
1438
  if (node.weekday) {
1233
1439
  return convertWeekday(node, opts);
1234
1440
  }
@@ -1238,6 +1444,23 @@ function convertDateNode(node, opts) {
1238
1444
  if (node.month !== void 0 && node.day !== void 0) {
1239
1445
  return convertMonthDay(node, opts);
1240
1446
  }
1447
+ if (node.dayOnly && node.day !== void 0) {
1448
+ return convertDayOnly(node, opts);
1449
+ }
1450
+ if (node.lastDayOfMonth) {
1451
+ return convertLastDayOfMonth(node, opts);
1452
+ }
1453
+ if (node.dayOfMonth && node.nextMonth) {
1454
+ const ref = opts.referenceDate;
1455
+ let month2 = ref.getUTCMonth() + 1;
1456
+ let year = ref.getUTCFullYear();
1457
+ if (month2 > 11) {
1458
+ month2 = 0;
1459
+ year++;
1460
+ }
1461
+ const day = node.ordinalWeekday || 1;
1462
+ return new Date(Date.UTC(year, month2, day));
1463
+ }
1241
1464
  if (node.relative && node.period) {
1242
1465
  return convertRelativePeriod(node, opts);
1243
1466
  }
@@ -1309,7 +1532,7 @@ function getHalfDates(half2, year, fiscalYearStart) {
1309
1532
  const start = new Date(Date.UTC(startYear, halfStartMonth, 1));
1310
1533
  const endMonth = (halfStartMonth + 6) % 12;
1311
1534
  let endYear = startYear;
1312
- if (endMonth < halfStartMonth || endMonth === halfStartMonth) {
1535
+ if (endMonth <= halfStartMonth) {
1313
1536
  endYear++;
1314
1537
  }
1315
1538
  const end = new Date(Date.UTC(endYear, endMonth, 0));
@@ -1382,8 +1605,115 @@ function getModifiedPeriod(start, end, modifier) {
1382
1605
  }
1383
1606
 
1384
1607
  // src/converters/fuzzy.ts
1608
+ function getWeekendDates(ref, relative, opts) {
1609
+ const currentDay = ref.getUTCDay();
1610
+ const saturdayOffset = (6 - currentDay + 7) % 7;
1611
+ let saturday = new Date(
1612
+ Date.UTC(
1613
+ ref.getUTCFullYear(),
1614
+ ref.getUTCMonth(),
1615
+ ref.getUTCDate() + saturdayOffset
1616
+ )
1617
+ );
1618
+ if (relative === "next") {
1619
+ saturday = new Date(saturday.getTime() + MS_PER_WEEK);
1620
+ } else if (relative === "last") {
1621
+ if (currentDay === 6 || currentDay === 0) {
1622
+ saturday = new Date(saturday.getTime() - MS_PER_WEEK);
1623
+ }
1624
+ saturday = new Date(saturday.getTime() - MS_PER_WEEK);
1625
+ }
1626
+ const sunday = new Date(saturday.getTime() + MS_PER_DAY);
1627
+ const sundayEnd = new Date(
1628
+ Date.UTC(
1629
+ sunday.getUTCFullYear(),
1630
+ sunday.getUTCMonth(),
1631
+ sunday.getUTCDate(),
1632
+ 23,
1633
+ 59
1634
+ )
1635
+ );
1636
+ return { start: saturday, end: sundayEnd };
1637
+ }
1638
+ function getNightDates(ref, relative, weekday2) {
1639
+ let baseDate = new Date(ref);
1640
+ if (relative === "last") {
1641
+ baseDate = new Date(
1642
+ Date.UTC(
1643
+ ref.getUTCFullYear(),
1644
+ ref.getUTCMonth(),
1645
+ ref.getUTCDate() - 1
1646
+ )
1647
+ );
1648
+ } else if (relative === "tomorrow") {
1649
+ baseDate = new Date(
1650
+ Date.UTC(
1651
+ ref.getUTCFullYear(),
1652
+ ref.getUTCMonth(),
1653
+ ref.getUTCDate() + 1
1654
+ )
1655
+ );
1656
+ } else if (weekday2) {
1657
+ const targetDay = WEEKDAY_MAP[weekday2.toLowerCase()];
1658
+ if (targetDay !== void 0) {
1659
+ const currentDay = ref.getUTCDay();
1660
+ let daysToAdd = (targetDay - currentDay + 7) % 7;
1661
+ if (daysToAdd === 0) {
1662
+ daysToAdd = 7;
1663
+ }
1664
+ baseDate = new Date(
1665
+ Date.UTC(
1666
+ ref.getUTCFullYear(),
1667
+ ref.getUTCMonth(),
1668
+ ref.getUTCDate() + daysToAdd
1669
+ )
1670
+ );
1671
+ }
1672
+ }
1673
+ const start = new Date(
1674
+ Date.UTC(
1675
+ baseDate.getUTCFullYear(),
1676
+ baseDate.getUTCMonth(),
1677
+ baseDate.getUTCDate(),
1678
+ 18,
1679
+ 0
1680
+ )
1681
+ );
1682
+ const end = new Date(
1683
+ Date.UTC(
1684
+ baseDate.getUTCFullYear(),
1685
+ baseDate.getUTCMonth(),
1686
+ baseDate.getUTCDate(),
1687
+ 23,
1688
+ 59
1689
+ )
1690
+ );
1691
+ return { start, end };
1692
+ }
1385
1693
  function getBasePeriodDates(node, opts, year) {
1386
1694
  const ref = opts.referenceDate;
1695
+ if (node.period === "weekend") {
1696
+ return getWeekendDates(ref, node.relative || "this", opts);
1697
+ }
1698
+ if (node.period === "tonight") {
1699
+ return getNightDates(ref, void 0, void 0);
1700
+ }
1701
+ if (node.period === "night") {
1702
+ return getNightDates(ref, node.relative, node.weekday);
1703
+ }
1704
+ if (node.period === "fortnight") {
1705
+ const count = node.count || 1;
1706
+ const relative = node.relative;
1707
+ const twoWeeks = 14 * MS_PER_DAY;
1708
+ if (relative === "last") {
1709
+ const end2 = new Date(ref);
1710
+ const start2 = new Date(ref.getTime() - twoWeeks);
1711
+ return { start: start2, end: end2 };
1712
+ }
1713
+ const start = new Date(ref);
1714
+ const end = new Date(ref.getTime() + count * twoWeeks);
1715
+ return { start, end };
1716
+ }
1387
1717
  if (node.period === "quarter" && node.quarter) {
1388
1718
  return getQuarterDates(
1389
1719
  node.quarter,
@@ -1546,7 +1876,7 @@ function convertASTToResult(ast, opts, originalInput) {
1546
1876
  end = new Date(Date.UTC(year, month2 + 1, 0));
1547
1877
  }
1548
1878
  if (endNode.yearOnly) {
1549
- const year = endNode.year;
1879
+ const year = endNode.year ?? opts.referenceDate.getUTCFullYear();
1550
1880
  end = new Date(Date.UTC(year, 11, 31));
1551
1881
  }
1552
1882
  } else if (endNode.nodeType === "fuzzy") {
@@ -1577,6 +1907,7 @@ function convertASTToResult(ast, opts, originalInput) {
1577
1907
  case "fuzzy": {
1578
1908
  const { start, end } = convertFuzzyNode(expression, opts);
1579
1909
  const mod = expression.modifier;
1910
+ const period = expression.period;
1580
1911
  if (mod === "start" || mod === "beginning") {
1581
1912
  const periodDates = convertFuzzyNodeWithoutModifier(expression, opts);
1582
1913
  return { type: "date", date: periodDates.start, title };
@@ -1585,6 +1916,10 @@ function convertASTToResult(ast, opts, originalInput) {
1585
1916
  const periodDates = convertFuzzyNodeWithoutModifier(expression, opts);
1586
1917
  return { type: "date", date: periodDates.end, title };
1587
1918
  }
1919
+ if (period === "weekend" || period === "night" || period === "tonight" || period === "fortnight") {
1920
+ const duration = end.getTime() - start.getTime();
1921
+ return { type: "span", start, end, duration, title };
1922
+ }
1588
1923
  return { type: "fuzzy", start, end, approximate: true, title };
1589
1924
  }
1590
1925
  case "relative": {
@@ -1601,6 +1936,81 @@ function convertASTToResult(ast, opts, originalInput) {
1601
1936
  }
1602
1937
  return { type: "span", start, end, duration, title };
1603
1938
  }
1939
+ case "relativeDate": {
1940
+ const durationNode = expression.duration;
1941
+ const baseNode = expression.baseDate;
1942
+ const timeSpec = expression.time;
1943
+ let baseDate;
1944
+ if (baseNode) {
1945
+ baseDate = convertDateNode(baseNode, opts);
1946
+ } else {
1947
+ baseDate = new Date(opts.referenceDate);
1948
+ }
1949
+ const durationValue = durationNode.value;
1950
+ const durationUnit = durationNode.unit;
1951
+ const direction = expression.direction === "past" ? -1 : 1;
1952
+ let resultDate;
1953
+ if (durationUnit === "month") {
1954
+ resultDate = new Date(
1955
+ Date.UTC(
1956
+ baseDate.getUTCFullYear(),
1957
+ baseDate.getUTCMonth() + direction * durationValue,
1958
+ baseDate.getUTCDate(),
1959
+ baseDate.getUTCHours(),
1960
+ baseDate.getUTCMinutes()
1961
+ )
1962
+ );
1963
+ } else if (durationUnit === "year") {
1964
+ resultDate = new Date(
1965
+ Date.UTC(
1966
+ baseDate.getUTCFullYear() + direction * durationValue,
1967
+ baseDate.getUTCMonth(),
1968
+ baseDate.getUTCDate(),
1969
+ baseDate.getUTCHours(),
1970
+ baseDate.getUTCMinutes()
1971
+ )
1972
+ );
1973
+ } else {
1974
+ const durationMs = convertDurationNode(durationNode);
1975
+ resultDate = new Date(baseDate.getTime() + direction * durationMs);
1976
+ }
1977
+ if (timeSpec) {
1978
+ if ("special" in timeSpec) {
1979
+ if (timeSpec.special === "noon") {
1980
+ resultDate = new Date(
1981
+ Date.UTC(
1982
+ resultDate.getUTCFullYear(),
1983
+ resultDate.getUTCMonth(),
1984
+ resultDate.getUTCDate(),
1985
+ 12,
1986
+ 0
1987
+ )
1988
+ );
1989
+ } else if (timeSpec.special === "midnight") {
1990
+ resultDate = new Date(
1991
+ Date.UTC(
1992
+ resultDate.getUTCFullYear(),
1993
+ resultDate.getUTCMonth(),
1994
+ resultDate.getUTCDate(),
1995
+ 0,
1996
+ 0
1997
+ )
1998
+ );
1999
+ }
2000
+ } else {
2001
+ resultDate = new Date(
2002
+ Date.UTC(
2003
+ resultDate.getUTCFullYear(),
2004
+ resultDate.getUTCMonth(),
2005
+ resultDate.getUTCDate(),
2006
+ timeSpec.hour,
2007
+ timeSpec.minute
2008
+ )
2009
+ );
2010
+ }
2011
+ }
2012
+ return { type: "date", date: resultDate, title };
2013
+ }
1604
2014
  default:
1605
2015
  return null;
1606
2016
  }
@@ -1623,13 +2033,13 @@ function stripUnmatchedPunctuation(input) {
1623
2033
  openParens = (result.match(/\(/g) || []).length;
1624
2034
  closeParens = (result.match(/\)/g) || []).length;
1625
2035
  while (openParens > closeParens) {
1626
- result = result.replace("(", "");
2036
+ result = result.replace(/\(/, "");
1627
2037
  openParens--;
1628
2038
  }
1629
2039
  openBrackets = (result.match(/\[/g) || []).length;
1630
2040
  closeBrackets = (result.match(/]/g) || []).length;
1631
2041
  while (openBrackets > closeBrackets) {
1632
- result = result.replace("[", "");
2042
+ result = result.replace(/\[/, "");
1633
2043
  openBrackets--;
1634
2044
  }
1635
2045
  return {