1 | import { ReferenceWithTimezone, ParsingComponents, ParsingResult } from "./results.js";
|
2 | import ENDefaultConfiguration from "./locales/en/configuration.js";
|
3 | export class Chrono {
|
4 | constructor(configuration) {
|
5 | this.defaultConfig = new ENDefaultConfiguration();
|
6 | configuration = configuration || this.defaultConfig.createCasualConfiguration();
|
7 | this.parsers = [...configuration.parsers];
|
8 | this.refiners = [...configuration.refiners];
|
9 | }
|
10 | clone() {
|
11 | return new Chrono({
|
12 | parsers: [...this.parsers],
|
13 | refiners: [...this.refiners],
|
14 | });
|
15 | }
|
16 | parseDate(text, referenceDate, option) {
|
17 | const results = this.parse(text, referenceDate, option);
|
18 | return results.length > 0 ? results[0].start.date() : null;
|
19 | }
|
20 | parse(text, referenceDate, option) {
|
21 | const context = new ParsingContext(text, referenceDate, option);
|
22 | let results = [];
|
23 | this.parsers.forEach((parser) => {
|
24 | const parsedResults = Chrono.executeParser(context, parser);
|
25 | results = results.concat(parsedResults);
|
26 | });
|
27 | results.sort((a, b) => {
|
28 | return a.index - b.index;
|
29 | });
|
30 | this.refiners.forEach(function (refiner) {
|
31 | results = refiner.refine(context, results);
|
32 | });
|
33 | return results;
|
34 | }
|
35 | static executeParser(context, parser) {
|
36 | const results = [];
|
37 | const pattern = parser.pattern(context);
|
38 | const originalText = context.text;
|
39 | let remainingText = context.text;
|
40 | let match = pattern.exec(remainingText);
|
41 | while (match) {
|
42 | const index = match.index + originalText.length - remainingText.length;
|
43 | match.index = index;
|
44 | const result = parser.extract(context, match);
|
45 | if (!result) {
|
46 | remainingText = originalText.substring(match.index + 1);
|
47 | match = pattern.exec(remainingText);
|
48 | continue;
|
49 | }
|
50 | let parsedResult = null;
|
51 | if (result instanceof ParsingResult) {
|
52 | parsedResult = result;
|
53 | }
|
54 | else if (result instanceof ParsingComponents) {
|
55 | parsedResult = context.createParsingResult(match.index, match[0]);
|
56 | parsedResult.start = result;
|
57 | }
|
58 | else {
|
59 | parsedResult = context.createParsingResult(match.index, match[0], result);
|
60 | }
|
61 | const parsedIndex = parsedResult.index;
|
62 | const parsedText = parsedResult.text;
|
63 | context.debug(() => console.log(`${parser.constructor.name} extracted (at index=${parsedIndex}) '${parsedText}'`));
|
64 | results.push(parsedResult);
|
65 | remainingText = originalText.substring(parsedIndex + parsedText.length);
|
66 | match = pattern.exec(remainingText);
|
67 | }
|
68 | return results;
|
69 | }
|
70 | }
|
71 | export class ParsingContext {
|
72 | constructor(text, refDate, option) {
|
73 | this.text = text;
|
74 | this.reference = new ReferenceWithTimezone(refDate);
|
75 | this.option = option ?? {};
|
76 | this.refDate = this.reference.instant;
|
77 | }
|
78 | createParsingComponents(components) {
|
79 | if (components instanceof ParsingComponents) {
|
80 | return components;
|
81 | }
|
82 | return new ParsingComponents(this.reference, components);
|
83 | }
|
84 | createParsingResult(index, textOrEndIndex, startComponents, endComponents) {
|
85 | const text = typeof textOrEndIndex === "string" ? textOrEndIndex : this.text.substring(index, textOrEndIndex);
|
86 | const start = startComponents ? this.createParsingComponents(startComponents) : null;
|
87 | const end = endComponents ? this.createParsingComponents(endComponents) : null;
|
88 | return new ParsingResult(this.reference, index, text, start, end);
|
89 | }
|
90 | debug(block) {
|
91 | if (this.option.debug) {
|
92 | if (this.option.debug instanceof Function) {
|
93 | this.option.debug(block);
|
94 | }
|
95 | else {
|
96 | const handler = this.option.debug;
|
97 | handler.debug(block);
|
98 | }
|
99 | }
|
100 | }
|
101 | }
|
102 |
|
\ | No newline at end of file |