chrono-node
Version:
A natural language date parser in Javascript
102 lines • 4.17 kB
JavaScript
import { ReferenceWithTimezone, ParsingComponents, ParsingResult } from "./results.js";
import ENDefaultConfiguration from "./locales/en/configuration.js";
export class Chrono {
constructor(configuration) {
this.defaultConfig = new ENDefaultConfiguration();
configuration = configuration || this.defaultConfig.createCasualConfiguration();
this.parsers = [...configuration.parsers];
this.refiners = [...configuration.refiners];
}
clone() {
return new Chrono({
parsers: [...this.parsers],
refiners: [...this.refiners],
});
}
parseDate(text, referenceDate, option) {
const results = this.parse(text, referenceDate, option);
return results.length > 0 ? results[0].start.date() : null;
}
parse(text, referenceDate, option) {
const context = new ParsingContext(text, referenceDate, option);
let results = [];
this.parsers.forEach((parser) => {
const parsedResults = Chrono.executeParser(context, parser);
results = results.concat(parsedResults);
});
results.sort((a, b) => {
return a.index - b.index;
});
this.refiners.forEach(function (refiner) {
results = refiner.refine(context, results);
});
return results;
}
static executeParser(context, parser) {
const results = [];
const pattern = parser.pattern(context);
const originalText = context.text;
let remainingText = context.text;
let match = pattern.exec(remainingText);
while (match) {
const index = match.index + originalText.length - remainingText.length;
match.index = index;
const result = parser.extract(context, match);
if (!result) {
remainingText = originalText.substring(match.index + 1);
match = pattern.exec(remainingText);
continue;
}
let parsedResult = null;
if (result instanceof ParsingResult) {
parsedResult = result;
}
else if (result instanceof ParsingComponents) {
parsedResult = context.createParsingResult(match.index, match[0]);
parsedResult.start = result;
}
else {
parsedResult = context.createParsingResult(match.index, match[0], result);
}
const parsedIndex = parsedResult.index;
const parsedText = parsedResult.text;
context.debug(() => console.log(`${parser.constructor.name} extracted (at index=${parsedIndex}) '${parsedText}'`));
results.push(parsedResult);
remainingText = originalText.substring(parsedIndex + parsedText.length);
match = pattern.exec(remainingText);
}
return results;
}
}
export class ParsingContext {
constructor(text, refDate, option) {
this.text = text;
this.reference = new ReferenceWithTimezone(refDate);
this.option = option ?? {};
this.refDate = this.reference.instant;
}
createParsingComponents(components) {
if (components instanceof ParsingComponents) {
return components;
}
return new ParsingComponents(this.reference, components);
}
createParsingResult(index, textOrEndIndex, startComponents, endComponents) {
const text = typeof textOrEndIndex === "string" ? textOrEndIndex : this.text.substring(index, textOrEndIndex);
const start = startComponents ? this.createParsingComponents(startComponents) : null;
const end = endComponents ? this.createParsingComponents(endComponents) : null;
return new ParsingResult(this.reference, index, text, start, end);
}
debug(block) {
if (this.option.debug) {
if (this.option.debug instanceof Function) {
this.option.debug(block);
}
else {
const handler = this.option.debug;
handler.debug(block);
}
}
}
}
//# sourceMappingURL=chrono.js.map