chrono-node 2.9.1 → 2.9.2
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/cjs/locales/de/parsers/DECasualTimeParser.js +7 -0
- package/dist/cjs/locales/de/parsers/DECasualTimeParser.js.map +1 -1
- package/dist/cjs/locales/en/configuration.js +2 -0
- package/dist/cjs/locales/en/configuration.js.map +1 -1
- package/dist/cjs/locales/en/parsers/ENMonthNameLittleEndianParser.js +1 -1
- package/dist/cjs/locales/en/parsers/ENMonthNameLittleEndianParser.js.map +1 -1
- package/dist/cjs/locales/en/parsers/ENYearMonthNameParser.d.ts +6 -0
- package/dist/cjs/locales/en/parsers/ENYearMonthNameParser.js +31 -0
- package/dist/cjs/locales/en/parsers/ENYearMonthNameParser.js.map +1 -0
- package/dist/cjs/locales/fi/parsers/FICasualTimeParser.js +7 -0
- package/dist/cjs/locales/fi/parsers/FICasualTimeParser.js.map +1 -1
- package/dist/cjs/locales/fr/parsers/FRCasualTimeParser.js +5 -0
- package/dist/cjs/locales/fr/parsers/FRCasualTimeParser.js.map +1 -1
- package/dist/cjs/locales/fr/parsers/FRTimeUnitRelativeFormatParser.js +2 -1
- package/dist/cjs/locales/fr/parsers/FRTimeUnitRelativeFormatParser.js.map +1 -1
- package/dist/cjs/locales/it/parsers/ITCasualTimeParser.js +5 -0
- package/dist/cjs/locales/it/parsers/ITCasualTimeParser.js.map +1 -1
- package/dist/cjs/locales/uk/parsers/UKTimeUnitWithinFormatParser.js +1 -1
- package/dist/cjs/locales/uk/parsers/UKTimeUnitWithinFormatParser.js.map +1 -1
- package/dist/cjs/locales/zh/hans/index.js +2 -0
- package/dist/cjs/locales/zh/hans/index.js.map +1 -1
- package/dist/cjs/locales/zh/hans/parsers/ZHHansAgoFormatParser.d.ts +6 -0
- package/dist/cjs/locales/zh/hans/parsers/ZHHansAgoFormatParser.js +80 -0
- package/dist/cjs/locales/zh/hans/parsers/ZHHansAgoFormatParser.js.map +1 -0
- package/dist/cjs/locales/zh/hant/index.js +2 -0
- package/dist/cjs/locales/zh/hant/index.js.map +1 -1
- package/dist/cjs/locales/zh/hant/parsers/ZHHantAgoFormatParser.d.ts +6 -0
- package/dist/cjs/locales/zh/hant/parsers/ZHHantAgoFormatParser.js +80 -0
- package/dist/cjs/locales/zh/hant/parsers/ZHHantAgoFormatParser.js.map +1 -0
- package/dist/esm/locales/de/parsers/DECasualTimeParser.js +7 -0
- package/dist/esm/locales/de/parsers/DECasualTimeParser.js.map +1 -1
- package/dist/esm/locales/en/configuration.js +2 -0
- package/dist/esm/locales/en/configuration.js.map +1 -1
- package/dist/esm/locales/en/parsers/ENMonthNameLittleEndianParser.js +1 -1
- package/dist/esm/locales/en/parsers/ENMonthNameLittleEndianParser.js.map +1 -1
- package/dist/esm/locales/en/parsers/ENYearMonthNameParser.d.ts +6 -0
- package/dist/esm/locales/en/parsers/ENYearMonthNameParser.js +28 -0
- package/dist/esm/locales/en/parsers/ENYearMonthNameParser.js.map +1 -0
- package/dist/esm/locales/fi/parsers/FICasualTimeParser.js +7 -0
- package/dist/esm/locales/fi/parsers/FICasualTimeParser.js.map +1 -1
- package/dist/esm/locales/fr/parsers/FRCasualTimeParser.js +5 -0
- package/dist/esm/locales/fr/parsers/FRCasualTimeParser.js.map +1 -1
- package/dist/esm/locales/fr/parsers/FRTimeUnitRelativeFormatParser.js +2 -1
- package/dist/esm/locales/fr/parsers/FRTimeUnitRelativeFormatParser.js.map +1 -1
- package/dist/esm/locales/it/parsers/ITCasualTimeParser.js +5 -0
- package/dist/esm/locales/it/parsers/ITCasualTimeParser.js.map +1 -1
- package/dist/esm/locales/uk/parsers/UKTimeUnitWithinFormatParser.js +1 -1
- package/dist/esm/locales/uk/parsers/UKTimeUnitWithinFormatParser.js.map +1 -1
- package/dist/esm/locales/zh/hans/index.js +2 -0
- package/dist/esm/locales/zh/hans/index.js.map +1 -1
- package/dist/esm/locales/zh/hans/parsers/ZHHansAgoFormatParser.d.ts +6 -0
- package/dist/esm/locales/zh/hans/parsers/ZHHansAgoFormatParser.js +77 -0
- package/dist/esm/locales/zh/hans/parsers/ZHHansAgoFormatParser.js.map +1 -0
- package/dist/esm/locales/zh/hant/index.js +2 -0
- package/dist/esm/locales/zh/hant/index.js.map +1 -1
- package/dist/esm/locales/zh/hant/parsers/ZHHantAgoFormatParser.d.ts +6 -0
- package/dist/esm/locales/zh/hant/parsers/ZHHantAgoFormatParser.js +77 -0
- package/dist/esm/locales/zh/hant/parsers/ZHHantAgoFormatParser.js.map +1 -0
- package/package.json +1 -1
- package/src/locales/de/parsers/DECasualTimeParser.ts +7 -0
- package/src/locales/en/configuration.ts +2 -0
- package/src/locales/en/parsers/ENMonthNameLittleEndianParser.ts +1 -1
- package/src/locales/en/parsers/ENYearMonthNameParser.ts +38 -0
- package/src/locales/fi/parsers/FICasualTimeParser.ts +7 -0
- package/src/locales/fr/parsers/FRCasualTimeParser.ts +5 -0
- package/src/locales/fr/parsers/FRTimeUnitRelativeFormatParser.ts +2 -1
- package/src/locales/it/parsers/ITCasualTimeParser.ts +5 -0
- package/src/locales/uk/parsers/UKTimeUnitWithinFormatParser.ts +1 -1
- package/src/locales/zh/hans/index.ts +2 -0
- package/src/locales/zh/hans/parsers/ZHHansAgoFormatParser.ts +87 -0
- package/src/locales/zh/hant/index.ts +2 -0
- package/src/locales/zh/hant/parsers/ZHHantAgoFormatParser.ts +87 -0
- package/test/de/de_casual.test.ts +14 -0
- package/test/en/en_month.test.ts +44 -0
- package/test/fi/fi_casual.test.ts +14 -0
- package/test/fr/fr_casual.test.ts +14 -0
- package/test/fr/fr_time_units_casual_relative.test.ts +6 -0
- package/test/it/it_casual.test.ts +37 -0
- package/test/uk/uk_time_units_within.test.ts +8 -1
- package/test/zh/hans/zh_hans_ago.test.ts +58 -0
- package/test/zh/hant/zh_hant_ago.test.ts +58 -0
|
@@ -24,6 +24,7 @@ export default class DECasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
24
24
|
component.imply("minute", 0);
|
|
25
25
|
component.imply("second", 0);
|
|
26
26
|
component.imply("meridiem", Meridiem.AM);
|
|
27
|
+
component.addTag("casualReference/morning");
|
|
27
28
|
break;
|
|
28
29
|
|
|
29
30
|
case "vormittag":
|
|
@@ -31,6 +32,7 @@ export default class DECasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
31
32
|
component.imply("minute", 0);
|
|
32
33
|
component.imply("second", 0);
|
|
33
34
|
component.imply("meridiem", Meridiem.AM);
|
|
35
|
+
component.addTag("casualReference/morning");
|
|
34
36
|
break;
|
|
35
37
|
|
|
36
38
|
case "mittag":
|
|
@@ -39,6 +41,7 @@ export default class DECasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
39
41
|
component.imply("minute", 0);
|
|
40
42
|
component.imply("second", 0);
|
|
41
43
|
component.imply("meridiem", Meridiem.AM);
|
|
44
|
+
component.addTag("casualReference/noon");
|
|
42
45
|
break;
|
|
43
46
|
|
|
44
47
|
case "nachmittag":
|
|
@@ -46,6 +49,7 @@ export default class DECasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
46
49
|
component.imply("minute", 0);
|
|
47
50
|
component.imply("second", 0);
|
|
48
51
|
component.imply("meridiem", Meridiem.PM);
|
|
52
|
+
component.addTag("casualReference/afternoon");
|
|
49
53
|
break;
|
|
50
54
|
|
|
51
55
|
case "abend":
|
|
@@ -53,6 +57,7 @@ export default class DECasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
53
57
|
component.imply("minute", 0);
|
|
54
58
|
component.imply("second", 0);
|
|
55
59
|
component.imply("meridiem", Meridiem.PM);
|
|
60
|
+
component.addTag("casualReference/evening");
|
|
56
61
|
break;
|
|
57
62
|
|
|
58
63
|
case "nacht":
|
|
@@ -60,6 +65,7 @@ export default class DECasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
60
65
|
component.imply("minute", 0);
|
|
61
66
|
component.imply("second", 0);
|
|
62
67
|
component.imply("meridiem", Meridiem.PM);
|
|
68
|
+
component.addTag("casualReference/evening");
|
|
63
69
|
break;
|
|
64
70
|
|
|
65
71
|
case "mitternacht":
|
|
@@ -71,6 +77,7 @@ export default class DECasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
71
77
|
component.imply("minute", 0);
|
|
72
78
|
component.imply("second", 0);
|
|
73
79
|
component.imply("meridiem", Meridiem.AM);
|
|
80
|
+
component.addTag("casualReference/midnight");
|
|
74
81
|
break;
|
|
75
82
|
}
|
|
76
83
|
return component;
|
|
@@ -5,6 +5,7 @@ import ENMonthNameLittleEndianParser from "./parsers/ENMonthNameLittleEndianPars
|
|
|
5
5
|
import ENMonthNameMiddleEndianParser from "./parsers/ENMonthNameMiddleEndianParser";
|
|
6
6
|
import ENMonthNameParser from "./parsers/ENMonthNameParser";
|
|
7
7
|
import ENYearMonthDayParser from "./parsers/ENYearMonthDayParser";
|
|
8
|
+
import ENYearMonthNameParser from "./parsers/ENYearMonthNameParser";
|
|
8
9
|
import ENSlashMonthFormatParser from "./parsers/ENSlashMonthFormatParser";
|
|
9
10
|
import ENTimeExpressionParser from "./parsers/ENTimeExpressionParser";
|
|
10
11
|
import ENTimeUnitAgoFormatParser from "./parsers/ENTimeUnitAgoFormatParser";
|
|
@@ -61,6 +62,7 @@ export default class ENDefaultConfiguration {
|
|
|
61
62
|
new ENTimeExpressionParser(strictMode),
|
|
62
63
|
new ENTimeUnitAgoFormatParser(strictMode),
|
|
63
64
|
new ENTimeUnitLaterFormatParser(strictMode),
|
|
65
|
+
new ENYearMonthNameParser(),
|
|
64
66
|
],
|
|
65
67
|
refiners: [new ENMergeDateTimeRefiner()],
|
|
66
68
|
},
|
|
@@ -12,7 +12,7 @@ const PATTERN = new RegExp(
|
|
|
12
12
|
`(?:on\\s{0,3})?` +
|
|
13
13
|
`(${ORDINAL_NUMBER_PATTERN})` +
|
|
14
14
|
`(?:` +
|
|
15
|
-
`\\s{0,3}(?:to|\\-|\\–|until|through|till)
|
|
15
|
+
`\\s{0,3}(?:to|\\-|\\–|until|through|till)\\s{0,3}` +
|
|
16
16
|
`(${ORDINAL_NUMBER_PATTERN})` +
|
|
17
17
|
")?" +
|
|
18
18
|
`(?:-|/|\\s{0,3}(?:of)?\\s{0,3})` +
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { MONTH_DICTIONARY } from "../constants";
|
|
2
|
+
import { ParsingContext } from "../../../chrono";
|
|
3
|
+
import { matchAnyPattern } from "../../../utils/pattern";
|
|
4
|
+
import { parseYear } from "../constants";
|
|
5
|
+
import { AbstractParserWithWordBoundaryChecking } from "../../../common/parsers/AbstractParserWithWordBoundary";
|
|
6
|
+
|
|
7
|
+
const YEAR_PATTERN = `(?:[1-9][0-9]{0,3}\\s{0,2}(?:BE|AD|BC|BCE|CE)|[1-9][0-9]{3})`;
|
|
8
|
+
|
|
9
|
+
const PATTERN = new RegExp(
|
|
10
|
+
`(${YEAR_PATTERN})` +
|
|
11
|
+
`(?:\\s*[-.\\/,]?\\s*|\\s+of\\s+)` +
|
|
12
|
+
`(${matchAnyPattern(MONTH_DICTIONARY)})` +
|
|
13
|
+
`(?=[^\\s\\w]|\\s+[^0-9]|\\s+$|$)`,
|
|
14
|
+
"i"
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const YEAR_GROUP = 1;
|
|
18
|
+
const MONTH_NAME_GROUP = 2;
|
|
19
|
+
|
|
20
|
+
export default class ENYearMonthNameParser extends AbstractParserWithWordBoundaryChecking {
|
|
21
|
+
innerPattern(): RegExp {
|
|
22
|
+
return PATTERN;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
innerExtract(context: ParsingContext, match: RegExpMatchArray) {
|
|
26
|
+
const year = parseYear(match[YEAR_GROUP]);
|
|
27
|
+
const monthName = match[MONTH_NAME_GROUP].toLowerCase();
|
|
28
|
+
const month = MONTH_DICTIONARY[monthName];
|
|
29
|
+
|
|
30
|
+
const result = context.createParsingResult(match.index, match[0]);
|
|
31
|
+
result.start.imply("day", 1);
|
|
32
|
+
result.start.assign("month", month);
|
|
33
|
+
result.start.assign("year", year);
|
|
34
|
+
result.start.addTag("parser/ENYearMonthNameParser");
|
|
35
|
+
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -25,6 +25,7 @@ export default class FICasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
25
25
|
component.imply("minute", 0);
|
|
26
26
|
component.imply("second", 0);
|
|
27
27
|
component.imply("meridiem", Meridiem.AM);
|
|
28
|
+
component.addTag("casualReference/morning");
|
|
28
29
|
break;
|
|
29
30
|
|
|
30
31
|
case "aamupäivällä":
|
|
@@ -32,6 +33,7 @@ export default class FICasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
32
33
|
component.imply("minute", 0);
|
|
33
34
|
component.imply("second", 0);
|
|
34
35
|
component.imply("meridiem", Meridiem.AM);
|
|
36
|
+
component.addTag("casualReference/morning");
|
|
35
37
|
break;
|
|
36
38
|
|
|
37
39
|
case "päivällä":
|
|
@@ -39,6 +41,7 @@ export default class FICasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
39
41
|
component.imply("minute", 0);
|
|
40
42
|
component.imply("second", 0);
|
|
41
43
|
component.imply("meridiem", Meridiem.AM);
|
|
44
|
+
component.addTag("casualReference/noon");
|
|
42
45
|
break;
|
|
43
46
|
|
|
44
47
|
case "iltapäivällä":
|
|
@@ -46,6 +49,7 @@ export default class FICasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
46
49
|
component.imply("minute", 0);
|
|
47
50
|
component.imply("second", 0);
|
|
48
51
|
component.imply("meridiem", Meridiem.PM);
|
|
52
|
+
component.addTag("casualReference/afternoon");
|
|
49
53
|
break;
|
|
50
54
|
|
|
51
55
|
case "illalla":
|
|
@@ -53,6 +57,7 @@ export default class FICasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
53
57
|
component.imply("minute", 0);
|
|
54
58
|
component.imply("second", 0);
|
|
55
59
|
component.imply("meridiem", Meridiem.PM);
|
|
60
|
+
component.addTag("casualReference/evening");
|
|
56
61
|
break;
|
|
57
62
|
|
|
58
63
|
case "yöllä":
|
|
@@ -60,6 +65,7 @@ export default class FICasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
60
65
|
component.imply("minute", 0);
|
|
61
66
|
component.imply("second", 0);
|
|
62
67
|
component.imply("meridiem", Meridiem.PM);
|
|
68
|
+
component.addTag("casualReference/evening");
|
|
63
69
|
break;
|
|
64
70
|
|
|
65
71
|
case "keskiyöllä":
|
|
@@ -71,6 +77,7 @@ export default class FICasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
71
77
|
component.imply("minute", 0);
|
|
72
78
|
component.imply("second", 0);
|
|
73
79
|
component.imply("meridiem", Meridiem.AM);
|
|
80
|
+
component.addTag("casualReference/midnight");
|
|
74
81
|
break;
|
|
75
82
|
}
|
|
76
83
|
return component;
|
|
@@ -18,29 +18,34 @@ export default class FRCasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
18
18
|
component.imply("hour", 14);
|
|
19
19
|
component.imply("minute", 0);
|
|
20
20
|
component.imply("meridiem", Meridiem.PM);
|
|
21
|
+
component.addTag("casualReference/afternoon");
|
|
21
22
|
break;
|
|
22
23
|
|
|
23
24
|
case "soir":
|
|
24
25
|
component.imply("hour", 18);
|
|
25
26
|
component.imply("minute", 0);
|
|
26
27
|
component.imply("meridiem", Meridiem.PM);
|
|
28
|
+
component.addTag("casualReference/evening");
|
|
27
29
|
break;
|
|
28
30
|
|
|
29
31
|
case "matin":
|
|
30
32
|
component.imply("hour", 8);
|
|
31
33
|
component.imply("minute", 0);
|
|
32
34
|
component.imply("meridiem", Meridiem.AM);
|
|
35
|
+
component.addTag("casualReference/morning");
|
|
33
36
|
break;
|
|
34
37
|
|
|
35
38
|
case "a midi":
|
|
36
39
|
component.imply("hour", 12);
|
|
37
40
|
component.imply("minute", 0);
|
|
38
41
|
component.imply("meridiem", Meridiem.AM);
|
|
42
|
+
component.addTag("casualReference/noon");
|
|
39
43
|
break;
|
|
40
44
|
|
|
41
45
|
case "à minuit":
|
|
42
46
|
component.imply("hour", 0);
|
|
43
47
|
component.imply("meridiem", Meridiem.AM);
|
|
48
|
+
component.addTag("casualReference/midnight");
|
|
44
49
|
break;
|
|
45
50
|
}
|
|
46
51
|
|
|
@@ -16,7 +16,8 @@ export default class FRTimeUnitAgoFormatParser extends AbstractParserWithWordBou
|
|
|
16
16
|
`(${NUMBER_PATTERN})?` +
|
|
17
17
|
`(?:\\s*(prochaine?s?|derni[eè]re?s?|pass[ée]e?s?|pr[ée]c[ée]dents?|suivante?s?))?` +
|
|
18
18
|
`\\s*(${matchAnyPattern(TIME_UNIT_DICTIONARY)})` +
|
|
19
|
-
`(?:\\s*(prochaine?s?|derni[eè]re?s?|pass[ée]e?s?|pr[ée]c[ée]dents?|suivante?s?))
|
|
19
|
+
`(?:\\s*(prochaine?s?|derni[eè]re?s?|pass[ée]e?s?|pr[ée]c[ée]dents?|suivante?s?))?` +
|
|
20
|
+
`(?=\\W|$)`,
|
|
20
21
|
"i"
|
|
21
22
|
);
|
|
22
23
|
}
|
|
@@ -18,12 +18,14 @@ export default class ITCasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
18
18
|
case "pomeriggio":
|
|
19
19
|
component.imply("meridiem", Meridiem.PM);
|
|
20
20
|
component.imply("hour", 15);
|
|
21
|
+
component.addTag("casualReference/afternoon");
|
|
21
22
|
break;
|
|
22
23
|
|
|
23
24
|
case "sera":
|
|
24
25
|
case "notte":
|
|
25
26
|
component.imply("meridiem", Meridiem.PM);
|
|
26
27
|
component.imply("hour", 20);
|
|
28
|
+
component.addTag("casualReference/evening");
|
|
27
29
|
break;
|
|
28
30
|
|
|
29
31
|
case "mezzanotte":
|
|
@@ -34,16 +36,19 @@ export default class ITCasualTimeParser extends AbstractParserWithWordBoundaryCh
|
|
|
34
36
|
component.imply("hour", 0);
|
|
35
37
|
component.imply("minute", 0);
|
|
36
38
|
component.imply("second", 0);
|
|
39
|
+
component.addTag("casualReference/midnight");
|
|
37
40
|
break;
|
|
38
41
|
|
|
39
42
|
case "mattina":
|
|
40
43
|
component.imply("meridiem", Meridiem.AM);
|
|
41
44
|
component.imply("hour", 6);
|
|
45
|
+
component.addTag("casualReference/morning");
|
|
42
46
|
break;
|
|
43
47
|
|
|
44
48
|
case "mezzogiorno":
|
|
45
49
|
component.imply("meridiem", Meridiem.AM);
|
|
46
50
|
component.imply("hour", 12);
|
|
51
|
+
component.addTag("casualReference/noon");
|
|
47
52
|
break;
|
|
48
53
|
}
|
|
49
54
|
|
|
@@ -12,7 +12,7 @@ export default class UKTimeUnitWithinFormatParser extends AbstractParserWithWord
|
|
|
12
12
|
|
|
13
13
|
innerPattern(context: ParsingContext): RegExp {
|
|
14
14
|
return context.option.forwardDate
|
|
15
|
-
? new RegExp(PATTERN,
|
|
15
|
+
? new RegExp(PATTERN, REGEX_PARTS.flags)
|
|
16
16
|
: new RegExp(`(?:протягом|на протязі|протягом|упродовж|впродовж)\\s*${PATTERN}`, REGEX_PARTS.flags);
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -10,6 +10,7 @@ import { Component, ParsedResult, ParsingOption, ParsingReference, Meridiem, Wee
|
|
|
10
10
|
import ZHHansCasualDateParser from "./parsers/ZHHansCasualDateParser";
|
|
11
11
|
import ZHHansDateParser from "./parsers/ZHHansDateParser";
|
|
12
12
|
import ZHHansDeadlineFormatParser from "./parsers/ZHHansDeadlineFormatParser";
|
|
13
|
+
import ZHHansAgoFormatParser from "./parsers/ZHHansAgoFormatParser";
|
|
13
14
|
import ZHHansRelationWeekdayParser from "./parsers/ZHHansRelationWeekdayParser";
|
|
14
15
|
import ZHHansTimeExpressionParser from "./parsers/ZHHansTimeExpressionParser";
|
|
15
16
|
import ZHHansWeekdayParser from "./parsers/ZHHansWeekdayParser";
|
|
@@ -53,6 +54,7 @@ export function createConfiguration(): Configuration {
|
|
|
53
54
|
new ZHHansWeekdayParser(),
|
|
54
55
|
new ZHHansTimeExpressionParser(),
|
|
55
56
|
new ZHHansDeadlineFormatParser(),
|
|
57
|
+
new ZHHansAgoFormatParser(),
|
|
56
58
|
],
|
|
57
59
|
refiners: [new ZHHansMergeDateRangeRefiner(), new ZHHansMergeDateTimeRefiner()],
|
|
58
60
|
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ParsingContext } from "../../../../chrono";
|
|
2
|
+
import { AbstractParserWithWordBoundaryChecking } from "../../../../common/parsers/AbstractParserWithWordBoundary";
|
|
3
|
+
import { addDuration, Duration, reverseDuration } from "../../../../calculation/duration";
|
|
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 ZHHansAgoFormatParser 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 duration: Duration = {};
|
|
45
|
+
const unit = match[UNIT_GROUP];
|
|
46
|
+
const unitAbbr = unit[0];
|
|
47
|
+
|
|
48
|
+
if (unitAbbr.match(/[日天星礼月年]/)) {
|
|
49
|
+
if (unitAbbr == "日" || unitAbbr == "天") {
|
|
50
|
+
duration.day = number;
|
|
51
|
+
} else if (unitAbbr == "星" || unitAbbr == "礼") {
|
|
52
|
+
duration.week = number;
|
|
53
|
+
} else if (unitAbbr == "月") {
|
|
54
|
+
duration.month = number;
|
|
55
|
+
} else if (unitAbbr == "年") {
|
|
56
|
+
duration.year = number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
duration = reverseDuration(duration);
|
|
60
|
+
|
|
61
|
+
const date = addDuration(context.refDate, duration);
|
|
62
|
+
result.start.assign("year", date.getFullYear());
|
|
63
|
+
result.start.assign("month", date.getMonth() + 1);
|
|
64
|
+
result.start.assign("day", date.getDate());
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (unitAbbr == "秒") {
|
|
69
|
+
duration.second = number;
|
|
70
|
+
} else if (unitAbbr == "分") {
|
|
71
|
+
duration.minute = number;
|
|
72
|
+
} else if (unitAbbr == "小" || unitAbbr == "钟") {
|
|
73
|
+
duration.hour = number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
duration = reverseDuration(duration);
|
|
77
|
+
|
|
78
|
+
const date = addDuration(context.refDate, duration);
|
|
79
|
+
result.start.imply("year", date.getFullYear());
|
|
80
|
+
result.start.imply("month", date.getMonth() + 1);
|
|
81
|
+
result.start.imply("day", date.getDate());
|
|
82
|
+
result.start.assign("hour", date.getHours());
|
|
83
|
+
result.start.assign("minute", date.getMinutes());
|
|
84
|
+
result.start.assign("second", date.getSeconds());
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -11,6 +11,7 @@ import { Component, ParsedResult, ParsingOption, ParsingReference, Meridiem, Wee
|
|
|
11
11
|
import ZHHantCasualDateParser from "./parsers/ZHHantCasualDateParser";
|
|
12
12
|
import ZHHantDateParser from "./parsers/ZHHantDateParser";
|
|
13
13
|
import ZHHantDeadlineFormatParser from "./parsers/ZHHantDeadlineFormatParser";
|
|
14
|
+
import ZHHantAgoFormatParser from "./parsers/ZHHantAgoFormatParser";
|
|
14
15
|
import ZHHantRelationWeekdayParser from "./parsers/ZHHantRelationWeekdayParser";
|
|
15
16
|
import ZHHantTimeExpressionParser from "./parsers/ZHHantTimeExpressionParser";
|
|
16
17
|
import ZHHantWeekdayParser from "./parsers/ZHHantWeekdayParser";
|
|
@@ -54,6 +55,7 @@ export function createConfiguration(): Configuration {
|
|
|
54
55
|
new ZHHantWeekdayParser(),
|
|
55
56
|
new ZHHantTimeExpressionParser(),
|
|
56
57
|
new ZHHantDeadlineFormatParser(),
|
|
58
|
+
new ZHHantAgoFormatParser(),
|
|
57
59
|
],
|
|
58
60
|
refiners: [new ZHHantMergeDateRangeRefiner(), new ZHHantMergeDateTimeRefiner()],
|
|
59
61
|
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ParsingContext } from "../../../../chrono";
|
|
2
|
+
import { AbstractParserWithWordBoundaryChecking } from "../../../../common/parsers/AbstractParserWithWordBoundary";
|
|
3
|
+
import { addDuration, Duration, reverseDuration } from "../../../../calculation/duration";
|
|
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 ZHHantAgoFormatParser 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 duration: Duration = {};
|
|
45
|
+
const unit = match[UNIT_GROUP];
|
|
46
|
+
const unitAbbr = unit[0];
|
|
47
|
+
|
|
48
|
+
if (unitAbbr.match(/[日天星禮月年]/)) {
|
|
49
|
+
if (unitAbbr == "日" || unitAbbr == "天") {
|
|
50
|
+
duration.day = number;
|
|
51
|
+
} else if (unitAbbr == "星" || unitAbbr == "禮") {
|
|
52
|
+
duration.week = number;
|
|
53
|
+
} else if (unitAbbr == "月") {
|
|
54
|
+
duration.month = number;
|
|
55
|
+
} else if (unitAbbr == "年") {
|
|
56
|
+
duration.year = number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
duration = reverseDuration(duration);
|
|
60
|
+
|
|
61
|
+
const date = addDuration(context.refDate, duration);
|
|
62
|
+
result.start.assign("year", date.getFullYear());
|
|
63
|
+
result.start.assign("month", date.getMonth() + 1);
|
|
64
|
+
result.start.assign("day", date.getDate());
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (unitAbbr == "秒") {
|
|
69
|
+
duration.second = number;
|
|
70
|
+
} else if (unitAbbr == "分") {
|
|
71
|
+
duration.minute = number;
|
|
72
|
+
} else if (unitAbbr == "小" || unitAbbr == "鐘") {
|
|
73
|
+
duration.hour = number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
duration = reverseDuration(duration);
|
|
77
|
+
|
|
78
|
+
const date = addDuration(context.refDate, duration);
|
|
79
|
+
result.start.imply("year", date.getFullYear());
|
|
80
|
+
result.start.imply("month", date.getMonth() + 1);
|
|
81
|
+
result.start.imply("day", date.getDate());
|
|
82
|
+
result.start.assign("hour", date.getHours());
|
|
83
|
+
result.start.assign("minute", date.getMinutes());
|
|
84
|
+
result.start.assign("second", date.getSeconds());
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -320,3 +320,17 @@ test("Test - Random negative text", function () {
|
|
|
320
320
|
|
|
321
321
|
testUnexpectedResult(chrono.de, "ljetztlich");
|
|
322
322
|
});
|
|
323
|
+
|
|
324
|
+
test("Test - Casual time keeps its meridiem when merged with an explicit time", () => {
|
|
325
|
+
testSingleCase(chrono.de, "nachmittag um 5", new Date(2016, 7, 10, 12), (result, text) => {
|
|
326
|
+
expect(result.text).toBe(text);
|
|
327
|
+
expect(result.start.get("hour")).toBe(17);
|
|
328
|
+
expect(result.start.get("meridiem")).toBe(1);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
testSingleCase(chrono.de, "abend um 5", new Date(2016, 7, 10, 12), (result, text) => {
|
|
332
|
+
expect(result.text).toBe(text);
|
|
333
|
+
expect(result.start.get("hour")).toBe(17);
|
|
334
|
+
expect(result.start.get("meridiem")).toBe(1);
|
|
335
|
+
});
|
|
336
|
+
});
|
package/test/en/en_month.test.ts
CHANGED
|
@@ -293,3 +293,47 @@ test("Test - Month only in different context", () => {
|
|
|
293
293
|
testUnexpectedResult(chrono.casual, "The mountain may not move");
|
|
294
294
|
testUnexpectedResult(chrono.casual, "May not be correct");
|
|
295
295
|
});
|
|
296
|
+
|
|
297
|
+
test("Test - Year Month expression", () => {
|
|
298
|
+
testSingleCase(chrono, "2024 Aug", (result) => {
|
|
299
|
+
expect(result.text).toBe("2024 Aug");
|
|
300
|
+
expect(result.start.get("year")).toBe(2024);
|
|
301
|
+
expect(result.start.get("month")).toBe(8);
|
|
302
|
+
expect(result.start.get("day")).toBe(1);
|
|
303
|
+
expect(result.start.isCertain("year")).toBe(true);
|
|
304
|
+
expect(result.start.isCertain("month")).toBe(true);
|
|
305
|
+
expect(result.start.isCertain("day")).toBe(false);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
testSingleCase(chrono, "2024 August", (result) => {
|
|
309
|
+
expect(result.text).toBe("2024 August");
|
|
310
|
+
expect(result.start.get("year")).toBe(2024);
|
|
311
|
+
expect(result.start.get("month")).toBe(8);
|
|
312
|
+
expect(result.start.get("day")).toBe(1);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
testSingleCase(chrono, "2023 Sept", (result) => {
|
|
316
|
+
expect(result.text).toBe("2023 Sept");
|
|
317
|
+
expect(result.start.get("year")).toBe(2023);
|
|
318
|
+
expect(result.start.get("month")).toBe(9);
|
|
319
|
+
expect(result.start.get("day")).toBe(1);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
testSingleCase(chrono, "2024-August", (result) => {
|
|
323
|
+
expect(result.text).toBe("2024-August");
|
|
324
|
+
expect(result.start.get("year")).toBe(2024);
|
|
325
|
+
expect(result.start.get("month")).toBe(8);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
testSingleCase(chrono, "2024/August", (result) => {
|
|
329
|
+
expect(result.text).toBe("2024/August");
|
|
330
|
+
expect(result.start.get("year")).toBe(2024);
|
|
331
|
+
expect(result.start.get("month")).toBe(8);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
testSingleCase(chrono, "2024 AD August", (result) => {
|
|
335
|
+
expect(result.text).toBe("2024 AD August");
|
|
336
|
+
expect(result.start.get("year")).toBe(2024);
|
|
337
|
+
expect(result.start.get("month")).toBe(8);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
@@ -83,3 +83,17 @@ test("Test - Combined Expression", function () {
|
|
|
83
83
|
expect(result.start.get("hour")).toBe(0);
|
|
84
84
|
});
|
|
85
85
|
});
|
|
86
|
+
|
|
87
|
+
test("Test - Casual time keeps its meridiem when merged with an explicit time", () => {
|
|
88
|
+
testSingleCase(chrono, "iltapäivällä klo 5", new Date(2016, 7, 10, 12), (result, text) => {
|
|
89
|
+
expect(result.text).toBe(text);
|
|
90
|
+
expect(result.start.get("hour")).toBe(17);
|
|
91
|
+
expect(result.start.get("meridiem")).toBe(1);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
testSingleCase(chrono, "illalla klo 8", new Date(2016, 7, 10, 12), (result, text) => {
|
|
95
|
+
expect(result.text).toBe(text);
|
|
96
|
+
expect(result.start.get("hour")).toBe(20);
|
|
97
|
+
expect(result.start.get("meridiem")).toBe(1);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -298,3 +298,17 @@ test("Test - Combined Expression", function () {
|
|
|
298
298
|
// expect(results.length).toBe(0);
|
|
299
299
|
//
|
|
300
300
|
// });
|
|
301
|
+
|
|
302
|
+
test("Test - Casual time keeps its meridiem when merged with an explicit time", () => {
|
|
303
|
+
testSingleCase(chrono.fr, "après-midi à 5", new Date(2016, 7, 10, 12), (result, text) => {
|
|
304
|
+
expect(result.text).toBe(text);
|
|
305
|
+
expect(result.start.get("hour")).toBe(17);
|
|
306
|
+
expect(result.start.get("meridiem")).toBe(1);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
testSingleCase(chrono.fr, "soir à 8", new Date(2016, 7, 10, 12), (result, text) => {
|
|
310
|
+
expect(result.text).toBe(text);
|
|
311
|
+
expect(result.start.get("hour")).toBe(20);
|
|
312
|
+
expect(result.start.get("meridiem")).toBe(1);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
@@ -106,3 +106,9 @@ test("Test - fr - relative date", function () {
|
|
|
106
106
|
expect(result.start.isCertain("second")).toBeFalsy();
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
|
+
|
|
110
|
+
test("Test - fr - false positive prevention for single-letter time units", function () {
|
|
111
|
+
// Test that "la derniere h" in "la derniere homme" doesn't match as "la derniere h" (last hour)
|
|
112
|
+
// The word boundary check should prevent "h" from matching the time unit "h"
|
|
113
|
+
testUnexpectedResult(chrono.fr, "la derniere homme");
|
|
114
|
+
});
|
|
@@ -42,3 +42,40 @@ test("Test - Single Expression", () => {
|
|
|
42
42
|
expect(result.start).toBeDate(new Date(2012, 7, 11, 17, 10));
|
|
43
43
|
});
|
|
44
44
|
});
|
|
45
|
+
|
|
46
|
+
test("Test - Casual time keeps its meridiem when merged with an explicit time", () => {
|
|
47
|
+
testSingleCase(chrono.it, "pomeriggio alle 5", new Date(2016, 7, 10, 12), (result, text) => {
|
|
48
|
+
expect(result.text).toBe(text);
|
|
49
|
+
expect(result.start.get("hour")).toBe(17);
|
|
50
|
+
expect(result.start.get("meridiem")).toBe(1);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
testSingleCase(chrono.it, "sera alle 8", new Date(2016, 7, 10, 12), (result, text) => {
|
|
54
|
+
expect(result.text).toBe(text);
|
|
55
|
+
expect(result.start.get("hour")).toBe(20);
|
|
56
|
+
expect(result.start.get("meridiem")).toBe(1);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("Test - Casual time midnight and noon", () => {
|
|
61
|
+
testSingleCase(chrono.it.casual, "La scadenza è mezzanotte", new Date(2012, 7, 10, 12), (result) => {
|
|
62
|
+
expect(result.index).toBe(13);
|
|
63
|
+
expect(result.text).toBe(" mezzanotte");
|
|
64
|
+
expect(result.start.get("year")).toBe(2012);
|
|
65
|
+
expect(result.start.get("month")).toBe(8);
|
|
66
|
+
expect(result.start.get("day")).toBe(11);
|
|
67
|
+
expect(result.start.get("hour")).toBe(0);
|
|
68
|
+
expect(result.start.get("minute")).toBe(0);
|
|
69
|
+
expect(result.start.get("second")).toBe(0);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
testSingleCase(chrono.it.casual, "La scadenza è mezzogiorno", new Date(2012, 7, 10, 12), (result) => {
|
|
73
|
+
expect(result.index).toBe(13);
|
|
74
|
+
expect(result.text).toBe(" mezzogiorno");
|
|
75
|
+
expect(result.start.get("year")).toBe(2012);
|
|
76
|
+
expect(result.start.get("month")).toBe(8);
|
|
77
|
+
expect(result.start.get("day")).toBe(10);
|
|
78
|
+
expect(result.start.get("hour")).toBe(12);
|
|
79
|
+
expect(result.start.get("meridiem")).toBe(0);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as chrono from "../../src";
|
|
2
|
-
import { testSingleCase } from "../test_util";
|
|
2
|
+
import { testSingleCase, testUnexpectedResult } from "../test_util";
|
|
3
3
|
|
|
4
4
|
test("Test - The normal within expression", () => {
|
|
5
5
|
testSingleCase(chrono.uk, "буде зроблено протягом хвилини", new Date(2012, 7, 10), (result) => {
|
|
@@ -14,3 +14,10 @@ test("Test - The normal within expression", () => {
|
|
|
14
14
|
expect(result.start).toBeDate(new Date(2012, 7, 10, 2));
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
|
+
|
|
18
|
+
test("Test - Within expression respects the word boundary", () => {
|
|
19
|
+
// The forwardDate branch builds a bare time-unit pattern whose right boundary uses the
|
|
20
|
+
// \p{L}\p{N} escapes, so a unit glued to a following letter must not match. "годин" (hours)
|
|
21
|
+
// is a prefix of "годинників" (watches), so this sentence must not parse as "5 hours".
|
|
22
|
+
testUnexpectedResult(chrono.uk, "купив 5 годинників", new Date(2012, 7, 10), { forwardDate: true });
|
|
23
|
+
});
|