Если вы не слышали об этом, Chrono (https://github.com/wanasit/chrono) - это синтаксический анализатор даты на естественном языке в JavaScript.
Я написал первую фиксацию еще в 2012 году (вспомните jQuery и Bootstrap v1). Примерно в то же время я переезжал в Токио, чтобы учиться в аспирантуре, и еще до того, как начал работать профессиональным разработчиком программного обеспечения. С тех пор было много изменений как в JavaScript (ES6, TypeScript, React,…), так и в моем опыте программирования. Этим летом у меня наконец-то есть время побыть дома и поработать над обновлением библиотеки.
Chrono, v2, представляет собой почти полностью переписанный проект на TypeScript с учетом следующих целей.
- Сохранение знакомых API
- Уменьшите количество повторяющегося кода и шаблонов
Сохранение знакомых API
Chrono делает только одно - разбирает дату из текста. Таким образом, он должен быть максимально простым и понятным для людей, которые хотят использовать его для этого. Скрывая под собой глубокий уровень сложности синтаксического анализа, Chrono всегда поддерживал минимальный интерфейс, а именно свою parse()
функцию.
За исключением нескольких важных отличий (в первую очередь, обработки локалей), Chrono v2 имеет те же минималистичные API.
import * as chrono from ‘chrono-node’; chrono.parseDate(‘Today at 5 PM’) // Return a javascript Date object chrono.parse(’Today at 5 PM’) // Return more detailed results
Вы можете настроить Chrono, клонировав базовую настройку и добавив / удалив parsers
или refiners
:
import * as chrono from ‘chrono-node’; const customChrono = new chrono.Chrono(); // or const customChrono = chrono.en.clone(); customChrono.parsers.push(...)
Если вы использовали Chrono, изменение должно быть несложным. В противном случае начать работу не составит труда.
В то же время для проектов TypeScript вы получаете бесплатные преимущества недавно усовершенствованной системы типов Chrono.
class Chrono { parsers: Array<Parser> refiners: Array<Refiner> parse( text: string, ref?: Date, option?: ParsingOption ): ParsedResult[] { ... } }
Уменьшите количество повторяющегося кода и шаблонов
До того, как class
был представлен в ECMAScript 2015, проекты JavaScript должны были полагаться на наследование на основе прототипов.
В Chrono дублированный код также усугубляется отсутствием хорошей независимой от языка абстракции (ни для парсеров, ни для уточнений). Участникам предлагается скопировать и вставить весь код с английского языка.
exports.Refiner = function ENMergeDateTimeRefiner() { Refiner.call(this); this.refine = function(text, results, opt) { // check if there are results with unknown date and time // check if the words between them meaningful // merge them } } exports.Refiner = function FRMergeDateTimeRefiner() { Refiner.call(this); this.refine = function(text, results, opt) { // mostly same code, but check French words } }
В версии 2 общая логика (например, календарь и обработка даты и времени) была организована в не зависящие от языка общие классы, в то время как обработка ключевых слов и шаблонов была разделена и содержалась в их собственных модулях (см. `/ Common /…` и `/ locales / en /… `).
Тот же английский уточнение в v2 будет выглядеть так:
export default class ENMergeDateTimeRefiner extends AbstractMergeDateTimeRefiner { patternBetween(): RegExp { return /^\s*(T|at|after|before|on|of|,|-)?\s*$/i; } }
Новая абстракция также должна упростить настройку Chrono.
В v1 это пример Readme о том, как добавить собственный синтаксический анализатор:
var christmasParser = new chrono.Parser(); christmasParser.pattern = function () { return /\bChristmas\b/i; }; christmasParser.extract = function(text, ref, match, opt) { return new chrono.ParsedResult({ ref: ref, text: match[0], index: match.index, start: { day: 25, month: 12, } }); }; var custom = new chrono.Chrono(); custom.parsers.push(christmasParser);
Теперь есть:
const custom = chrono.casual.clone(); custom.parsers.push({ pattern: () => { return /\bChristmas\b/i }, extract: () => { return { day: 25, month: 12 } } });
Еще одно важное изменение
›… Очень мало причин, по которым мы должны пытаться анализировать сразу несколько языков по умолчанию. Это приводит к множеству угловых случаев, например - # 319- # 318. Многоязычные приложения уже должны отслеживать язык пользователя, поэтому я не уверен, что действительно нужны наши попытки автоматического определения.
- Бен Обин, участник Chrono № 318
По умолчанию Chrono v1 применяет все шаблоны / ключевые слова даты со всех поддерживаемых языков, и это оказалось плохим дизайнерским решением.
Вначале это работало хорошо, когда Chrono поддерживал синтаксический анализ только на английском и японском языках. Однако после анализа большего количества языков (7 языков в v1.3.7
, благодаря большому количеству участников), применение всех шаблонов даты приводит к множеству неверных или неожиданных результатов (например, смешивание немецких сокращений с английскими), и становится необходимым обслуживание и исправление ошибок. все сложнее и сложнее.
Итак, начиная с версии 2, Chrono по умолчанию будет пытаться анализировать только английский (международный).
chrono.parseDate('6/10/2018'); chrono.en.parseDate('6/10/2018');
Конечно, вы можете использовать синтаксический анализ Chrono на других языках через те же простые в использовании API.
chrono.ja.parseDate('令和2年8月10日');
Итак, теперь, когда мы можем поддерживать несколько языков или более шаблонов дат более устойчивыми способами, мы, безусловно, приветствуем любые ваши предложения или отзывы.
Пожалуйста, проверьте Chrono на Github!