A natural language date parser in Javascript
# Agent Documentation - Project Setup & Architecture
This document provides a guide for AI agents working on `chrono` (chrono-node) to quickly understand the project context, layout, testing commands, and implementation constraints.
## Project Overview
`chrono` is a natural language date parser written in JavaScript/TypeScript. It extracts dates, times, and relative date expressions from free text.
---
## Technical Stack & Setup
- **Language**: TypeScript / JavaScript (ES6 Modules and CommonJS outputs)
- **Dependency Manager**: `npm`
- **Testing Framework**: `jest`
### Running Tests
To run the full test suite, execute:
```bash
npm test
```
To run tests silently:
```bash
npm run test:silent
```
---
## Directory Structure & Architecture
```
src/
βββ index.ts # Main entry point and locale shortcut exports
βββ chrono.ts # Main orchestrator class (Chrono, Parser, Refiner, Configuration)
βββ results.ts # Core result models (ParsingResult, ParsingComponents)
βββ types.ts # Global type definitions (ParsedResult, ParsingOption, ParsingReference)
βββ calculation/ # Arithmetic helpers (duration, weekdays)
βββ common/ # Locale-agnostic base parsers and refiners
βββ locales/ # Language-specific configurations, parsers, and refiners
β βββ de/
β βββ en/
β βββ zh/
β β βββ hans/
β β βββ hant/
β βββ ...
βββ utils/ # General utility functions
```
### Core Concepts
1. **Parsers (`Parser`)**:
Implement `innerPattern()` to return the regular expression pattern, and `innerExtract(context, match)` to process matching strings and return a `ParsingResult`.
2. **Refiners (`Refiner`)**:
Post-process and merge/filter the parsed results (e.g., merging separate date and time components, or resolving overlapping date ranges).
3. **ParsingComponents (`ParsingComponents`)**:
Stores date and time elements (e.g., year, month, day, hour). Elements are marked as either explicitly assigned (`assign`) or implied (`imply`).
---
## Key Context & Caveats
1. **Modular Parsers**:
Avoid overloading a single parser with multiple disparate concepts (e.g. mixing "after/within" with "ago/before"). Instead, introduce distinct, small parsers for each concern (e.g., `ZHHansDeadlineFormatParser` and `ZHHansAgoFormatParser`).
2. **Locale Symmetry & Chinese (zh) Special Case**:
- The Chinese locale is a special case where we want Simplified (`zh.hans`) and Traditional (`zh.hant`) components to remain exactly synchronized. When implementing a parser/refiner or a test for Simplified Chinese (`zh.hans`), always implement the equivalent for Traditional Chinese (`zh.hant`) if relevant, translating characters accordingly (e.g., `ε ` vs `εΉΎ`, `δΈͺ` vs `ε`, `ι` vs `ι`).
- English (`en`) is the most advanced locale in the library. Other locales are modeled after English but often lag behind.
3. **Relative Date Arithmetic**:
Use helpers from `src/calculation/duration.ts` such as `addDuration` and `reverseDuration` to perform date calculations. When handling "ago/before" expressions, calculate the positive duration first, then reverse it using `reverseDuration`.
4. **Abstract Parsers**:
Inherit from `AbstractParserWithWordBoundaryChecking` (or `AbstractParserWithLeftBoundaryChecking`) to inherit word boundary detection and clean regex boundary matching.
5. **Testing Conventions**:
- **Spell out test cases individually**: Do NOT use loops (`for`, `forEach`), shared case tables, or `test.each`. Every test case should be in an explicit `test(...)` block using `testSingleCase(...)` (or `testUnexpectedResult(...)`). This ensures that test failure messages immediately highlight the exact broken input, line number, and expected vs actual values.
- Always pass a clear reference date (`refDate`) to `testSingleCase` to ensure deterministic execution of relative time tests.
- Assert the matched index (`result.index`) and text boundaries (`result.text`) to check for correct extraction when the text is embedded within sentences.
- The `result.index` check can be skipped if it is trivial (e.g., the input string is exactly equal to the expected matched text `result.text`).
- The `result.text` check may also be intentionally omitted on vague edge cases.
6. **Commit & PR Scoping, and Design Philosophy**:
- **Chrono relies on human maintainer review; simplicity and consistency with existing patterns take precedence.**
- **Keep commits and PRs focused and incremental**: Avoid committing or bundling multiple unrelated changes together, both locally in git commits and in pull requests (e.g., mixing eras, holidays, and relative time expressions). If a change touches multiple concepts or features, break them down into separate, incremental commits and PRs. This keeps changes easy to review, simplifies regression analysis, and makes bug bisecting possible.
- **Avoid premature over-abstraction**: Do not introduce custom interfaces or heavy abstractions (e.g., per-locale holiday definitions, period managers) inside a single locale. Abstractions should be rare, conceptually solid, designed to work across all or most locales, andβmost importantlyβintroduced on their own rather than bundled with specific feature implementations.
---
## Git & Commit Message Format
Follow the Conventional Commits specification:
```
<type>(<scope>): <description>
```
- Example: `feat(zh): support past-tense relative time expressions (e.g. "1ε°ζΆε")`
- Example: `fix(en): support 'of' connector in weekday postfix`
### Pre-commit Formatting
Run the formatter before staging by executing:
```bash
npm run prettier
```
*Note: Git commit runs `npm run prettier` and `npm run test:silent` automatically as a pre-commit hook.*
---
## AI Agent Tool & Command Guidelines
To ensure secure, auditable, and standard operations:
- **Network Requests**: Do not run arbitrary commands to execute network calls. Use sandboxed tools or curl commands if external documentation is needed.
- **Verification**: Always run `npm test` inside the workspace directory rather than trying to run temporary JS code blocks elsewhere to verify behaviors.