chrono-node 2.3.3 → 2.3.7
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/README.md +2 -2
- package/dist/common/casualReferences.js +3 -1
- package/dist/common/parsers/AbstractParserWithWordBoundary.js +2 -1
- package/dist/common/refiners/ExtractTimezoneAbbrRefiner.js +5 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/locales/en/index.js +2 -1
- package/dist/locales/en/parsers/ENRelativeDateFormatParser.js +2 -2
- package/dist/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.js +1 -1
- package/dist/locales/en/refiners/ENMergeRelativeDateRefiner.d.ts +7 -0
- package/dist/locales/en/refiners/ENMergeRelativeDateRefiner.js +35 -0
- package/dist/locales/zh/hans/constants.d.ts +27 -0
- package/dist/locales/zh/hans/constants.js +51 -0
- package/dist/locales/zh/hans/index.d.ts +9 -0
- package/dist/locales/zh/hans/index.js +49 -0
- package/dist/locales/zh/hans/parsers/ZHHansCasualDateParser.d.ts +7 -0
- package/dist/locales/zh/hans/parsers/ZHHansCasualDateParser.js +138 -0
- package/dist/locales/zh/hans/parsers/ZHHansDateParser.d.ts +6 -0
- package/dist/locales/zh/hans/parsers/ZHHansDateParser.js +72 -0
- package/dist/locales/zh/hans/parsers/ZHHansDeadlineFormatParser.d.ts +6 -0
- package/dist/locales/zh/hans/parsers/ZHHansDeadlineFormatParser.js +78 -0
- package/dist/locales/zh/hans/parsers/ZHHansRelationWeekdayParser.d.ts +7 -0
- package/dist/locales/zh/hans/parsers/ZHHansRelationWeekdayParser.js +70 -0
- package/dist/locales/zh/hans/parsers/ZHHansTimeExpressionParser.d.ts +6 -0
- package/dist/locales/zh/hans/parsers/ZHHansTimeExpressionParser.js +438 -0
- package/dist/locales/zh/hans/parsers/ZHHansWeekdayParser.d.ts +7 -0
- package/dist/locales/zh/hans/parsers/ZHHansWeekdayParser.js +46 -0
- package/dist/locales/zh/hans/refiners/ZHHansMergeDateRangeRefiner.d.ts +4 -0
- package/dist/locales/zh/hans/refiners/ZHHansMergeDateRangeRefiner.js +12 -0
- package/dist/locales/zh/hans/refiners/ZHHansMergeDateTimeRefiner.d.ts +4 -0
- package/dist/locales/zh/hans/refiners/ZHHansMergeDateTimeRefiner.js +12 -0
- package/dist/locales/zh/hant/constants.d.ts +28 -0
- package/dist/locales/zh/hant/constants.js +52 -0
- package/dist/locales/zh/hant/index.d.ts +9 -0
- package/dist/locales/zh/hant/index.js +49 -0
- package/dist/locales/zh/hant/parsers/ZHHantCasualDateParser.d.ts +7 -0
- package/dist/locales/zh/hant/parsers/ZHHantCasualDateParser.js +138 -0
- package/dist/locales/zh/hant/parsers/ZHHantDateParser.d.ts +6 -0
- package/dist/locales/zh/hant/parsers/ZHHantDateParser.js +64 -0
- package/dist/locales/zh/hant/parsers/ZHHantDeadlineFormatParser.d.ts +6 -0
- package/dist/locales/zh/hant/parsers/ZHHantDeadlineFormatParser.js +78 -0
- package/dist/locales/zh/hant/parsers/ZHHantRelationWeekdayParser.d.ts +7 -0
- package/dist/locales/zh/hant/parsers/ZHHantRelationWeekdayParser.js +70 -0
- package/dist/locales/zh/hant/parsers/ZHHantTimeExpressionParser.d.ts +6 -0
- package/dist/locales/zh/hant/parsers/ZHHantTimeExpressionParser.js +438 -0
- package/dist/locales/zh/hant/parsers/ZHHantWeekdayParser.d.ts +7 -0
- package/dist/locales/zh/hant/parsers/ZHHantWeekdayParser.js +46 -0
- package/dist/locales/zh/hant/refiners/ZHHantMergeDateRangeRefiner.d.ts +4 -0
- package/dist/locales/zh/hant/refiners/ZHHantMergeDateRangeRefiner.js +12 -0
- package/dist/locales/zh/hant/refiners/ZHHantMergeDateTimeRefiner.d.ts +4 -0
- package/dist/locales/zh/hant/refiners/ZHHantMergeDateTimeRefiner.js +12 -0
- package/dist/locales/zh/index.d.ts +2 -0
- package/dist/locales/zh/index.js +16 -0
- package/dist/results.js +8 -5
- package/dist/timezone.js +1 -1
- package/dist/utils/dayjs.js +7 -0
- package/package.json +1 -1
- package/src/common/casualReferences.ts +3 -1
- package/src/common/parsers/AbstractParserWithWordBoundary.ts +1 -1
- package/src/common/refiners/ExtractTimezoneAbbrRefiner.ts +8 -0
- package/src/index.ts +2 -1
- package/src/locales/en/index.ts +2 -1
- package/src/locales/en/parsers/ENMonthNameLittleEndianParser.ts +0 -2
- package/src/locales/en/parsers/ENRelativeDateFormatParser.ts +2 -2
- package/src/locales/en/parsers/ENTimeUnitCasualRelativeFormatParser.ts +1 -1
- package/src/locales/en/refiners/ENMergeRelativeDateRefiner.ts +58 -0
- package/src/locales/zh/hans/constants.ts +52 -0
- package/src/locales/zh/hans/index.ts +62 -0
- package/src/locales/zh/hans/parsers/ZHHansCasualDateParser.ts +128 -0
- package/src/locales/zh/hans/parsers/ZHHansDateParser.ts +75 -0
- package/src/locales/zh/hans/parsers/ZHHansDeadlineFormatParser.ts +81 -0
- package/src/locales/zh/hans/parsers/ZHHansRelationWeekdayParser.ts +69 -0
- package/src/locales/zh/hans/parsers/ZHHansTimeExpressionParser.ts +424 -0
- package/src/locales/zh/hans/parsers/ZHHansWeekdayParser.ts +46 -0
- package/src/locales/zh/hans/refiners/ZHHansMergeDateRangeRefiner.ts +7 -0
- package/src/locales/zh/hans/refiners/ZHHansMergeDateTimeRefiner.ts +7 -0
- package/src/locales/zh/hant/constants.ts +53 -0
- package/src/locales/zh/hant/index.ts +63 -0
- package/src/locales/zh/hant/parsers/ZHHantCasualDateParser.ts +128 -0
- package/src/locales/zh/hant/parsers/ZHHantDateParser.ts +68 -0
- package/src/locales/zh/hant/parsers/ZHHantDeadlineFormatParser.ts +81 -0
- package/src/locales/zh/hant/parsers/ZHHantRelationWeekdayParser.ts +69 -0
- package/src/locales/zh/hant/parsers/ZHHantTimeExpressionParser.ts +424 -0
- package/src/locales/zh/hant/parsers/ZHHantWeekdayParser.ts +46 -0
- package/src/locales/zh/hant/refiners/ZHHantMergeDateRangeRefiner.ts +7 -0
- package/src/locales/zh/hant/refiners/ZHHantMergeDateTimeRefiner.ts +7 -0
- package/src/locales/zh/index.ts +2 -0
- package/src/results.ts +11 -4
- package/src/timezone.ts +1 -1
- package/src/utils/dayjs.ts +6 -0
- package/test/en/en_casual.test.ts +11 -0
- package/test/en/en_merging_relative_dates.test.ts +51 -0
- package/test/en/en_month.test.ts +13 -0
- package/test/en/en_relative.test.ts +20 -0
- package/test/en/en_time_units_ago.test.ts +16 -0
- package/test/en/en_time_units_casual_relative.test.ts +16 -0
- package/test/en/en_time_units_later.test.ts +6 -0
- package/test/en/en_timezone_exp.test.ts +85 -10
- package/test/zh/zh.test.ts +18 -0
- package/test/zh/zh_hans_casual.test.ts +228 -0
- package/test/zh/zh_hans_date.test.ts +102 -0
- package/test/zh/zh_hans_deadline.test.ts +136 -0
- package/test/zh/zh_hans_time_exp.test.ts +182 -0
- package/test/zh/zh_hans_weekday.test.ts +132 -0
- package/test/zh/zh_hant_casual.test.ts +246 -0
- package/test/zh/zh_hant_date.test.ts +102 -0
- package/test/zh/zh_hant_deadline.test.ts +136 -0
- package/test/zh/zh_hant_time_exp.test.ts +182 -0
- package/test/zh/zh_hant_weekday.test.ts +132 -0
package/src/locales/en/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ import { ParsedResult, ParsingOption } from "../../index";
|
|
|
26
26
|
import { Chrono, Configuration } from "../../chrono";
|
|
27
27
|
import SlashDateFormatParser from "../../common/parsers/SlashDateFormatParser";
|
|
28
28
|
import ENTimeUnitCasualRelativeFormatParser from "./parsers/ENTimeUnitCasualRelativeFormatParser";
|
|
29
|
+
import ENMergeRelativeDateRefiner from "./refiners/ENMergeRelativeDateRefiner";
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* Chrono object configured for parsing *casual* English
|
|
@@ -91,7 +92,7 @@ export function createConfiguration(strictMode = true, littleEndian = false): Co
|
|
|
91
92
|
new ENTimeUnitAgoFormatParser(strictMode),
|
|
92
93
|
new ENTimeUnitLaterFormatParser(strictMode),
|
|
93
94
|
],
|
|
94
|
-
refiners: [new ENMergeDateTimeRefiner(), new ENMergeDateRangeRefiner()],
|
|
95
|
+
refiners: [new ENMergeRelativeDateRefiner(), new ENMergeDateTimeRefiner(), new ENMergeDateRangeRefiner()],
|
|
95
96
|
},
|
|
96
97
|
strictMode
|
|
97
98
|
);
|
|
@@ -36,8 +36,6 @@ export default class ENMonthNameLittleEndianParser extends AbstractParserWithWor
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingResult {
|
|
39
|
-
//console.log(match)
|
|
40
|
-
|
|
41
39
|
const result = context.createParsingResult(match.index, match[0]);
|
|
42
40
|
|
|
43
41
|
const month = MONTH_DICTIONARY[match[MONTH_NAME_GROUP].toLowerCase()];
|
|
@@ -6,7 +6,7 @@ import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/
|
|
|
6
6
|
import { matchAnyPattern } from "../../../utils/pattern";
|
|
7
7
|
|
|
8
8
|
const PATTERN = new RegExp(
|
|
9
|
-
`(this|
|
|
9
|
+
`(this|last|past|next|after\\s*this)\\s*(${matchAnyPattern(TIME_UNIT_DICTIONARY)})(?=\\s*)` + "(?=\\W|$)",
|
|
10
10
|
"i"
|
|
11
11
|
);
|
|
12
12
|
|
|
@@ -23,7 +23,7 @@ export default class ENRelativeDateFormatParser extends AbstractParserWithWordBo
|
|
|
23
23
|
const unitWord = match[RELATIVE_WORD_GROUP].toLowerCase();
|
|
24
24
|
const timeunit = TIME_UNIT_DICTIONARY[unitWord];
|
|
25
25
|
|
|
26
|
-
if (modifier == "next") {
|
|
26
|
+
if (modifier == "next" || modifier.startsWith("after")) {
|
|
27
27
|
const timeUnits = {};
|
|
28
28
|
timeUnits[timeunit] = 1;
|
|
29
29
|
return ParsingComponents.createRelativeFromReference(context.reference, timeUnits);
|
|
@@ -4,7 +4,7 @@ import { ParsingComponents } from "../../../results";
|
|
|
4
4
|
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
|
|
5
5
|
import { reverseTimeUnits } from "../../../utils/timeunits";
|
|
6
6
|
|
|
7
|
-
const PATTERN = new RegExp(`(this|last|past|next|\\+|-)\\s*(${TIME_UNITS_PATTERN})(?=\\W|$)`, "i");
|
|
7
|
+
const PATTERN = new RegExp(`(this|last|past|next|after|\\+|-)\\s*(${TIME_UNITS_PATTERN})(?=\\W|$)`, "i");
|
|
8
8
|
|
|
9
9
|
export default class ENTimeUnitCasualRelativeFormatParser extends AbstractParserWithWordBoundaryChecking {
|
|
10
10
|
innerPattern(): RegExp {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { MergingRefiner } from "../../../common/abstractRefiners";
|
|
2
|
+
import { ParsingComponents, ParsingResult, ReferenceWithTimezone } from "../../../results";
|
|
3
|
+
import { parseTimeUnits } from "../constants";
|
|
4
|
+
import { reverseTimeUnits } from "../../../utils/timeunits";
|
|
5
|
+
|
|
6
|
+
function hasImpliedEarlierReferenceDate(result: ParsingResult): boolean {
|
|
7
|
+
return result.text.match(/\s+(before|from)$/i) != null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function hasImpliedLaterReferenceDate(result: ParsingResult): boolean {
|
|
11
|
+
return result.text.match(/\s+(after|since)$/i) != null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Merges an absolute date with a relative date.
|
|
16
|
+
* - 2 weeks before 2020-02-13
|
|
17
|
+
* - 2 days after next Friday
|
|
18
|
+
*/
|
|
19
|
+
export default class ENMergeRelativeDateRefiner extends MergingRefiner {
|
|
20
|
+
patternBetween(): RegExp {
|
|
21
|
+
return /^\s*$/i;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
shouldMergeResults(textBetween: string, currentResult: ParsingResult, nextResult: ParsingResult): boolean {
|
|
25
|
+
// Dates need to be next to each other to get merged
|
|
26
|
+
if (!textBetween.match(this.patternBetween())) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Check if any relative tokens were swallowed by the first date.
|
|
31
|
+
// E.g. [<relative_date1> from] [<date2>]
|
|
32
|
+
if (!hasImpliedEarlierReferenceDate(currentResult) && !hasImpliedLaterReferenceDate(currentResult)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// make sure that <date2> implies an absolute date
|
|
37
|
+
return !!nextResult.start.get("day") && !!nextResult.start.get("month") && !!nextResult.start.get("year");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
mergeResults(textBetween: string, currentResult: ParsingResult, nextResult: ParsingResult): ParsingResult {
|
|
41
|
+
let timeUnits = parseTimeUnits(currentResult.text);
|
|
42
|
+
if (hasImpliedEarlierReferenceDate(currentResult)) {
|
|
43
|
+
timeUnits = reverseTimeUnits(timeUnits);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const components = ParsingComponents.createRelativeFromReference(
|
|
47
|
+
new ReferenceWithTimezone(nextResult.start.date()),
|
|
48
|
+
timeUnits
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
return new ParsingResult(
|
|
52
|
+
nextResult.reference,
|
|
53
|
+
currentResult.index,
|
|
54
|
+
`${currentResult.text}${textBetween}${nextResult.text}`,
|
|
55
|
+
components
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const NUMBER = {
|
|
2
|
+
"零": 0,
|
|
3
|
+
"〇": 0,
|
|
4
|
+
"一": 1,
|
|
5
|
+
"二": 2,
|
|
6
|
+
"两": 2,
|
|
7
|
+
"三": 3,
|
|
8
|
+
"四": 4,
|
|
9
|
+
"五": 5,
|
|
10
|
+
"六": 6,
|
|
11
|
+
"七": 7,
|
|
12
|
+
"八": 8,
|
|
13
|
+
"九": 9,
|
|
14
|
+
"十": 10,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const WEEKDAY_OFFSET = {
|
|
18
|
+
"天": 0,
|
|
19
|
+
"日": 0,
|
|
20
|
+
"一": 1,
|
|
21
|
+
"二": 2,
|
|
22
|
+
"三": 3,
|
|
23
|
+
"四": 4,
|
|
24
|
+
"五": 5,
|
|
25
|
+
"六": 6,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function zhStringToNumber(text: string) {
|
|
29
|
+
let number = 0;
|
|
30
|
+
|
|
31
|
+
for (let i = 0; i < text.length; i++) {
|
|
32
|
+
const char = text[i];
|
|
33
|
+
if (char === "十") {
|
|
34
|
+
number = number === 0 ? NUMBER[char] : number * NUMBER[char];
|
|
35
|
+
} else {
|
|
36
|
+
number += NUMBER[char];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function zhStringToYear(text: string) {
|
|
44
|
+
let string = "";
|
|
45
|
+
|
|
46
|
+
for (let i = 0; i < text.length; i++) {
|
|
47
|
+
const char = text[i];
|
|
48
|
+
string = string + NUMBER[char];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return parseInt(string);
|
|
52
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrono components for zh support
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Chrono, Configuration } from "../../../chrono";
|
|
6
|
+
import ExtractTimezoneOffsetRefiner from "../../../common/refiners/ExtractTimezoneOffsetRefiner";
|
|
7
|
+
import { includeCommonConfiguration } from "../../../configurations";
|
|
8
|
+
import { ParsedResult, ParsingOption } from "../../../index";
|
|
9
|
+
import ZHHansCasualDateParser from "./parsers/ZHHansCasualDateParser";
|
|
10
|
+
import ZHHansDateParser from "./parsers/ZHHansDateParser";
|
|
11
|
+
import ZHHansDeadlineFormatParser from "./parsers/ZHHansDeadlineFormatParser";
|
|
12
|
+
import ZHHansRelationWeekdayParser from "./parsers/ZHHansRelationWeekdayParser";
|
|
13
|
+
import ZHHansTimeExpressionParser from "./parsers/ZHHansTimeExpressionParser";
|
|
14
|
+
import ZHHansWeekdayParser from "./parsers/ZHHansWeekdayParser";
|
|
15
|
+
import ZHHansMergeDateRangeRefiner from "./refiners/ZHHansMergeDateRangeRefiner";
|
|
16
|
+
import ZHHansMergeDateTimeRefiner from "./refiners/ZHHansMergeDateTimeRefiner";
|
|
17
|
+
|
|
18
|
+
// Shortcuts
|
|
19
|
+
export const hans = new Chrono(createCasualConfiguration());
|
|
20
|
+
|
|
21
|
+
export const casual = new Chrono(createCasualConfiguration());
|
|
22
|
+
export const strict = new Chrono(createConfiguration());
|
|
23
|
+
|
|
24
|
+
export function parse(text: string, ref?: Date, option?: ParsingOption): ParsedResult[] {
|
|
25
|
+
return casual.parse(text, ref, option);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function parseDate(text: string, ref?: Date, option?: ParsingOption): Date {
|
|
29
|
+
return casual.parseDate(text, ref, option);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @ignore (to be documented later)
|
|
34
|
+
*/
|
|
35
|
+
export function createCasualConfiguration(): Configuration {
|
|
36
|
+
const option = createConfiguration();
|
|
37
|
+
option.parsers.unshift(new ZHHansCasualDateParser());
|
|
38
|
+
return option;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @ignore (to be documented later)
|
|
43
|
+
*/
|
|
44
|
+
export function createConfiguration(): Configuration {
|
|
45
|
+
const configuration = includeCommonConfiguration({
|
|
46
|
+
parsers: [
|
|
47
|
+
new ZHHansDateParser(),
|
|
48
|
+
new ZHHansRelationWeekdayParser(),
|
|
49
|
+
new ZHHansWeekdayParser(),
|
|
50
|
+
new ZHHansTimeExpressionParser(),
|
|
51
|
+
new ZHHansDeadlineFormatParser(),
|
|
52
|
+
],
|
|
53
|
+
refiners: [new ZHHansMergeDateRangeRefiner(), new ZHHansMergeDateTimeRefiner()],
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// REMOVE ExtractTimezoneOffsetRefiner
|
|
57
|
+
configuration.refiners = configuration.refiners.filter(
|
|
58
|
+
(refiner) => !(refiner instanceof ExtractTimezoneOffsetRefiner)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return configuration;
|
|
62
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
import { ParsingContext } from "../../../../chrono";
|
|
3
|
+
import { AbstractParserWithWordBoundaryChecking } from "../../../../common/parsers/AbstractParserWithWordBoundary";
|
|
4
|
+
import { ParsingComponents, ParsingResult } from "../../../../results";
|
|
5
|
+
|
|
6
|
+
const NOW_GROUP = 1;
|
|
7
|
+
const DAY_GROUP_1 = 2;
|
|
8
|
+
const TIME_GROUP_1 = 3;
|
|
9
|
+
const TIME_GROUP_2 = 4;
|
|
10
|
+
const DAY_GROUP_3 = 5;
|
|
11
|
+
const TIME_GROUP_3 = 6;
|
|
12
|
+
|
|
13
|
+
export default class ZHHansCasualDateParser extends AbstractParserWithWordBoundaryChecking {
|
|
14
|
+
innerPattern(context: ParsingContext): RegExp {
|
|
15
|
+
return new RegExp(
|
|
16
|
+
"(现在|立(?:刻|即)|即刻)|" +
|
|
17
|
+
"(今|明|前|大前|后|大后|昨)(早|晚)|" +
|
|
18
|
+
"(上(?:午)|早(?:上)|下(?:午)|晚(?:上)|夜(?:晚)?|中(?:午)|凌(?:晨))|" +
|
|
19
|
+
"(今|明|前|大前|后|大后|昨)(?:日|天)" +
|
|
20
|
+
"(?:[\\s|,|,]*)" +
|
|
21
|
+
"(?:(上(?:午)|早(?:上)|下(?:午)|晚(?:上)|夜(?:晚)?|中(?:午)|凌(?:晨)))?",
|
|
22
|
+
"i"
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingComponents | ParsingResult {
|
|
27
|
+
const index = match.index;
|
|
28
|
+
const result = context.createParsingResult(index, match[0]);
|
|
29
|
+
|
|
30
|
+
const refMoment = dayjs(context.refDate);
|
|
31
|
+
let startMoment = refMoment;
|
|
32
|
+
|
|
33
|
+
if (match[NOW_GROUP]) {
|
|
34
|
+
result.start.imply("hour", refMoment.hour());
|
|
35
|
+
result.start.imply("minute", refMoment.minute());
|
|
36
|
+
result.start.imply("second", refMoment.second());
|
|
37
|
+
result.start.imply("millisecond", refMoment.millisecond());
|
|
38
|
+
} else if (match[DAY_GROUP_1]) {
|
|
39
|
+
const day1 = match[DAY_GROUP_1];
|
|
40
|
+
const time1 = match[TIME_GROUP_1];
|
|
41
|
+
|
|
42
|
+
if (day1 == "明") {
|
|
43
|
+
// Check not "Tomorrow" on late night
|
|
44
|
+
if (refMoment.hour() > 1) {
|
|
45
|
+
startMoment = startMoment.add(1, "day");
|
|
46
|
+
}
|
|
47
|
+
} else if (day1 == "昨") {
|
|
48
|
+
startMoment = startMoment.add(-1, "day");
|
|
49
|
+
} else if (day1 == "前") {
|
|
50
|
+
startMoment = startMoment.add(-2, "day");
|
|
51
|
+
} else if (day1 == "大前") {
|
|
52
|
+
startMoment = startMoment.add(-3, "day");
|
|
53
|
+
} else if (day1 == "后") {
|
|
54
|
+
startMoment = startMoment.add(2, "day");
|
|
55
|
+
} else if (day1 == "大后") {
|
|
56
|
+
startMoment = startMoment.add(3, "day");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (time1 == "早") {
|
|
60
|
+
result.start.imply("hour", 6);
|
|
61
|
+
} else if (time1 == "晚") {
|
|
62
|
+
result.start.imply("hour", 22);
|
|
63
|
+
result.start.imply("meridiem", 1);
|
|
64
|
+
}
|
|
65
|
+
} else if (match[TIME_GROUP_2]) {
|
|
66
|
+
const timeString2 = match[TIME_GROUP_2];
|
|
67
|
+
const time2 = timeString2[0];
|
|
68
|
+
if (time2 == "早" || time2 == "上") {
|
|
69
|
+
result.start.imply("hour", 6);
|
|
70
|
+
} else if (time2 == "下") {
|
|
71
|
+
result.start.imply("hour", 15);
|
|
72
|
+
result.start.imply("meridiem", 1);
|
|
73
|
+
} else if (time2 == "中") {
|
|
74
|
+
result.start.imply("hour", 12);
|
|
75
|
+
result.start.imply("meridiem", 1);
|
|
76
|
+
} else if (time2 == "夜" || time2 == "晚") {
|
|
77
|
+
result.start.imply("hour", 22);
|
|
78
|
+
result.start.imply("meridiem", 1);
|
|
79
|
+
} else if (time2 == "凌") {
|
|
80
|
+
result.start.imply("hour", 0);
|
|
81
|
+
}
|
|
82
|
+
} else if (match[DAY_GROUP_3]) {
|
|
83
|
+
const day3 = match[DAY_GROUP_3];
|
|
84
|
+
|
|
85
|
+
if (day3 == "明") {
|
|
86
|
+
// Check not "Tomorrow" on late night
|
|
87
|
+
if (refMoment.hour() > 1) {
|
|
88
|
+
startMoment = startMoment.add(1, "day");
|
|
89
|
+
}
|
|
90
|
+
} else if (day3 == "昨") {
|
|
91
|
+
startMoment = startMoment.add(-1, "day");
|
|
92
|
+
} else if (day3 == "前") {
|
|
93
|
+
startMoment = startMoment.add(-2, "day");
|
|
94
|
+
} else if (day3 == "大前") {
|
|
95
|
+
startMoment = startMoment.add(-3, "day");
|
|
96
|
+
} else if (day3 == "后") {
|
|
97
|
+
startMoment = startMoment.add(2, "day");
|
|
98
|
+
} else if (day3 == "大后") {
|
|
99
|
+
startMoment = startMoment.add(3, "day");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const timeString3 = match[TIME_GROUP_3];
|
|
103
|
+
if (timeString3) {
|
|
104
|
+
const time3 = timeString3[0];
|
|
105
|
+
if (time3 == "早" || time3 == "上") {
|
|
106
|
+
result.start.imply("hour", 6);
|
|
107
|
+
} else if (time3 == "下") {
|
|
108
|
+
result.start.imply("hour", 15);
|
|
109
|
+
result.start.imply("meridiem", 1);
|
|
110
|
+
} else if (time3 == "中") {
|
|
111
|
+
result.start.imply("hour", 12);
|
|
112
|
+
result.start.imply("meridiem", 1);
|
|
113
|
+
} else if (time3 == "夜" || time3 == "晚") {
|
|
114
|
+
result.start.imply("hour", 22);
|
|
115
|
+
result.start.imply("meridiem", 1);
|
|
116
|
+
} else if (time3 == "凌") {
|
|
117
|
+
result.start.imply("hour", 0);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
result.start.assign("day", startMoment.date());
|
|
123
|
+
result.start.assign("month", startMoment.month() + 1);
|
|
124
|
+
result.start.assign("year", startMoment.year());
|
|
125
|
+
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
import { ParsingContext } from "../../../../chrono";
|
|
3
|
+
import { AbstractParserWithWordBoundaryChecking } from "../../../../common/parsers/AbstractParserWithWordBoundary";
|
|
4
|
+
import { NUMBER, zhStringToNumber, zhStringToYear } from "../constants";
|
|
5
|
+
|
|
6
|
+
const YEAR_GROUP = 1;
|
|
7
|
+
const MONTH_GROUP = 2;
|
|
8
|
+
const DAY_GROUP = 3;
|
|
9
|
+
|
|
10
|
+
export default class ZHHansDateParser extends AbstractParserWithWordBoundaryChecking {
|
|
11
|
+
innerPattern() {
|
|
12
|
+
// prettier-ignore
|
|
13
|
+
return new RegExp(
|
|
14
|
+
"(" +
|
|
15
|
+
"\\d{2,4}|" +
|
|
16
|
+
"[" +
|
|
17
|
+
Object.keys(NUMBER).join("") +
|
|
18
|
+
"]{4}|" +
|
|
19
|
+
"[" +
|
|
20
|
+
Object.keys(NUMBER).join("") +
|
|
21
|
+
"]{2}" +
|
|
22
|
+
")?" +
|
|
23
|
+
"(?:\\s*)" +
|
|
24
|
+
"(?:年)?" +
|
|
25
|
+
"(?:[\\s|,|,]*)" +
|
|
26
|
+
"(" +
|
|
27
|
+
"\\d{1,2}|" +
|
|
28
|
+
"[" +
|
|
29
|
+
Object.keys(NUMBER).join("") +
|
|
30
|
+
"]{1,3}" +
|
|
31
|
+
")" +
|
|
32
|
+
"(?:\\s*)" +
|
|
33
|
+
"(?:月)" +
|
|
34
|
+
"(?:\\s*)" +
|
|
35
|
+
"(" +
|
|
36
|
+
"\\d{1,2}|" +
|
|
37
|
+
"[" +
|
|
38
|
+
Object.keys(NUMBER).join("") +
|
|
39
|
+
"]{1,3}" +
|
|
40
|
+
")?" +
|
|
41
|
+
"(?:\\s*)" +
|
|
42
|
+
"(?:日|号)?"
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
innerExtract(context: ParsingContext, match: RegExpMatchArray) {
|
|
47
|
+
const startMoment = dayjs(context.refDate);
|
|
48
|
+
const result = context.createParsingResult(match.index, match[0]);
|
|
49
|
+
|
|
50
|
+
//Month
|
|
51
|
+
let month = parseInt(match[MONTH_GROUP]);
|
|
52
|
+
if (isNaN(month)) month = zhStringToNumber(match[MONTH_GROUP]);
|
|
53
|
+
result.start.assign("month", month);
|
|
54
|
+
|
|
55
|
+
//Day
|
|
56
|
+
if (match[DAY_GROUP]) {
|
|
57
|
+
let day = parseInt(match[DAY_GROUP]);
|
|
58
|
+
if (isNaN(day)) day = zhStringToNumber(match[DAY_GROUP]);
|
|
59
|
+
result.start.assign("day", day);
|
|
60
|
+
} else {
|
|
61
|
+
result.start.imply("day", startMoment.date());
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//Year
|
|
65
|
+
if (match[YEAR_GROUP]) {
|
|
66
|
+
let year = parseInt(match[YEAR_GROUP]);
|
|
67
|
+
if (isNaN(year)) year = zhStringToYear(match[YEAR_GROUP]);
|
|
68
|
+
result.start.assign("year", year);
|
|
69
|
+
} else {
|
|
70
|
+
result.start.imply("year", startMoment.year());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
import { ParsingContext } from "../../../../chrono";
|
|
3
|
+
import { AbstractParserWithWordBoundaryChecking } from "../../../../common/parsers/AbstractParserWithWordBoundary";
|
|
4
|
+
import { NUMBER, zhStringToNumber } from "../constants";
|
|
5
|
+
|
|
6
|
+
const PATTERN = new RegExp(
|
|
7
|
+
"(\\d+|[" +
|
|
8
|
+
Object.keys(NUMBER).join("") +
|
|
9
|
+
"]+|半|几)(?:\\s*)" +
|
|
10
|
+
"(?:个)?" +
|
|
11
|
+
"(秒(?:钟)?|分钟|小时|钟|日|天|星期|礼拜|月|年)" +
|
|
12
|
+
"(?:(?:之|过)?后|(?:之)?内)",
|
|
13
|
+
"i"
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const NUMBER_GROUP = 1;
|
|
17
|
+
const UNIT_GROUP = 2;
|
|
18
|
+
|
|
19
|
+
export default class ZHHansDeadlineFormatParser extends AbstractParserWithWordBoundaryChecking {
|
|
20
|
+
innerPattern(): RegExp {
|
|
21
|
+
return PATTERN;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
innerExtract(context: ParsingContext, match: RegExpMatchArray) {
|
|
25
|
+
const result = context.createParsingResult(match.index, match[0]);
|
|
26
|
+
|
|
27
|
+
let number = parseInt(match[NUMBER_GROUP]);
|
|
28
|
+
if (isNaN(number)) {
|
|
29
|
+
number = zhStringToNumber(match[NUMBER_GROUP]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (isNaN(number)) {
|
|
33
|
+
const string = match[NUMBER_GROUP];
|
|
34
|
+
if (string === "几") {
|
|
35
|
+
number = 3;
|
|
36
|
+
} else if (string === "半") {
|
|
37
|
+
number = 0.5;
|
|
38
|
+
} else {
|
|
39
|
+
//just in case
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let date = dayjs(context.refDate);
|
|
45
|
+
const unit = match[UNIT_GROUP];
|
|
46
|
+
const unitAbbr = unit[0];
|
|
47
|
+
|
|
48
|
+
if (unitAbbr.match(/[日天星礼月年]/)) {
|
|
49
|
+
if (unitAbbr == "日" || unitAbbr == "天") {
|
|
50
|
+
date = date.add(number, "d");
|
|
51
|
+
} else if (unitAbbr == "星" || unitAbbr == "礼") {
|
|
52
|
+
date = date.add(number * 7, "d");
|
|
53
|
+
} else if (unitAbbr == "月") {
|
|
54
|
+
date = date.add(number, "month");
|
|
55
|
+
} else if (unitAbbr == "年") {
|
|
56
|
+
date = date.add(number, "year");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
result.start.assign("year", date.year());
|
|
60
|
+
result.start.assign("month", date.month() + 1);
|
|
61
|
+
result.start.assign("day", date.date());
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (unitAbbr == "秒") {
|
|
66
|
+
date = date.add(number, "second");
|
|
67
|
+
} else if (unitAbbr == "分") {
|
|
68
|
+
date = date.add(number, "minute");
|
|
69
|
+
} else if (unitAbbr == "小" || unitAbbr == "钟") {
|
|
70
|
+
date = date.add(number, "hour");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
result.start.imply("year", date.year());
|
|
74
|
+
result.start.imply("month", date.month() + 1);
|
|
75
|
+
result.start.imply("day", date.date());
|
|
76
|
+
result.start.assign("hour", date.hour());
|
|
77
|
+
result.start.assign("minute", date.minute());
|
|
78
|
+
result.start.assign("second", date.second());
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
import { ParsingContext } from "../../../../chrono";
|
|
3
|
+
import { AbstractParserWithWordBoundaryChecking } from "../../../../common/parsers/AbstractParserWithWordBoundary";
|
|
4
|
+
import { ParsingResult } from "../../../../results";
|
|
5
|
+
import { WEEKDAY_OFFSET } from "../constants";
|
|
6
|
+
|
|
7
|
+
const PATTERN = new RegExp(
|
|
8
|
+
"(?<prefix>上|下|这)(?:个)?(?:星期|礼拜|周)(?<weekday>" + Object.keys(WEEKDAY_OFFSET).join("|") + ")"
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
export default class ZHHansRelationWeekdayParser extends AbstractParserWithWordBoundaryChecking {
|
|
12
|
+
innerPattern(): RegExp {
|
|
13
|
+
return PATTERN;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
innerExtract(context: ParsingContext, match: RegExpMatchArray): ParsingResult {
|
|
17
|
+
const result = context.createParsingResult(match.index, match[0]);
|
|
18
|
+
|
|
19
|
+
const dayOfWeek = match.groups.weekday;
|
|
20
|
+
const offset = WEEKDAY_OFFSET[dayOfWeek];
|
|
21
|
+
if (offset === undefined) return null;
|
|
22
|
+
|
|
23
|
+
let modifier = null;
|
|
24
|
+
const prefix = match.groups.prefix;
|
|
25
|
+
|
|
26
|
+
if (prefix == "上") {
|
|
27
|
+
modifier = "last";
|
|
28
|
+
} else if (prefix == "下") {
|
|
29
|
+
modifier = "next";
|
|
30
|
+
} else if (prefix == "这") {
|
|
31
|
+
modifier = "this";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let startMoment = dayjs(context.refDate);
|
|
35
|
+
let startMomentFixed = false;
|
|
36
|
+
const refOffset = startMoment.day();
|
|
37
|
+
|
|
38
|
+
if (modifier == "last" || modifier == "past") {
|
|
39
|
+
startMoment = startMoment.day(offset - 7);
|
|
40
|
+
startMomentFixed = true;
|
|
41
|
+
} else if (modifier == "next") {
|
|
42
|
+
startMoment = startMoment.day(offset + 7);
|
|
43
|
+
startMomentFixed = true;
|
|
44
|
+
} else if (modifier == "this") {
|
|
45
|
+
startMoment = startMoment.day(offset);
|
|
46
|
+
} else {
|
|
47
|
+
if (Math.abs(offset - 7 - refOffset) < Math.abs(offset - refOffset)) {
|
|
48
|
+
startMoment = startMoment.day(offset - 7);
|
|
49
|
+
} else if (Math.abs(offset + 7 - refOffset) < Math.abs(offset - refOffset)) {
|
|
50
|
+
startMoment = startMoment.day(offset + 7);
|
|
51
|
+
} else {
|
|
52
|
+
startMoment = startMoment.day(offset);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
result.start.assign("weekday", offset);
|
|
57
|
+
if (startMomentFixed) {
|
|
58
|
+
result.start.assign("day", startMoment.date());
|
|
59
|
+
result.start.assign("month", startMoment.month() + 1);
|
|
60
|
+
result.start.assign("year", startMoment.year());
|
|
61
|
+
} else {
|
|
62
|
+
result.start.imply("day", startMoment.date());
|
|
63
|
+
result.start.imply("month", startMoment.month() + 1);
|
|
64
|
+
result.start.imply("year", startMoment.year());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
}
|