Sign In

@taskade/temporal-parser

Package Overview
Dependencies
Maintainers
2
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@taskade/temporal-parser - npm Package Compare versions

Comparing version
1.0.5
to
1.1.0
+72
dist/types/stringify.d.ts
import type { AnnotationAst, DateAst, DateTimeAst, DurationAst, OffsetAst, RangeAst, TemporalAst, TimeAst, TimeZoneAst } from './parser-types.js';
/**
* Convert a temporal AST back to its string representation.
*
* @param ast - The AST to stringify
* @returns ISO 8601 / IXDTF formatted string
*
* @example
* ```typescript
* const ast = parseTemporal('2025-01-12T10:00:00+08:00');
* const str = stringifyTemporal(ast);
* // '2025-01-12T10:00:00+08:00'
* ```
*/
export declare function stringifyTemporal(ast: TemporalAst): string;
/**
* Stringify a date AST to ISO 8601 format.
*
* @param date - The date AST
* @returns Date string (YYYY, YYYY-MM, or YYYY-MM-DD)
*/
export declare function stringifyDate(date: DateAst): string;
/**
* Stringify a time AST to ISO 8601 format.
*
* @param time - The time AST
* @returns Time string (HH:MM, HH:MM:SS, or HH:MM:SS.fff)
*/
export declare function stringifyTime(time: TimeAst): string;
/**
* Stringify a timezone offset AST to canonical format.
*
* @param offset - The offset AST
* @returns Offset string in canonical format (Z or ±HH:MM)
*/
export declare function stringifyOffset(offset: OffsetAst): string;
/**
* Stringify a timezone AST.
*
* @param timeZone - The timezone AST
* @returns Timezone string [Asia/Singapore] or [!Asia/Singapore]
*/
export declare function stringifyTimeZone(timeZone: TimeZoneAst): string;
/**
* Stringify an annotation AST.
*
* @param annotation - The annotation AST
* @returns Annotation string [u-ca=gregory] or [!u-ca=gregory]
*/
export declare function stringifyAnnotation(annotation: AnnotationAst): string;
/**
* Stringify a datetime AST to ISO 8601 / IXDTF format.
*
* @param dateTime - The datetime AST
* @returns DateTime string with optional time, offset, timezone, and annotations
*/
export declare function stringifyDateTime(dateTime: DateTimeAst): string;
/**
* Stringify a duration AST to ISO 8601 format.
*
* @param duration - The duration AST
* @returns Duration string (P1Y2M3DT4H5M6S)
*/
export declare function stringifyDuration(duration: DurationAst): string;
/**
* Stringify a range AST to ISO 8601 format.
*
* @param range - The range AST
* @returns Range string (start/end, /end, or start/)
*/
export declare function stringifyRange(range: RangeAst): string;
//# sourceMappingURL=stringify.d.ts.map
{"version":3,"file":"stringify.d.ts","sourceRoot":"","sources":["../../src/stringify.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,aAAa,EACb,OAAO,EACP,WAAW,EACX,WAAW,EACX,SAAS,EACT,QAAQ,EACR,WAAW,EACX,OAAO,EACP,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAQ1D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAsBnD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAenD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAQzD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAG/D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,aAAa,GAAG,MAAM,CAErE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAoB/D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CA4C/D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CActD"}
+83
-0
# @taskade/temporal-parser
## 1.1.0
### Minor Changes
- c557ac0: feat: Add support for BC dates (negative years in ISO 8601)
Implement parsing and stringification of BC dates using ISO 8601 extended year format with negative year numbers. This follows the astronomical year numbering system where year 0 = 1 BC, year -1 = 2 BC, etc.
**Key features:**
- Parse BC dates with negative year notation: `-0044-03-15` (44 BC)
- Support year 0 representing 1 BC: `0000-01-01`
- Handle BC dates with time and timezone components
- Proper year padding in output: `-0044`, `-0001`
- Full round-trip compatibility
**Supported formats:**
- BC year only: `-0100`
- BC year-month: `-0753-04`
- BC full date: `-0044-03-15`
- BC datetime: `-0044-03-15T12:00:00`
- BC with timezone: `-0044-03-15T12:00:00Z`
**Examples:**
```typescript
// Parse the Ides of March, 44 BC
const bcDate = parseTemporal("-0044-03-15");
// { kind: 'DateTime', date: { year: -44, month: 3, day: 15 }, ... }
// Stringify BC date
stringifyDate({ kind: "Date", year: -44, month: 3, day: 15 });
// Returns: '-0044-03-15'
// Year 0 represents 1 BC in ISO 8601
parseTemporal("0000-01-01");
// { kind: 'DateTime', date: { year: 0, month: 1, day: 1 }, ... }
```
This implementation maintains full backward compatibility and follows ISO 8601:2004 extended year format specification.
- 7223124: feat: add comprehensive stringify API for AST serialization
Add comprehensive stringify API for AST serialization. Implements full round-trip serialization support by converting parsed temporal ASTs back to ISO 8601/IXDTF formatted strings.
**New exports:**
- `stringifyTemporal()` - Main function for all temporal types
- `stringifyDate()`, `stringifyTime()`, `stringifyDateTime()` - DateTime components
- `stringifyDuration()`, `stringifyRange()` - Duration and Range types
- `stringifyOffset()`, `stringifyTimeZone()`, `stringifyAnnotation()` - Supporting components
**Features:**
- Automatic normalization of offsets to canonical format (±HH:MM)
- Component-based reconstruction for consistent output
- Full round-trip compatibility with parser
- Preserves all AST information including annotations and critical flags
**Example:**
```typescript
import { parseTemporal, stringifyTemporal } from "@taskade/temporal-parser";
const ast = parseTemporal("2025-01-12T10:00:00+0530"); // Compact format
const normalized = stringifyTemporal(ast);
// '2025-01-12T10:00:00+05:30' (canonical format)
```
### Patch Changes
- 692b0f7: fix: Support comma as decimal separator in fractional seconds (European format)
Add support for comma (`,`) as a decimal separator in fractional seconds for both time and duration components, as specified in ISO 8601. This enables parsing of European-formatted temporal strings while maintaining canonical dot (`.`) notation in serialized output.
**Supported formats:**
- Time with fractional seconds: `T10:30:45,123` → `T10:30:45.123`
- Duration with fractional seconds: `PT1,5S` → `PT1.5S`
**Behavior:**
- Parser accepts both `.` and `,` as decimal separators
- Stringify normalizes all output to use `.` for consistency
- Full round-trip compatibility maintained
This change improves ISO 8601 compliance and enables parsing of temporal strings from European locales where comma is the standard decimal separator.
## 1.0.5

@@ -4,0 +87,0 @@

+142
-6

@@ -30,3 +30,12 @@ "use strict";

parseOffset: () => parseOffset,
parseTemporal: () => parseTemporal
parseTemporal: () => parseTemporal,
stringifyAnnotation: () => stringifyAnnotation,
stringifyDate: () => stringifyDate,
stringifyDateTime: () => stringifyDateTime,
stringifyDuration: () => stringifyDuration,
stringifyOffset: () => stringifyOffset,
stringifyRange: () => stringifyRange,
stringifyTemporal: () => stringifyTemporal,
stringifyTime: () => stringifyTime,
stringifyTimeZone: () => stringifyTimeZone
});

@@ -474,4 +483,8 @@ module.exports = __toCommonJS(index_exports);

parseDate() {
const isNegative = this.tryEat("Dash" /* Dash */);
const yTok = this.eat("Number" /* Number */);
const year = toInt(yTok.value, "year", this.i);
let year = toInt(yTok.value, "year", this.i);
if (isNegative) {
year = -year;
}
if (!this.tryEat("Dash" /* Dash */)) {

@@ -500,3 +513,3 @@ return { kind: "Date", year };

second = toInt(sTok.value, "second", this.i);
if (this.tryEat("Dot" /* Dot */)) {
if (this.tryEat("Dot" /* Dot */) || this.tryEat("Comma" /* Comma */)) {
const fracTok = this.eat("Number" /* Number */);

@@ -612,4 +625,5 @@ fraction = fracTok.value;

let fraction;
if (this.tryEat("Dot" /* Dot */)) {
rawParts.push(".");
const dotOrComma = this.tryEat("Dot" /* Dot */) || this.tryEat("Comma" /* Comma */);
if (dotOrComma) {
rawParts.push(dotOrComma.value);
const fracTok = this.eat("Number" /* Number */);

@@ -663,2 +677,115 @@ rawParts.push(fracTok.value);

}
// src/stringify.ts
function stringifyTemporal(ast) {
if (ast.kind === "Range") {
return stringifyRange(ast);
}
if (ast.kind === "Duration") {
return stringifyDuration(ast);
}
return stringifyDateTime(ast);
}
function stringifyDate(date) {
let yearStr;
if (date.year < 0) {
yearStr = "-" + Math.abs(date.year).toString().padStart(4, "0");
} else {
yearStr = date.year.toString().padStart(4, "0");
}
const parts = [yearStr];
if (date.month != null) {
parts.push(date.month.toString().padStart(2, "0"));
if (date.day != null) {
parts.push(date.day.toString().padStart(2, "0"));
}
}
return parts.join("-");
}
function stringifyTime(time) {
const parts = [
time.hour.toString().padStart(2, "0"),
time.minute.toString().padStart(2, "0")
];
if (time.second != null) {
let secondStr = time.second.toString().padStart(2, "0");
if (time.fraction != null) {
secondStr += `.${time.fraction}`;
}
parts.push(secondStr);
}
return parts.join(":");
}
function stringifyOffset(offset) {
if (offset.kind === "UtcOffset") {
return "Z";
}
const hours = offset.hours.toString().padStart(2, "0");
const minutes = offset.minutes.toString().padStart(2, "0");
return `${offset.sign}${hours}:${minutes}`;
}
function stringifyTimeZone(timeZone) {
const id = timeZone.critical ? `!${timeZone.id}` : timeZone.id;
return `[${id}]`;
}
function stringifyAnnotation(annotation) {
return `[${annotation.raw}]`;
}
function stringifyDateTime(dateTime) {
let result = stringifyDate(dateTime.date);
if (dateTime.time) {
result += `T${stringifyTime(dateTime.time)}`;
}
if (dateTime.offset) {
result += stringifyOffset(dateTime.offset);
}
if (dateTime.timeZone) {
result += stringifyTimeZone(dateTime.timeZone);
}
for (const annotation of dateTime.annotations) {
result += stringifyAnnotation(annotation);
}
return result;
}
function stringifyDuration(duration) {
let result = "P";
if (duration.years != null) {
result += `${duration.years}Y`;
}
if (duration.months != null) {
result += `${duration.months}M`;
}
if (duration.weeks != null) {
result += `${duration.weeks}W`;
}
if (duration.days != null) {
result += `${duration.days}D`;
}
const hasTimePart = duration.hours != null || duration.minutes != null || duration.seconds != null;
if (hasTimePart) {
result += "T";
if (duration.hours != null) {
result += `${duration.hours}H`;
}
if (duration.minutes != null) {
result += `${duration.minutes}M`;
}
if (duration.seconds != null) {
result += `${duration.seconds}`;
if (duration.secondsFraction != null && duration.secondsFraction.length > 0) {
result += `.${duration.secondsFraction}`;
}
result += "S";
}
}
for (const annotation of duration.annotations) {
result += stringifyAnnotation(annotation);
}
return result;
}
function stringifyRange(range) {
const start = range.start ? range.start.kind === "Duration" ? stringifyDuration(range.start) : stringifyDateTime(range.start) : "";
const end = range.end ? range.end.kind === "Duration" ? stringifyDuration(range.end) : stringifyDateTime(range.end) : "";
return `${start}/${end}`;
}
// Annotate the CommonJS export names for ESM import in node:

@@ -673,4 +800,13 @@ 0 && (module.exports = {

parseOffset,
parseTemporal
parseTemporal,
stringifyAnnotation,
stringifyDate,
stringifyDateTime,
stringifyDuration,
stringifyOffset,
stringifyRange,
stringifyTemporal,
stringifyTime,
stringifyTimeZone
});
//# sourceMappingURL=index.cjs.map
+3
-3
{
"version": 3,
"sources": ["../../src/index.ts", "../../src/lexer-types.ts", "../../src/combineTimezoneOffsets.ts", "../../src/errors.ts", "../../src/helpers/isAlpha.ts", "../../src/helpers/isDigit.ts", "../../src/helpers/isBracketWordChar.ts", "../../src/lexer.ts", "../../src/helpers/toInt.ts", "../../src/parseOffset.ts", "../../src/parser.ts"],
"sourcesContent": ["// index.ts\n// Main entry point for the temporal parser library\n\n// Export lexer functionality\nexport { combineTimezoneOffsets } from './combineTimezoneOffsets.js';\nexport { lexTemporal } from './lexer.js';\n\n// Export lexer types\nexport type { AnyToken, CombinedToken, Token } from './lexer-types.js';\nexport { CombinedTokType, TokType } from './lexer-types.js';\n\n// Export parser functionality\nexport { parseTemporal } from './parser.js';\n\n// Export offset parser (useful standalone utility)\nexport { parseOffset } from './parseOffset.js';\n\n// Export parser types\nexport type {\n AnnotationAst,\n DateAst,\n DateTimeAst,\n DurationAst,\n OffsetAst,\n RangeAst,\n TemporalAst,\n TimeAst,\n TimeZoneAst,\n ValueAst,\n} from './parser-types.js';\n\n// Export errors\nexport { LexError, ParseError } from './errors.js';\n", "// lexer-types.ts\n// Token types and interfaces for the lexer\n\nexport enum TokType {\n // Numbers: sequences of digits (0-9)\n // Examples: \"2025\", \"01\", \"12\", \"59\"\n Number = 'Number',\n\n // Ident (Identifier): sequences of alphabetic characters (A-Z, a-z)\n // This is the generic \"text\" token for letter-based designators.\n // Examples: \"P\" (duration), \"Y\" (year), \"M\" (month), \"gregory\" (calendar)\n // The lexer keeps it simple; the parser interprets the meaning.\n Ident = 'Ident',\n\n // Single-character punctuation tokens\n Dash = 'Dash', // -\n Colon = 'Colon', // :\n Dot = 'Dot', // .\n Plus = 'Plus', // +\n Slash = 'Slash', // /\n Comma = 'Comma', // ,\n Equals = 'Equals', // =\n Underscore = 'Underscore', // _\n Exclamation = 'Exclamation', // ! (critical flag in IXDTF)\n\n // Special letter tokens with dedicated meaning in ISO 8601\n T = 'T', // Date/time separator: 2025-01-01T10:00:00\n Z = 'Z', // UTC timezone marker: 2025-01-01T10:00:00Z\n\n // Bracket tokens for IXDTF annotations/extensions\n LBracket = 'LBracket', // [\n RBracket = 'RBracket', // ]\n\n // BracketText: complex text inside brackets that contains non-letter chars\n // Example: in [u-ca=gregory], \"u-ca\" is BracketText (has dash), \"gregory\" is Ident (letters only)\n // Example: in [Asia/Singapore], \"Asia/Singapore\" is BracketText (has slash)\n BracketText = 'BracketText',\n\n EOF = 'EOF',\n}\n\nexport type Token = {\n type: TokType;\n value: string;\n start: number; // inclusive\n end: number; // exclusive\n};\n\n// Combined token types for timezone offsets\nexport enum CombinedTokType {\n TZOffset = 'TZOffset', // +08:00, -0530, +09\n}\n\nexport type CombinedToken = {\n type: CombinedTokType;\n value: string;\n tokens: Token[];\n start: number;\n end: number;\n};\n\nexport type AnyToken = Token | CombinedToken;\n", "// combineTimezoneOffsets.ts\n// Combines numeric timezone offset tokens into single tokens for easier parsing\n\nimport { type AnyToken, CombinedTokType, type Token, TokType } from './lexer-types.js';\n\n/**\n * Combine numeric timezone offsets into single tokens for easier parsing.\n * This is an optional post-processing step for the lexer output.\n *\n * Combines patterns like:\n * - (+|-) Number Colon Number => +08:00, -05:30\n * - (+|-) Number (2 or 4 digits) => +09, -0530\n *\n * Only combines when context suggests a timezone offset (after time components),\n * NOT after:\n * - Z (mutually exclusive per ISO 8601)\n * - brackets (offset comes BEFORE brackets per RFC 9557/IXDTF)\n * - standalone dates (e.g., 2025-01 where - is a date separator)\n *\n * @param tokens - The raw token array from lexTemporal\n * @returns Array of tokens (either original Token or combined CombinedToken with TZOffset type where applicable)\n *\n * @example\n * ```typescript\n * const raw = lexTemporal('10:00:00+08:00');\n * const combined = combineTimezoneOffsets(raw);\n * // Result includes: { type: 'TZOffset', value: '+08:00' }\n * ```\n */\nexport function combineTimezoneOffsets(tokens: Token[]): AnyToken[] {\n const out: AnyToken[] = [];\n let i = 0;\n\n const peek = (k: number) => tokens[i + k];\n\n // Helper to check if previous tokens suggest this could be a timezone offset\n // Timezone offsets come after time components (HH:MM:SS)\n // NOT after just a date like 2025-01\n // NOT after Z (Z and numeric offsets are mutually exclusive per ISO 8601)\n // NOT after brackets (per RFC 9557/IXDTF: offset comes BEFORE brackets)\n const couldBeTzOffset = () => {\n if (out.length < 1) {\n return false;\n }\n const prev: AnyToken | undefined = out[out.length - 1];\n if (prev == null) {\n return false;\n }\n\n // After Z - NOT valid (Z and numeric offsets are mutually exclusive)\n // Per ISO 8601: use either Z OR +HH:MM, never both\n if (prev.type === TokType.Z) {\n return false;\n }\n\n // After bracket - NOT valid (offset must come BEFORE brackets per RFC 9557)\n // Valid: Time+08:00[Asia/Tokyo]\n // Invalid: [Asia/Tokyo]+08:00\n if (prev.type === TokType.RBracket) {\n return false;\n }\n\n // After a number, check context\n if (prev.type === TokType.Number) {\n if (out.length < 2) {\n return false;\n }\n const prevPrev = out[out.length - 2];\n\n // After a number with colon before it (time component)\n // e.g., ...10:00:00+08:00 - the number before + has a colon before it\n if (prevPrev?.type === TokType.Colon) {\n return true;\n }\n\n // After a number with dot before it (milliseconds)\n // e.g., ...10:00:00.999+08:00 - the number before + has a dot before it\n if (prevPrev?.type === TokType.Dot) {\n return true;\n }\n }\n\n return false;\n };\n\n while (i < tokens.length) {\n const t = tokens[i]!;\n const isSign = t.type === TokType.Plus || t.type === TokType.Dash;\n\n // Only try to combine if context suggests timezone offset\n if (isSign && couldBeTzOffset()) {\n // (+|-) Number Colon Number => +08:00\n if (\n peek(1)?.type === TokType.Number &&\n peek(2)?.type === TokType.Colon &&\n peek(3)?.type === TokType.Number\n ) {\n const originalTokens = [t, peek(1)!, peek(2)!, peek(3)!];\n const start = t.start;\n const end = peek(3)!.end;\n const value = `${t.value}${peek(1)!.value}:${peek(3)!.value}`;\n out.push({ type: CombinedTokType.TZOffset, value, tokens: originalTokens, start, end });\n i += 4;\n continue;\n }\n\n // (+|-) Number where Number is 2 or 4 digits => +09 or -0530\n if (peek(1)?.type === TokType.Number) {\n const num = peek(1)!.value;\n if (num.length === 2 || num.length === 4) {\n const originalTokens = [t, peek(1)!];\n const start = t.start;\n const end = peek(1)!.end;\n const value = `${t.value}${num}`;\n out.push({ type: CombinedTokType.TZOffset, value, tokens: originalTokens, start, end });\n i += 2;\n continue;\n }\n }\n }\n\n out.push(t);\n i++;\n }\n\n return out;\n}\n", "// errors.ts\n// Error classes for lexer and parser\n\nexport class LexError extends Error {\n public readonly position: number;\n constructor(message: string, position: number) {\n super(`${message} at position ${position}`);\n this.name = 'LexError';\n this.position = position;\n }\n}\n\nexport class ParseError extends Error {\n public readonly position: number;\n constructor(message: string, position: number) {\n super(`${message} at token index ${position}`);\n this.name = 'ParseError';\n this.position = position;\n }\n}\n", "/**\n * Check if character is alphabetic (A-Z or a-z)\n * This defines what can be part of an IDENT token in default mode\n * @param c - the character to check\n * @returns true if character is alphabetic, false otherwise\n */\nexport function isAlpha(c: string): boolean {\n return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');\n}\n", "/**\n * Check if character is a digit (0-9)\n * @param c - the character to check\n * @returns true if character is a digit, false otherwise\n */\nexport function isDigit(c: string) {\n return c >= '0' && c <= '9';\n}\n", "import { isAlpha } from './isAlpha.js';\nimport { isDigit } from './isDigit.js';\n\n/**\n * Check if character is valid inside bracket annotations\n * In default mode, IDENT is letters only (keeps date/time parsing clean).\n * In bracket mode, we allow broader \"words\" like:\n * - u-ca (has dash)\n * - Asia/Singapore (has slash)\n * - Etc/GMT+8 (has plus)\n * - iso8601 (has digits)\n * @param c - the character to check\n * @returns true if character is valid in bracket context, false otherwise\n */\nexport function isBracketWordChar(c: string): boolean {\n return (\n isAlpha(c) || isDigit(c) || c === '-' || c === '/' || c === '+' || c === '.' // allow dots in some TZ-ish values\n );\n}\n", "// lexer.ts\n// Temporal (IXDTF / ISO-8601-ish) lexer with support for *extensions/annotations* like calendar.\n//\n// Supports:\n// - Basic date/time tokens: numbers, identifiers, T, Z, punctuation\n// - Ranges: '/'\n// - Durations: 'P' (as IDENT; parser enforces rules)\n// - Time zone forms:\n// - 'Z'\n// - numeric offsets: +08:00 / -0530 / +09 (optionally combined via helper)\n// - bracketed IANA TZ: [Asia/Singapore]\n// - IXDTF-style annotations/extensions in brackets, e.g.:\n// - [u-ca=gregory] (calendar)\n// - [u-tz=Asia/Singapore] (timeZone)\n// - multiple bracket groups: 2025-01-01T00:00Z[u-ca=iso8601][u-tz=UTC]\n//\n// The lexer is permissive; your parser should validate semantics.\n\nimport { LexError } from './errors.js';\nimport { isAlpha } from './helpers/isAlpha.js';\nimport { isBracketWordChar } from './helpers/isBracketWordChar.js';\nimport { isDigit } from './helpers/isDigit.js';\nimport type { Token } from './lexer-types.js';\nimport { TokType } from './lexer-types.js';\n\nexport function lexTemporal(src: string): Token[] {\n const tokens: Token[] = [];\n let i = 0;\n\n const emit = (type: TokType, start: number, end: number, value?: string) => {\n tokens.push({ type, value: value ?? src.slice(start, end), start, end });\n };\n\n // Lex a number: consume consecutive digits\n // Examples: \"2025\", \"01\", \"59\"\n const lexNumber = () => {\n const start = i;\n i++;\n while (i < src.length && isDigit(src[i]!)) {\n i++;\n }\n emit(TokType.Number, start, i);\n };\n\n // Lex an identifier: consume consecutive alphabetic characters\n // This is where IDENT tokens are created!\n //\n // Examples of what becomes IDENT:\n // - Duration designators: P, Y, M, W, D, H, S\n // - Calendar names: gregory, hebrew, iso8601\n // - Any letter sequence: P, YMD, UTC, America\n //\n // Special cases:\n // - \"T\" gets its own token type (datetime separator)\n // - \"Z\" gets its own token type (UTC marker)\n // - Everything else becomes Ident\n //\n // IMPORTANT: We only consume a single letter at a time to allow T and Z\n // to be recognized individually (e.g., \"DT\" should be \"D\" then \"T\", not \"DT\")\n const lexIdent = () => {\n const start = i;\n const ch = src[i]!;\n i++;\n\n // Special handling for T and Z - emit them as special tokens\n if (ch === 'T') {\n emit(TokType.T, start, i, 'T');\n return;\n }\n if (ch === 'Z') {\n emit(TokType.Z, start, i, 'Z');\n return;\n }\n\n // For other letters, consume consecutive letters that are NOT T or Z\n // This allows multi-letter identifiers like \"gregory\" but keeps T and Z separate\n while (i < src.length && isAlpha(src[i]!) && src[i] !== 'T' && src[i] !== 'Z') {\n i++;\n }\n\n emit(TokType.Ident, start, i); // Generic identifier\n };\n\n const lexBracketContent = () => {\n // We are positioned after '['. Emit content tokens until ']'.\n while (i < src.length) {\n const ch = src[i]!;\n\n if (ch === ']') {\n return;\n }\n\n // Skip whitespace inside brackets (rare but harmless)\n if (/\\s/.test(ch)) {\n i++;\n continue;\n }\n\n // Single-char tokens inside brackets\n if (ch === '=') {\n emit(TokType.Equals, i, i + 1);\n i++;\n continue;\n }\n if (ch === '_') {\n emit(TokType.Underscore, i, i + 1);\n i++;\n continue;\n }\n if (ch === ':') {\n emit(TokType.Colon, i, i + 1);\n i++;\n continue;\n }\n if (ch === '-') {\n emit(TokType.Dash, i, i + 1);\n i++;\n continue;\n }\n if (ch === '+') {\n emit(TokType.Plus, i, i + 1);\n i++;\n continue;\n }\n if (ch === '/') {\n emit(TokType.Slash, i, i + 1);\n i++;\n continue;\n }\n if (ch === '.') {\n emit(TokType.Dot, i, i + 1);\n i++;\n continue;\n }\n if (ch === ',') {\n emit(TokType.Comma, i, i + 1);\n i++;\n continue;\n }\n if (ch === '!') {\n emit(TokType.Exclamation, i, i + 1);\n i++;\n continue;\n }\n\n // Words inside brackets (u-ca, gregory, Asia/Singapore, iso8601, Etc/GMT+8, etc.)\n if (isBracketWordChar(ch)) {\n const start = i;\n i++;\n while (i < src.length && isBracketWordChar(src[i]!)) {\n i++;\n }\n const text = src.slice(start, i);\n\n // Decision: Ident vs BracketText\n // - If purely letters (A-Z, a-z): emit as Ident\n // Examples: \"gregory\", \"hebrew\", \"u\", \"ca\"\n // - If contains other chars (digits, -, /, +, .): emit as BracketText\n // Examples: \"u-ca\", \"Asia/Singapore\", \"iso8601\", \"Etc/GMT+8\"\n if (/^[A-Za-z]+$/.test(text)) {\n emit(TokType.Ident, start, i, text);\n } else {\n emit(TokType.BracketText, start, i, text);\n }\n\n continue;\n }\n\n throw new LexError(`Unexpected character ${JSON.stringify(ch)} inside brackets`, i);\n }\n\n throw new LexError(\"Unterminated bracket annotation, expected ']'\", src.length);\n };\n\n while (i < src.length) {\n const ch = src[i]!;\n\n // Skip whitespace\n if (/\\s/.test(ch)) {\n i++;\n continue;\n }\n\n // Bracketed extensions/annotations/timezone IDs\n if (ch === '[') {\n emit(TokType.LBracket, i, i + 1);\n i++;\n\n lexBracketContent();\n\n if (i >= src.length || src[i] !== ']') {\n throw new LexError(\"Unterminated bracket annotation, expected ']'\", i);\n }\n emit(TokType.RBracket, i, i + 1);\n i++;\n continue;\n }\n\n // Numbers: sequences of digits\n if (isDigit(ch)) {\n lexNumber();\n continue;\n }\n\n // Letters: this is where IDENT tokens are created!\n // Any alphabetic character triggers identifier lexing.\n // Examples: P (duration), Y (year), M (month), gregory, UTC\n if (isAlpha(ch)) {\n lexIdent();\n continue;\n }\n\n // Punctuation (default mode)\n switch (ch) {\n case '-':\n emit(TokType.Dash, i, i + 1);\n i++;\n continue;\n case ':':\n emit(TokType.Colon, i, i + 1);\n i++;\n continue;\n case '.':\n emit(TokType.Dot, i, i + 1);\n i++;\n continue;\n case '+':\n emit(TokType.Plus, i, i + 1);\n i++;\n continue;\n case '/':\n emit(TokType.Slash, i, i + 1);\n i++;\n continue;\n case ',':\n emit(TokType.Comma, i, i + 1);\n i++;\n continue;\n case '=':\n emit(TokType.Equals, i, i + 1);\n i++;\n continue;\n case '_':\n emit(TokType.Underscore, i, i + 1);\n i++;\n continue;\n default:\n throw new LexError(`Unexpected character ${JSON.stringify(ch)}`, i);\n }\n }\n\n emit(TokType.EOF, src.length, src.length, '');\n return tokens;\n}\n", "import { ParseError } from '../errors.js';\n\n/**\n * Convert a string to an integer, throwing a ParseError if invalid\n * @param s - the string to convert\n * @param label - a descriptive label for error messages (e.g., \"year\", \"month\")\n * @param position - the position in the token stream for error reporting\n * @returns the parsed integer value\n * @throws {ParseError} if the string is not a valid integer\n */\nexport function toInt(s: string, label: string, position: number): number {\n const n = Number(s);\n if (!Number.isFinite(n) || !Number.isInteger(n)) {\n throw new ParseError(`Invalid integer for ${label}: ${JSON.stringify(s)}`, position);\n }\n return n;\n}\n", "// parseOffset.ts\n// Parse timezone offset strings into structured components\n\nimport { ParseError } from './errors.js';\nimport { toInt } from './helpers/toInt.js';\nimport type { OffsetAst } from './parser-types.js';\n\n// Timezone offset validation constants\n// Per ISO 8601 and real-world usage:\n// - Westernmost: UTC-12:00 (Baker Island, Howland Island)\n// - Easternmost: UTC+14:00 (Line Islands, Kiritimati)\nconst MAX_OFFSET_HOURS = 14;\nconst MAX_MINUTES = 59;\n\n/**\n * Parse a timezone offset string into structured components.\n *\n * Supports three formats:\n * - Standard: +08:00, -05:30\n * - Compact: +0530, -0800\n * - Short: +09, -05\n *\n * Valid timezone offset ranges (per ISO 8601):\n * - Hours: 0-14 (UTC-12:00 to UTC+14:00)\n * - Minutes: 0-59\n *\n * Note: This function only parses numeric offsets (e.g., +08:00).\n * For UTC, use 'Z' (UtcOffset kind) which is semantically different from +00:00.\n * Per RFC 3339 section 4.3, -00:00 indicates \"local time with unknown offset\".\n *\n * @param offsetString - The offset string to parse (e.g., '+08:00', '-0530', '+09')\n * @param position - Position in token stream for error reporting (optional)\n * @returns Parsed offset with sign, hours, and minutes\n * @throws {ParseError} If the offset format is invalid or out of range\n *\n * @example\n * ```typescript\n * parseOffset('+08:00') // { kind: 'NumericOffset', sign: '+', hours: 8, minutes: 0, raw: '+08:00' }\n * parseOffset('-05:30') // { kind: 'NumericOffset', sign: '-', hours: 5, minutes: 30, raw: '-05:30' }\n * parseOffset('+0530') // { kind: 'NumericOffset', sign: '+', hours: 5, minutes: 30, raw: '+0530' }\n * parseOffset('+09') // { kind: 'NumericOffset', sign: '+', hours: 9, minutes: 0, raw: '+09' }\n * parseOffset('+14:00') // { kind: 'NumericOffset', sign: '+', hours: 14, minutes: 0, raw: '+14:00' }\n * ```\n */\nexport function parseOffset(offsetString: string, position = 0): OffsetAst {\n // Validate input is not empty\n if (offsetString.length === 0) {\n throw new ParseError('Offset string cannot be empty', position);\n }\n\n const raw = offsetString;\n\n // Validate first character is sign and assert type\n const sign = raw[0];\n if (sign !== '+' && sign !== '-') {\n throw new ParseError(`Offset must start with + or -, got ${JSON.stringify(sign)}`, position);\n }\n // Type assertion: TypeScript now knows sign is '+' | '-'\n const validSign: '+' | '-' = sign;\n\n const rest = raw.slice(1);\n\n // Validate rest is not empty\n if (rest.length === 0) {\n throw new ParseError(`Offset sign must be followed by digits`, position);\n }\n\n let hours: number;\n let minutes: number;\n\n if (rest.includes(':')) {\n // Format: +08:00 or -05:30\n const parts = rest.split(':');\n if (parts.length !== 2) {\n throw new ParseError(`Invalid offset format: ${raw} (expected HH:MM)`, position);\n }\n // After length check, we know parts[0] and parts[1] exist\n const [h, m] = parts;\n hours = toInt(h!, 'offset hours', position);\n minutes = toInt(m!, 'offset minutes', position);\n } else if (rest.length === 4) {\n // Format: +0530 or -0800\n hours = toInt(rest.slice(0, 2), 'offset hours', position);\n minutes = toInt(rest.slice(2, 4), 'offset minutes', position);\n } else if (rest.length === 2) {\n // Format: +08 or -05\n hours = toInt(rest, 'offset hours', position);\n minutes = 0;\n } else {\n throw new ParseError(\n `Invalid offset format: ${raw} (expected +HH:MM, +HHMM, or +HH)`,\n position,\n );\n }\n\n // Validate ranges\n if (hours < 0 || hours > MAX_OFFSET_HOURS) {\n throw new ParseError(`Offset hours must be 0-${MAX_OFFSET_HOURS}, got ${hours}`, position);\n }\n if (minutes < 0 || minutes > MAX_MINUTES) {\n throw new ParseError(`Offset minutes must be 0-${MAX_MINUTES}, got ${minutes}`, position);\n }\n\n return { kind: 'NumericOffset', sign: validSign, hours, minutes, raw };\n}\n", "// parser.ts\n// A practical recursive-descent parser that works with the lexer we wrote.\n// It builds an AST for a useful Temporal subset:\n// - date/time (with optional fractional seconds)\n// - timezone: Z | numeric offset (+08:00, -0530, +09) | bracket TZ id [Asia/Singapore]\n// - duration: P... with optional T part\n// - range: <expr> \"/\" <expr> where each side can be dateTime/date/duration, and either side may be empty (open range)\n// - bracket extensions like [u-ca=gregory], [u-tz=Asia/Singapore], etc. (stored as key/value pairs)\n\nimport { combineTimezoneOffsets } from './combineTimezoneOffsets.js';\nimport { ParseError } from './errors.js';\nimport { toInt } from './helpers/toInt.js';\nimport { lexTemporal } from './lexer.js';\nimport { type AnyToken, CombinedTokType, TokType } from './lexer-types.js';\nimport { parseOffset } from './parseOffset.js';\nimport type {\n AnnotationAst,\n DateAst,\n DateTimeAst,\n DurationAst,\n OffsetAst,\n TemporalAst,\n TimeAst,\n TimeZoneAst,\n ValueAst,\n} from './parser-types.js';\n\n// ---------- Parser ----------\n\nclass Parser {\n private i = 0;\n constructor(private toks: AnyToken[]) {}\n\n private peek(k = 0): AnyToken {\n return this.toks[Math.min(this.i + k, this.toks.length - 1)]!;\n }\n private at(type: TokType | CombinedTokType): boolean {\n return this.peek().type === type;\n }\n private eat(type: TokType | CombinedTokType): AnyToken {\n const t = this.peek();\n if (t.type !== type) {\n throw new ParseError(`Expected ${type} but got ${t.type}`, this.i);\n }\n this.i++;\n return t;\n }\n private tryEat(type: TokType | CombinedTokType): AnyToken | null {\n if (this.at(type)) {\n return this.eat(type);\n }\n return null;\n }\n private eof(): boolean {\n return this.at(TokType.EOF);\n }\n\n // Top-level: parse a range if we see '/', otherwise a single value.\n parseTemporal(): TemporalAst {\n // Open-start range: \"/...\"\n if (this.tryEat(TokType.Slash)) {\n const end = this.parseValueOrNull(); // allow empty end too\n this.eat(TokType.EOF);\n return { kind: 'Range', start: null, end };\n }\n\n const first = this.parseValueOrNull();\n // If first is null, only valid if it's \"/\" (handled above). So error:\n if (!first) {\n throw new ParseError('Expected a value', this.i);\n }\n\n if (this.tryEat(TokType.Slash)) {\n const second = this.parseValueOrNull(); // open-ended allowed\n this.eat(TokType.EOF);\n return { kind: 'Range', start: first, end: second };\n }\n\n this.eat(TokType.EOF);\n return first;\n }\n\n private parseValueOrNull(): ValueAst | null {\n // Empty side for open range:\n if (this.at(TokType.EOF) || this.at(TokType.Slash) || this.at(TokType.RBracket)) {\n return null;\n }\n\n // Duration starts with IDENT \"P\" (as produced by lexer)\n if (this.at(TokType.Ident) && String(this.peek().value) === 'P') {\n return this.parseDuration();\n }\n\n // Otherwise parse a date/datetime (common case)\n return this.parseDateTime();\n }\n\n // -------- DateTime parsing --------\n // Supports:\n // - YYYY\n // - YYYY-MM\n // - YYYY-MM-DD\n // - + time part with T: YYYY-MM-DDTHH:MM[:SS[.fff]]\n // - offset: Z | +08:00 | -0530\n // - timezone: [Asia/Singapore] (first bracketed IANA timezone)\n // - annotations: [u-ca=...][u-tz=...] (other bracketed content)\n private parseDateTime(): DateTimeAst {\n const date = this.parseDate();\n\n let time: DateTimeAst['time'] | undefined;\n\n // time separator is TokType.T (from lexer special-casing \"T\")\n if (this.tryEat(TokType.T)) {\n time = this.parseTime();\n }\n\n // Parse numeric offset (Z or +HH:MM)\n const offset = this.parseOffsetIfPresent();\n\n // Parse bracket groups: first IANA timezone becomes timeZone, rest are annotations\n const annotations: AnnotationAst[] = [];\n let timeZone: TimeZoneAst | undefined;\n\n while (this.at(TokType.LBracket)) {\n const { raw, critical, isLikelyTzId, pairs } = this.parseBracketGroup();\n\n // First timezone-like bracket becomes the timeZone field\n // Note: Even though IXDTF doesn't typically use critical flags for timezones,\n // we preserve it in case the input has it\n if (timeZone === undefined && isLikelyTzId) {\n // Strip leading ! from id (it's stored in the critical flag)\n const id = critical ? raw.slice(1) : raw;\n timeZone = { kind: 'IanaTimeZone', id, critical };\n } else {\n annotations.push({ kind: 'Annotation', raw, critical, pairs });\n }\n }\n\n return { kind: 'DateTime', date, time, offset, timeZone, annotations };\n }\n\n private parseDate(): DateAst {\n const yTok = this.eat(TokType.Number);\n const year = toInt(yTok.value, 'year', this.i);\n\n // Optional -MM\n if (!this.tryEat(TokType.Dash)) {\n return { kind: 'Date', year };\n }\n const mTok = this.eat(TokType.Number);\n const month = toInt(mTok.value, 'month', this.i);\n\n // Optional -DD\n if (!this.tryEat(TokType.Dash)) {\n return { kind: 'Date', year, month };\n }\n const dTok = this.eat(TokType.Number);\n const day = toInt(dTok.value, 'day', this.i);\n\n return { kind: 'Date', year, month, day };\n }\n\n private parseTime(): TimeAst {\n const hTok = this.eat(TokType.Number);\n const hour = toInt(hTok.value, 'hour', this.i);\n\n this.eat(TokType.Colon);\n const minTok = this.eat(TokType.Number);\n const minute = toInt(minTok.value, 'minute', this.i);\n\n let second: number | undefined;\n let fraction: string | undefined;\n\n if (this.tryEat(TokType.Colon)) {\n const sTok = this.eat(TokType.Number);\n second = toInt(sTok.value, 'second', this.i);\n\n if (this.tryEat(TokType.Dot)) {\n const fracTok = this.eat(TokType.Number);\n fraction = fracTok.value; // keep raw digits\n }\n }\n\n return { kind: 'Time', hour, minute, second, fraction };\n }\n\n /**\n * Parse timezone offset: Z | +HH:MM | -HH:MM\n *\n * Important semantic distinction per RFC 3339 and ISO 8601:\n *\n * - Z (Zulu time):\n * Explicitly indicates UTC. Used when the time is known to be in UTC.\n * Has no sign ambiguity - it's always UTC, never local time.\n *\n * - +00:00 (zero positive offset):\n * Indicates local time at the prime meridian (UTC+0 timezone).\n * Semantically different from Z - this is a local time that happens to match UTC.\n *\n * - -00:00 (zero negative offset):\n * Per RFC 3339 section 4.3: indicates local time with unknown UTC offset.\n * Used when the time is known to be local but the offset is not known.\n * This is semantically very different from both Z and +00:00.\n * https://www.rfc-editor.org/rfc/rfc3339.html#section-4.3\n *\n * We preserve this distinction by treating Z as UtcOffset (no sign, no components)\n * while +00:00 and -00:00 are NumericOffset (with sign and parsed components).\n */\n private parseOffsetIfPresent(): OffsetAst | undefined {\n if (this.tryEat(TokType.Z)) {\n return { kind: 'UtcOffset' };\n }\n\n // combined numeric offset token if you used combineTimezoneOffsets()\n if (this.at(CombinedTokType.TZOffset)) {\n const t = this.eat(CombinedTokType.TZOffset);\n return parseOffset(t.value, this.i);\n }\n\n return undefined;\n }\n\n // -------- Bracket group parsing --------\n // Consumes: [ ... ]\n // Returns:\n // - raw inner text (reconstructed)\n // - critical flag (true if starts with !)\n // - pairs if it looks like key=value (or flags)\n // - isLikelyTzId for things like [Asia/Singapore]\n private parseBracketGroup(): {\n raw: string;\n critical: boolean;\n pairs: Record<string, string | true>;\n isLikelyTzId: boolean;\n } {\n this.eat(TokType.LBracket);\n\n const parts: string[] = [];\n const pairs: Record<string, string | true> = {};\n\n // Check for critical flag (IXDTF: [!u-ca=gregory])\n const critical = this.tryEat(TokType.Exclamation) != null;\n if (critical) {\n parts.push('!');\n }\n\n // Gather tokens until RBracket\n while (!this.at(TokType.RBracket)) {\n if (this.eof()) {\n throw new ParseError('Unterminated bracket group', this.i);\n }\n\n const t = this.peek();\n this.i++;\n\n parts.push(String(t.value));\n }\n\n this.eat(TokType.RBracket);\n\n const raw = parts.join('');\n\n // Best-effort parse into key/value pairs:\n // Support \"key=value\" and \"flag\" and \"k=v,k2=v2\"\n // Strip leading ! if present for parsing\n const contentToParse = critical ? raw.slice(1) : raw;\n const segments = contentToParse\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n for (const seg of segments) {\n const eq = seg.indexOf('=');\n if (eq === -1) {\n pairs[seg] = true;\n } else {\n const k = seg.slice(0, eq).trim();\n const v = seg.slice(eq + 1).trim();\n if (k) {\n pairs[k] = v || true;\n }\n }\n }\n\n // Heuristic: likely TZ ID if no '=' present and contains '/' (e.g. Asia/Singapore) or starts with Etc/\n // We now preserve critical flag even for timezones, so don't exclude them\n const isLikelyTzId =\n contentToParse.indexOf('=') === -1 &&\n (contentToParse.includes('/') || contentToParse.startsWith('Etc/'));\n\n // Note: If you want STRICTLY separate tz-id brackets vs extension brackets, do it here.\n\n return { raw, critical, pairs, isLikelyTzId };\n }\n\n // -------- Duration parsing --------\n // Grammar (subset):\n // P (Y M W D)* (T (H M S)*)?\n // Examples:\n // P1Y2M\n // P3W\n // P10DT2H30M\n // PT1.5S\n private parseDuration(): DurationAst {\n // Collect raw string as we parse\n const rawParts: string[] = [];\n const annotations: AnnotationAst[] = [];\n\n const pTok = this.eat(TokType.Ident);\n if (String(pTok.value) !== 'P') {\n throw new ParseError(\"Duration must start with 'P'\", this.i);\n }\n rawParts.push('P');\n\n let inTime = false;\n\n const dur: Omit<DurationAst, 'kind' | 'raw' | 'annotations'> = {};\n\n // Parse designators until we hit bracket annotations, slash, or EOF\n while (!this.eof() && !this.at(TokType.Slash) && !this.at(TokType.LBracket)) {\n // Time marker T\n if (this.tryEat(TokType.T)) {\n rawParts.push('T');\n inTime = true;\n continue;\n }\n\n // Expect a number (possibly with fraction for seconds)\n const numTok = this.tryEat(TokType.Number);\n if (!numTok) {\n break;\n } // be permissive; let parser user decide if this is error-worthy\n rawParts.push(numTok.value);\n\n let fraction: string | undefined;\n if (this.tryEat(TokType.Dot)) {\n rawParts.push('.');\n const fracTok = this.eat(TokType.Number);\n rawParts.push(fracTok.value);\n fraction = fracTok.value;\n }\n\n // Unit is IDENT (Y,M,W,D,H,M,S). Note M is months if !inTime else minutes.\n const unitTok = this.eat(TokType.Ident);\n const unit = String(unitTok.value);\n rawParts.push(unit);\n\n const n = toInt(numTok.value, 'duration number', this.i);\n\n if (!inTime) {\n if (unit === 'Y') {\n dur.years = (dur.years ?? 0) + n;\n } else if (unit === 'M') {\n dur.months = (dur.months ?? 0) + n;\n } else if (unit === 'W') {\n dur.weeks = (dur.weeks ?? 0) + n;\n } else if (unit === 'D') {\n dur.days = (dur.days ?? 0) + n;\n } else {\n throw new ParseError(`Invalid duration unit '${unit}' in date part`, this.i);\n }\n } else {\n if (unit === 'H') {\n dur.hours = (dur.hours ?? 0) + n;\n } else if (unit === 'M') {\n dur.minutes = (dur.minutes ?? 0) + n;\n } else if (unit === 'S') {\n dur.seconds = (dur.seconds ?? 0) + n;\n if (fraction !== undefined && fraction.length > 0) {\n dur.secondsFraction = fraction;\n }\n } else {\n throw new ParseError(`Invalid duration unit '${unit}' in time part`, this.i);\n }\n }\n }\n\n // bracket annotations after duration\n while (this.at(TokType.LBracket)) {\n const { raw, critical, pairs } = this.parseBracketGroup();\n annotations.push({ kind: 'Annotation', raw, critical, pairs });\n }\n\n return { kind: 'Duration', ...dur, raw: rawParts.join(''), annotations };\n }\n}\n\n// ---------- Public API ----------\nexport function parseTemporal(src: string): TemporalAst {\n const raw = lexTemporal(src);\n const toks = combineTimezoneOffsets(raw);\n const p = new Parser(toks);\n return p.parseTemporal();\n}\n"],
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGO,IAAK,UAAL,kBAAKA,aAAL;AAGL,EAAAA,SAAA,YAAS;AAMT,EAAAA,SAAA,WAAQ;AAGR,EAAAA,SAAA,UAAO;AACP,EAAAA,SAAA,WAAQ;AACR,EAAAA,SAAA,SAAM;AACN,EAAAA,SAAA,UAAO;AACP,EAAAA,SAAA,WAAQ;AACR,EAAAA,SAAA,WAAQ;AACR,EAAAA,SAAA,YAAS;AACT,EAAAA,SAAA,gBAAa;AACb,EAAAA,SAAA,iBAAc;AAGd,EAAAA,SAAA,OAAI;AACJ,EAAAA,SAAA,OAAI;AAGJ,EAAAA,SAAA,cAAW;AACX,EAAAA,SAAA,cAAW;AAKX,EAAAA,SAAA,iBAAc;AAEd,EAAAA,SAAA,SAAM;AAnCI,SAAAA;AAAA,GAAA;AA8CL,IAAK,kBAAL,kBAAKC,qBAAL;AACL,EAAAA,iBAAA,cAAW;AADD,SAAAA;AAAA,GAAA;;;ACpBL,SAAS,uBAAuB,QAA6B;AAClE,QAAM,MAAkB,CAAC;AACzB,MAAI,IAAI;AAER,QAAM,OAAO,CAAC,MAAc,OAAO,IAAI,CAAC;AAOxC,QAAM,kBAAkB,MAAM;AAC5B,QAAI,IAAI,SAAS,GAAG;AAClB,aAAO;AAAA,IACT;AACA,UAAM,OAA6B,IAAI,IAAI,SAAS,CAAC;AACrD,QAAI,QAAQ,MAAM;AAChB,aAAO;AAAA,IACT;AAIA,QAAI,KAAK,sBAAoB;AAC3B,aAAO;AAAA,IACT;AAKA,QAAI,KAAK,oCAA2B;AAClC,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,gCAAyB;AAChC,UAAI,IAAI,SAAS,GAAG;AAClB,eAAO;AAAA,MACT;AACA,YAAM,WAAW,IAAI,IAAI,SAAS,CAAC;AAInC,UAAI,UAAU,8BAAwB;AACpC,eAAO;AAAA,MACT;AAIA,UAAI,UAAU,0BAAsB;AAClC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO,IAAI,OAAO,QAAQ;AACxB,UAAM,IAAI,OAAO,CAAC;AAClB,UAAM,SAAS,EAAE,8BAAyB,EAAE;AAG5C,QAAI,UAAU,gBAAgB,GAAG;AAE/B,UACE,KAAK,CAAC,GAAG,kCACT,KAAK,CAAC,GAAG,gCACT,KAAK,CAAC,GAAG,gCACT;AACA,cAAM,iBAAiB,CAAC,GAAG,KAAK,CAAC,GAAI,KAAK,CAAC,GAAI,KAAK,CAAC,CAAE;AACvD,cAAM,QAAQ,EAAE;AAChB,cAAM,MAAM,KAAK,CAAC,EAAG;AACrB,cAAM,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAK,CAAC,EAAG,KAAK,IAAI,KAAK,CAAC,EAAG,KAAK;AAC3D,YAAI,KAAK,EAAE,iCAAgC,OAAO,QAAQ,gBAAgB,OAAO,IAAI,CAAC;AACtF,aAAK;AACL;AAAA,MACF;AAGA,UAAI,KAAK,CAAC,GAAG,gCAAyB;AACpC,cAAM,MAAM,KAAK,CAAC,EAAG;AACrB,YAAI,IAAI,WAAW,KAAK,IAAI,WAAW,GAAG;AACxC,gBAAM,iBAAiB,CAAC,GAAG,KAAK,CAAC,CAAE;AACnC,gBAAM,QAAQ,EAAE;AAChB,gBAAM,MAAM,KAAK,CAAC,EAAG;AACrB,gBAAM,QAAQ,GAAG,EAAE,KAAK,GAAG,GAAG;AAC9B,cAAI,KAAK,EAAE,iCAAgC,OAAO,QAAQ,gBAAgB,OAAO,IAAI,CAAC;AACtF,eAAK;AACL;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,CAAC;AACV;AAAA,EACF;AAEA,SAAO;AACT;;;AC3HO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAClB;AAAA,EAChB,YAAY,SAAiB,UAAkB;AAC7C,UAAM,GAAG,OAAO,gBAAgB,QAAQ,EAAE;AAC1C,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EAClB;AACF;AAEO,IAAM,aAAN,cAAyB,MAAM;AAAA,EACpB;AAAA,EAChB,YAAY,SAAiB,UAAkB;AAC7C,UAAM,GAAG,OAAO,mBAAmB,QAAQ,EAAE;AAC7C,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EAClB;AACF;;;ACbO,SAAS,QAAQ,GAAoB;AAC1C,SAAQ,KAAK,OAAO,KAAK,OAAS,KAAK,OAAO,KAAK;AACrD;;;ACHO,SAAS,QAAQ,GAAW;AACjC,SAAO,KAAK,OAAO,KAAK;AAC1B;;;ACOO,SAAS,kBAAkB,GAAoB;AACpD,SACE,QAAQ,CAAC,KAAK,QAAQ,CAAC,KAAK,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM;AAE7E;;;ACOO,SAAS,YAAY,KAAsB;AAChD,QAAM,SAAkB,CAAC;AACzB,MAAI,IAAI;AAER,QAAM,OAAO,CAAC,MAAe,OAAe,KAAa,UAAmB;AAC1E,WAAO,KAAK,EAAE,MAAM,OAAO,SAAS,IAAI,MAAM,OAAO,GAAG,GAAG,OAAO,IAAI,CAAC;AAAA,EACzE;AAIA,QAAM,YAAY,MAAM;AACtB,UAAM,QAAQ;AACd;AACA,WAAO,IAAI,IAAI,UAAU,QAAQ,IAAI,CAAC,CAAE,GAAG;AACzC;AAAA,IACF;AACA,gCAAqB,OAAO,CAAC;AAAA,EAC/B;AAiBA,QAAM,WAAW,MAAM;AACrB,UAAM,QAAQ;AACd,UAAM,KAAK,IAAI,CAAC;AAChB;AAGA,QAAI,OAAO,KAAK;AACd,wBAAgB,OAAO,GAAG,GAAG;AAC7B;AAAA,IACF;AACA,QAAI,OAAO,KAAK;AACd,wBAAgB,OAAO,GAAG,GAAG;AAC7B;AAAA,IACF;AAIA,WAAO,IAAI,IAAI,UAAU,QAAQ,IAAI,CAAC,CAAE,KAAK,IAAI,CAAC,MAAM,OAAO,IAAI,CAAC,MAAM,KAAK;AAC7E;AAAA,IACF;AAEA,8BAAoB,OAAO,CAAC;AAAA,EAC9B;AAEA,QAAM,oBAAoB,MAAM;AAE9B,WAAO,IAAI,IAAI,QAAQ;AACrB,YAAM,KAAK,IAAI,CAAC;AAEhB,UAAI,OAAO,KAAK;AACd;AAAA,MACF;AAGA,UAAI,KAAK,KAAK,EAAE,GAAG;AACjB;AACA;AAAA,MACF;AAGA,UAAI,OAAO,KAAK;AACd,oCAAqB,GAAG,IAAI,CAAC;AAC7B;AACA;AAAA,MACF;AACA,UAAI,OAAO,KAAK;AACd,4CAAyB,GAAG,IAAI,CAAC;AACjC;AACA;AAAA,MACF;AACA,UAAI,OAAO,KAAK;AACd,kCAAoB,GAAG,IAAI,CAAC;AAC5B;AACA;AAAA,MACF;AACA,UAAI,OAAO,KAAK;AACd,gCAAmB,GAAG,IAAI,CAAC;AAC3B;AACA;AAAA,MACF;AACA,UAAI,OAAO,KAAK;AACd,gCAAmB,GAAG,IAAI,CAAC;AAC3B;AACA;AAAA,MACF;AACA,UAAI,OAAO,KAAK;AACd,kCAAoB,GAAG,IAAI,CAAC;AAC5B;AACA;AAAA,MACF;AACA,UAAI,OAAO,KAAK;AACd,8BAAkB,GAAG,IAAI,CAAC;AAC1B;AACA;AAAA,MACF;AACA,UAAI,OAAO,KAAK;AACd,kCAAoB,GAAG,IAAI,CAAC;AAC5B;AACA;AAAA,MACF;AACA,UAAI,OAAO,KAAK;AACd,8CAA0B,GAAG,IAAI,CAAC;AAClC;AACA;AAAA,MACF;AAGA,UAAI,kBAAkB,EAAE,GAAG;AACzB,cAAM,QAAQ;AACd;AACA,eAAO,IAAI,IAAI,UAAU,kBAAkB,IAAI,CAAC,CAAE,GAAG;AACnD;AAAA,QACF;AACA,cAAM,OAAO,IAAI,MAAM,OAAO,CAAC;AAO/B,YAAI,cAAc,KAAK,IAAI,GAAG;AAC5B,oCAAoB,OAAO,GAAG,IAAI;AAAA,QACpC,OAAO;AACL,gDAA0B,OAAO,GAAG,IAAI;AAAA,QAC1C;AAEA;AAAA,MACF;AAEA,YAAM,IAAI,SAAS,wBAAwB,KAAK,UAAU,EAAE,CAAC,oBAAoB,CAAC;AAAA,IACpF;AAEA,UAAM,IAAI,SAAS,iDAAiD,IAAI,MAAM;AAAA,EAChF;AAEA,SAAO,IAAI,IAAI,QAAQ;AACrB,UAAM,KAAK,IAAI,CAAC;AAGhB,QAAI,KAAK,KAAK,EAAE,GAAG;AACjB;AACA;AAAA,IACF;AAGA,QAAI,OAAO,KAAK;AACd,sCAAuB,GAAG,IAAI,CAAC;AAC/B;AAEA,wBAAkB;AAElB,UAAI,KAAK,IAAI,UAAU,IAAI,CAAC,MAAM,KAAK;AACrC,cAAM,IAAI,SAAS,iDAAiD,CAAC;AAAA,MACvE;AACA,sCAAuB,GAAG,IAAI,CAAC;AAC/B;AACA;AAAA,IACF;AAGA,QAAI,QAAQ,EAAE,GAAG;AACf,gBAAU;AACV;AAAA,IACF;AAKA,QAAI,QAAQ,EAAE,GAAG;AACf,eAAS;AACT;AAAA,IACF;AAGA,YAAQ,IAAI;AAAA,MACV,KAAK;AACH,gCAAmB,GAAG,IAAI,CAAC;AAC3B;AACA;AAAA,MACF,KAAK;AACH,kCAAoB,GAAG,IAAI,CAAC;AAC5B;AACA;AAAA,MACF,KAAK;AACH,8BAAkB,GAAG,IAAI,CAAC;AAC1B;AACA;AAAA,MACF,KAAK;AACH,gCAAmB,GAAG,IAAI,CAAC;AAC3B;AACA;AAAA,MACF,KAAK;AACH,kCAAoB,GAAG,IAAI,CAAC;AAC5B;AACA;AAAA,MACF,KAAK;AACH,kCAAoB,GAAG,IAAI,CAAC;AAC5B;AACA;AAAA,MACF,KAAK;AACH,oCAAqB,GAAG,IAAI,CAAC;AAC7B;AACA;AAAA,MACF,KAAK;AACH,4CAAyB,GAAG,IAAI,CAAC;AACjC;AACA;AAAA,MACF;AACE,cAAM,IAAI,SAAS,wBAAwB,KAAK,UAAU,EAAE,CAAC,IAAI,CAAC;AAAA,IACtE;AAAA,EACF;AAEA,wBAAkB,IAAI,QAAQ,IAAI,QAAQ,EAAE;AAC5C,SAAO;AACT;;;ACnPO,SAAS,MAAM,GAAW,OAAe,UAA0B;AACxE,QAAM,IAAI,OAAO,CAAC;AAClB,MAAI,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,GAAG;AAC/C,UAAM,IAAI,WAAW,uBAAuB,KAAK,KAAK,KAAK,UAAU,CAAC,CAAC,IAAI,QAAQ;AAAA,EACrF;AACA,SAAO;AACT;;;ACLA,IAAM,mBAAmB;AACzB,IAAM,cAAc;AAgCb,SAAS,YAAY,cAAsB,WAAW,GAAc;AAEzE,MAAI,aAAa,WAAW,GAAG;AAC7B,UAAM,IAAI,WAAW,iCAAiC,QAAQ;AAAA,EAChE;AAEA,QAAM,MAAM;AAGZ,QAAM,OAAO,IAAI,CAAC;AAClB,MAAI,SAAS,OAAO,SAAS,KAAK;AAChC,UAAM,IAAI,WAAW,sCAAsC,KAAK,UAAU,IAAI,CAAC,IAAI,QAAQ;AAAA,EAC7F;AAEA,QAAM,YAAuB;AAE7B,QAAM,OAAO,IAAI,MAAM,CAAC;AAGxB,MAAI,KAAK,WAAW,GAAG;AACrB,UAAM,IAAI,WAAW,0CAA0C,QAAQ;AAAA,EACzE;AAEA,MAAI;AACJ,MAAI;AAEJ,MAAI,KAAK,SAAS,GAAG,GAAG;AAEtB,UAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,IAAI,WAAW,0BAA0B,GAAG,qBAAqB,QAAQ;AAAA,IACjF;AAEA,UAAM,CAAC,GAAG,CAAC,IAAI;AACf,YAAQ,MAAM,GAAI,gBAAgB,QAAQ;AAC1C,cAAU,MAAM,GAAI,kBAAkB,QAAQ;AAAA,EAChD,WAAW,KAAK,WAAW,GAAG;AAE5B,YAAQ,MAAM,KAAK,MAAM,GAAG,CAAC,GAAG,gBAAgB,QAAQ;AACxD,cAAU,MAAM,KAAK,MAAM,GAAG,CAAC,GAAG,kBAAkB,QAAQ;AAAA,EAC9D,WAAW,KAAK,WAAW,GAAG;AAE5B,YAAQ,MAAM,MAAM,gBAAgB,QAAQ;AAC5C,cAAU;AAAA,EACZ,OAAO;AACL,UAAM,IAAI;AAAA,MACR,0BAA0B,GAAG;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAGA,MAAI,QAAQ,KAAK,QAAQ,kBAAkB;AACzC,UAAM,IAAI,WAAW,0BAA0B,gBAAgB,SAAS,KAAK,IAAI,QAAQ;AAAA,EAC3F;AACA,MAAI,UAAU,KAAK,UAAU,aAAa;AACxC,UAAM,IAAI,WAAW,4BAA4B,WAAW,SAAS,OAAO,IAAI,QAAQ;AAAA,EAC1F;AAEA,SAAO,EAAE,MAAM,iBAAiB,MAAM,WAAW,OAAO,SAAS,IAAI;AACvE;;;AC3EA,IAAM,SAAN,MAAa;AAAA,EAEX,YAAoB,MAAkB;AAAlB;AAAA,EAAmB;AAAA,EAD/B,IAAI;AAAA,EAGJ,KAAK,IAAI,GAAa;AAC5B,WAAO,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC;AAAA,EAC7D;AAAA,EACQ,GAAG,MAA0C;AACnD,WAAO,KAAK,KAAK,EAAE,SAAS;AAAA,EAC9B;AAAA,EACQ,IAAI,MAA2C;AACrD,UAAM,IAAI,KAAK,KAAK;AACpB,QAAI,EAAE,SAAS,MAAM;AACnB,YAAM,IAAI,WAAW,YAAY,IAAI,YAAY,EAAE,IAAI,IAAI,KAAK,CAAC;AAAA,IACnE;AACA,SAAK;AACL,WAAO;AAAA,EACT;AAAA,EACQ,OAAO,MAAkD;AAC/D,QAAI,KAAK,GAAG,IAAI,GAAG;AACjB,aAAO,KAAK,IAAI,IAAI;AAAA,IACtB;AACA,WAAO;AAAA,EACT;AAAA,EACQ,MAAe;AACrB,WAAO,KAAK,kBAAc;AAAA,EAC5B;AAAA;AAAA,EAGA,gBAA6B;AAE3B,QAAI,KAAK,0BAAoB,GAAG;AAC9B,YAAM,MAAM,KAAK,iBAAiB;AAClC,WAAK,mBAAe;AACpB,aAAO,EAAE,MAAM,SAAS,OAAO,MAAM,IAAI;AAAA,IAC3C;AAEA,UAAM,QAAQ,KAAK,iBAAiB;AAEpC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,WAAW,oBAAoB,KAAK,CAAC;AAAA,IACjD;AAEA,QAAI,KAAK,0BAAoB,GAAG;AAC9B,YAAM,SAAS,KAAK,iBAAiB;AACrC,WAAK,mBAAe;AACpB,aAAO,EAAE,MAAM,SAAS,OAAO,OAAO,KAAK,OAAO;AAAA,IACpD;AAEA,SAAK,mBAAe;AACpB,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAoC;AAE1C,QAAI,KAAK,kBAAc,KAAK,KAAK,sBAAgB,KAAK,KAAK,4BAAmB,GAAG;AAC/E,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,sBAAgB,KAAK,OAAO,KAAK,KAAK,EAAE,KAAK,MAAM,KAAK;AAC/D,aAAO,KAAK,cAAc;AAAA,IAC5B;AAGA,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,gBAA6B;AACnC,UAAM,OAAO,KAAK,UAAU;AAE5B,QAAI;AAGJ,QAAI,KAAK,kBAAgB,GAAG;AAC1B,aAAO,KAAK,UAAU;AAAA,IACxB;AAGA,UAAM,SAAS,KAAK,qBAAqB;AAGzC,UAAM,cAA+B,CAAC;AACtC,QAAI;AAEJ,WAAO,KAAK,4BAAmB,GAAG;AAChC,YAAM,EAAE,KAAK,UAAU,cAAc,MAAM,IAAI,KAAK,kBAAkB;AAKtE,UAAI,aAAa,UAAa,cAAc;AAE1C,cAAM,KAAK,WAAW,IAAI,MAAM,CAAC,IAAI;AACrC,mBAAW,EAAE,MAAM,gBAAgB,IAAI,SAAS;AAAA,MAClD,OAAO;AACL,oBAAY,KAAK,EAAE,MAAM,cAAc,KAAK,UAAU,MAAM,CAAC;AAAA,MAC/D;AAAA,IACF;AAEA,WAAO,EAAE,MAAM,YAAY,MAAM,MAAM,QAAQ,UAAU,YAAY;AAAA,EACvE;AAAA,EAEQ,YAAqB;AAC3B,UAAM,OAAO,KAAK,yBAAkB;AACpC,UAAM,OAAO,MAAM,KAAK,OAAO,QAAQ,KAAK,CAAC;AAG7C,QAAI,CAAC,KAAK,wBAAmB,GAAG;AAC9B,aAAO,EAAE,MAAM,QAAQ,KAAK;AAAA,IAC9B;AACA,UAAM,OAAO,KAAK,yBAAkB;AACpC,UAAM,QAAQ,MAAM,KAAK,OAAO,SAAS,KAAK,CAAC;AAG/C,QAAI,CAAC,KAAK,wBAAmB,GAAG;AAC9B,aAAO,EAAE,MAAM,QAAQ,MAAM,MAAM;AAAA,IACrC;AACA,UAAM,OAAO,KAAK,yBAAkB;AACpC,UAAM,MAAM,MAAM,KAAK,OAAO,OAAO,KAAK,CAAC;AAE3C,WAAO,EAAE,MAAM,QAAQ,MAAM,OAAO,IAAI;AAAA,EAC1C;AAAA,EAEQ,YAAqB;AAC3B,UAAM,OAAO,KAAK,yBAAkB;AACpC,UAAM,OAAO,MAAM,KAAK,OAAO,QAAQ,KAAK,CAAC;AAE7C,SAAK,uBAAiB;AACtB,UAAM,SAAS,KAAK,yBAAkB;AACtC,UAAM,SAAS,MAAM,OAAO,OAAO,UAAU,KAAK,CAAC;AAEnD,QAAI;AACJ,QAAI;AAEJ,QAAI,KAAK,0BAAoB,GAAG;AAC9B,YAAM,OAAO,KAAK,yBAAkB;AACpC,eAAS,MAAM,KAAK,OAAO,UAAU,KAAK,CAAC;AAE3C,UAAI,KAAK,sBAAkB,GAAG;AAC5B,cAAM,UAAU,KAAK,yBAAkB;AACvC,mBAAW,QAAQ;AAAA,MACrB;AAAA,IACF;AAEA,WAAO,EAAE,MAAM,QAAQ,MAAM,QAAQ,QAAQ,SAAS;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBQ,uBAA8C;AACpD,QAAI,KAAK,kBAAgB,GAAG;AAC1B,aAAO,EAAE,MAAM,YAAY;AAAA,IAC7B;AAGA,QAAI,KAAK,4BAA2B,GAAG;AACrC,YAAM,IAAI,KAAK,6BAA4B;AAC3C,aAAO,YAAY,EAAE,OAAO,KAAK,CAAC;AAAA,IACpC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,oBAKN;AACA,SAAK,6BAAoB;AAEzB,UAAM,QAAkB,CAAC;AACzB,UAAM,QAAuC,CAAC;AAG9C,UAAM,WAAW,KAAK,sCAA0B,KAAK;AACrD,QAAI,UAAU;AACZ,YAAM,KAAK,GAAG;AAAA,IAChB;AAGA,WAAO,CAAC,KAAK,4BAAmB,GAAG;AACjC,UAAI,KAAK,IAAI,GAAG;AACd,cAAM,IAAI,WAAW,8BAA8B,KAAK,CAAC;AAAA,MAC3D;AAEA,YAAM,IAAI,KAAK,KAAK;AACpB,WAAK;AAEL,YAAM,KAAK,OAAO,EAAE,KAAK,CAAC;AAAA,IAC5B;AAEA,SAAK,6BAAoB;AAEzB,UAAM,MAAM,MAAM,KAAK,EAAE;AAKzB,UAAM,iBAAiB,WAAW,IAAI,MAAM,CAAC,IAAI;AACjD,UAAM,WAAW,eACd,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,OAAO;AACjB,eAAW,OAAO,UAAU;AAC1B,YAAM,KAAK,IAAI,QAAQ,GAAG;AAC1B,UAAI,OAAO,IAAI;AACb,cAAM,GAAG,IAAI;AAAA,MACf,OAAO;AACL,cAAM,IAAI,IAAI,MAAM,GAAG,EAAE,EAAE,KAAK;AAChC,cAAM,IAAI,IAAI,MAAM,KAAK,CAAC,EAAE,KAAK;AACjC,YAAI,GAAG;AACL,gBAAM,CAAC,IAAI,KAAK;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAIA,UAAM,eACJ,eAAe,QAAQ,GAAG,MAAM,OAC/B,eAAe,SAAS,GAAG,KAAK,eAAe,WAAW,MAAM;AAInE,WAAO,EAAE,KAAK,UAAU,OAAO,aAAa;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,gBAA6B;AAEnC,UAAM,WAAqB,CAAC;AAC5B,UAAM,cAA+B,CAAC;AAEtC,UAAM,OAAO,KAAK,uBAAiB;AACnC,QAAI,OAAO,KAAK,KAAK,MAAM,KAAK;AAC9B,YAAM,IAAI,WAAW,gCAAgC,KAAK,CAAC;AAAA,IAC7D;AACA,aAAS,KAAK,GAAG;AAEjB,QAAI,SAAS;AAEb,UAAM,MAAyD,CAAC;AAGhE,WAAO,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,sBAAgB,KAAK,CAAC,KAAK,4BAAmB,GAAG;AAE3E,UAAI,KAAK,kBAAgB,GAAG;AAC1B,iBAAS,KAAK,GAAG;AACjB,iBAAS;AACT;AAAA,MACF;AAGA,YAAM,SAAS,KAAK,4BAAqB;AACzC,UAAI,CAAC,QAAQ;AACX;AAAA,MACF;AACA,eAAS,KAAK,OAAO,KAAK;AAE1B,UAAI;AACJ,UAAI,KAAK,sBAAkB,GAAG;AAC5B,iBAAS,KAAK,GAAG;AACjB,cAAM,UAAU,KAAK,yBAAkB;AACvC,iBAAS,KAAK,QAAQ,KAAK;AAC3B,mBAAW,QAAQ;AAAA,MACrB;AAGA,YAAM,UAAU,KAAK,uBAAiB;AACtC,YAAM,OAAO,OAAO,QAAQ,KAAK;AACjC,eAAS,KAAK,IAAI;AAElB,YAAM,IAAI,MAAM,OAAO,OAAO,mBAAmB,KAAK,CAAC;AAEvD,UAAI,CAAC,QAAQ;AACX,YAAI,SAAS,KAAK;AAChB,cAAI,SAAS,IAAI,SAAS,KAAK;AAAA,QACjC,WAAW,SAAS,KAAK;AACvB,cAAI,UAAU,IAAI,UAAU,KAAK;AAAA,QACnC,WAAW,SAAS,KAAK;AACvB,cAAI,SAAS,IAAI,SAAS,KAAK;AAAA,QACjC,WAAW,SAAS,KAAK;AACvB,cAAI,QAAQ,IAAI,QAAQ,KAAK;AAAA,QAC/B,OAAO;AACL,gBAAM,IAAI,WAAW,0BAA0B,IAAI,kBAAkB,KAAK,CAAC;AAAA,QAC7E;AAAA,MACF,OAAO;AACL,YAAI,SAAS,KAAK;AAChB,cAAI,SAAS,IAAI,SAAS,KAAK;AAAA,QACjC,WAAW,SAAS,KAAK;AACvB,cAAI,WAAW,IAAI,WAAW,KAAK;AAAA,QACrC,WAAW,SAAS,KAAK;AACvB,cAAI,WAAW,IAAI,WAAW,KAAK;AACnC,cAAI,aAAa,UAAa,SAAS,SAAS,GAAG;AACjD,gBAAI,kBAAkB;AAAA,UACxB;AAAA,QACF,OAAO;AACL,gBAAM,IAAI,WAAW,0BAA0B,IAAI,kBAAkB,KAAK,CAAC;AAAA,QAC7E;AAAA,MACF;AAAA,IACF;AAGA,WAAO,KAAK,4BAAmB,GAAG;AAChC,YAAM,EAAE,KAAK,UAAU,MAAM,IAAI,KAAK,kBAAkB;AACxD,kBAAY,KAAK,EAAE,MAAM,cAAc,KAAK,UAAU,MAAM,CAAC;AAAA,IAC/D;AAEA,WAAO,EAAE,MAAM,YAAY,GAAG,KAAK,KAAK,SAAS,KAAK,EAAE,GAAG,YAAY;AAAA,EACzE;AACF;AAGO,SAAS,cAAc,KAA0B;AACtD,QAAM,MAAM,YAAY,GAAG;AAC3B,QAAM,OAAO,uBAAuB,GAAG;AACvC,QAAM,IAAI,IAAI,OAAO,IAAI;AACzB,SAAO,EAAE,cAAc;AACzB;",
"sources": ["../../src/index.ts", "../../src/lexer-types.ts", "../../src/combineTimezoneOffsets.ts", "../../src/errors.ts", "../../src/helpers/isAlpha.ts", "../../src/helpers/isDigit.ts", "../../src/helpers/isBracketWordChar.ts", "../../src/lexer.ts", "../../src/helpers/toInt.ts", "../../src/parseOffset.ts", "../../src/parser.ts", "../../src/stringify.ts"],
"sourcesContent": ["// index.ts\n// Main entry point for the temporal parser library\n\n// Export lexer functionality\nexport { combineTimezoneOffsets } from './combineTimezoneOffsets.js';\nexport { lexTemporal } from './lexer.js';\n\n// Export lexer types\nexport type { AnyToken, CombinedToken, Token } from './lexer-types.js';\nexport { CombinedTokType, TokType } from './lexer-types.js';\n\n// Export parser functionality\nexport { parseTemporal } from './parser.js';\n\n// Export offset parser (useful standalone utility)\nexport { parseOffset } from './parseOffset.js';\n\n// Export stringify functionality\nexport {\n stringifyAnnotation,\n stringifyDate,\n stringifyDateTime,\n stringifyDuration,\n stringifyOffset,\n stringifyRange,\n stringifyTemporal,\n stringifyTime,\n stringifyTimeZone,\n} from './stringify.js';\n\n// Export parser types\nexport type {\n AnnotationAst,\n DateAst,\n DateTimeAst,\n DurationAst,\n OffsetAst,\n RangeAst,\n TemporalAst,\n TimeAst,\n TimeZoneAst,\n ValueAst,\n} from './parser-types.js';\n\n// Export errors\nexport { LexError, ParseError } from './errors.js';\n", "// lexer-types.ts\n// Token types and interfaces for the lexer\n\nexport enum TokType {\n // Numbers: sequences of digits (0-9)\n // Examples: \"2025\", \"01\", \"12\", \"59\"\n Number = 'Number',\n\n // Ident (Identifier): sequences of alphabetic characters (A-Z, a-z)\n // This is the generic \"text\" token for letter-based designators.\n // Examples: \"P\" (duration), \"Y\" (year), \"M\" (month), \"gregory\" (calendar)\n // The lexer keeps it simple; the parser interprets the meaning.\n Ident = 'Ident',\n\n // Single-character punctuation tokens\n Dash = 'Dash', // -\n Colon = 'Colon', // :\n Dot = 'Dot', // .\n Plus = 'Plus', // +\n Slash = 'Slash', // /\n Comma = 'Comma', // ,\n Equals = 'Equals', // =\n Underscore = 'Underscore', // _\n Exclamation = 'Exclamation', // ! (critical flag in IXDTF)\n\n // Special letter tokens with dedicated meaning in ISO 8601\n T = 'T', // Date/time separator: 2025-01-01T10:00:00\n Z = 'Z', // UTC timezone marker: 2025-01-01T10:00:00Z\n\n // Bracket tokens for IXDTF annotations/extensions\n LBracket = 'LBracket', // [\n RBracket = 'RBracket', // ]\n\n // BracketText: complex text inside brackets that contains non-letter chars\n // Example: in [u-ca=gregory], \"u-ca\" is BracketText (has dash), \"gregory\" is Ident (letters only)\n // Example: in [Asia/Singapore], \"Asia/Singapore\" is BracketText (has slash)\n BracketText = 'BracketText',\n\n EOF = 'EOF',\n}\n\nexport type Token = {\n type: TokType;\n value: string;\n start: number; // inclusive\n end: number; // exclusive\n};\n\n// Combined token types for timezone offsets\nexport enum CombinedTokType {\n TZOffset = 'TZOffset', // +08:00, -0530, +09\n}\n\nexport type CombinedToken = {\n type: CombinedTokType;\n value: string;\n tokens: Token[];\n start: number;\n end: number;\n};\n\nexport type AnyToken = Token | CombinedToken;\n", "// combineTimezoneOffsets.ts\n// Combines numeric timezone offset tokens into single tokens for easier parsing\n\nimport { type AnyToken, CombinedTokType, type Token, TokType } from './lexer-types.js';\n\n/**\n * Combine numeric timezone offsets into single tokens for easier parsing.\n * This is an optional post-processing step for the lexer output.\n *\n * Combines patterns like:\n * - (+|-) Number Colon Number => +08:00, -05:30\n * - (+|-) Number (2 or 4 digits) => +09, -0530\n *\n * Only combines when context suggests a timezone offset (after time components),\n * NOT after:\n * - Z (mutually exclusive per ISO 8601)\n * - brackets (offset comes BEFORE brackets per RFC 9557/IXDTF)\n * - standalone dates (e.g., 2025-01 where - is a date separator)\n *\n * @param tokens - The raw token array from lexTemporal\n * @returns Array of tokens (either original Token or combined CombinedToken with TZOffset type where applicable)\n *\n * @example\n * ```typescript\n * const raw = lexTemporal('10:00:00+08:00');\n * const combined = combineTimezoneOffsets(raw);\n * // Result includes: { type: 'TZOffset', value: '+08:00' }\n * ```\n */\nexport function combineTimezoneOffsets(tokens: Token[]): AnyToken[] {\n const out: AnyToken[] = [];\n let i = 0;\n\n const peek = (k: number) => tokens[i + k];\n\n // Helper to check if previous tokens suggest this could be a timezone offset\n // Timezone offsets come after time components (HH:MM:SS)\n // NOT after just a date like 2025-01\n // NOT after Z (Z and numeric offsets are mutually exclusive per ISO 8601)\n // NOT after brackets (per RFC 9557/IXDTF: offset comes BEFORE brackets)\n const couldBeTzOffset = () => {\n if (out.length < 1) {\n return false;\n }\n const prev: AnyToken | undefined = out[out.length - 1];\n if (prev == null) {\n return false;\n }\n\n // After Z - NOT valid (Z and numeric offsets are mutually exclusive)\n // Per ISO 8601: use either Z OR +HH:MM, never both\n if (prev.type === TokType.Z) {\n return false;\n }\n\n // After bracket - NOT valid (offset must come BEFORE brackets per RFC 9557)\n // Valid: Time+08:00[Asia/Tokyo]\n // Invalid: [Asia/Tokyo]+08:00\n if (prev.type === TokType.RBracket) {\n return false;\n }\n\n // After a number, check context\n if (prev.type === TokType.Number) {\n if (out.length < 2) {\n return false;\n }\n const prevPrev = out[out.length - 2];\n\n // After a number with colon before it (time component)\n // e.g., ...10:00:00+08:00 - the number before + has a colon before it\n if (prevPrev?.type === TokType.Colon) {\n return true;\n }\n\n // After a number with dot before it (milliseconds)\n // e.g., ...10:00:00.999+08:00 - the number before + has a dot before it\n if (prevPrev?.type === TokType.Dot) {\n return true;\n }\n }\n\n return false;\n };\n\n while (i < tokens.length) {\n const t = tokens[i]!;\n const isSign = t.type === TokType.Plus || t.type === TokType.Dash;\n\n // Only try to combine if context suggests timezone offset\n if (isSign && couldBeTzOffset()) {\n // (+|-) Number Colon Number => +08:00\n if (\n peek(1)?.type === TokType.Number &&\n peek(2)?.type === TokType.Colon &&\n peek(3)?.type === TokType.Number\n ) {\n const originalTokens = [t, peek(1)!, peek(2)!, peek(3)!];\n const start = t.start;\n const end = peek(3)!.end;\n const value = `${t.value}${peek(1)!.value}:${peek(3)!.value}`;\n out.push({ type: CombinedTokType.TZOffset, value, tokens: originalTokens, start, end });\n i += 4;\n continue;\n }\n\n // (+|-) Number where Number is 2 or 4 digits => +09 or -0530\n if (peek(1)?.type === TokType.Number) {\n const num = peek(1)!.value;\n if (num.length === 2 || num.length === 4) {\n const originalTokens = [t, peek(1)!];\n const start = t.start;\n const end = peek(1)!.end;\n const value = `${t.value}${num}`;\n out.push({ type: CombinedTokType.TZOffset, value, tokens: originalTokens, start, end });\n i += 2;\n continue;\n }\n }\n }\n\n out.push(t);\n i++;\n }\n\n return out;\n}\n", "// errors.ts\n// Error classes for lexer and parser\n\nexport class LexError extends Error {\n public readonly position: number;\n constructor(message: string, position: number) {\n super(`${message} at position ${position}`);\n this.name = 'LexError';\n this.position = position;\n }\n}\n\nexport class ParseError extends Error {\n public readonly position: number;\n constructor(message: string, position: number) {\n super(`${message} at token index ${position}`);\n this.name = 'ParseError';\n this.position = position;\n }\n}\n", "/**\n * Check if character is alphabetic (A-Z or a-z)\n * This defines what can be part of an IDENT token in default mode\n * @param c - the character to check\n * @returns true if character is alphabetic, false otherwise\n */\nexport function isAlpha(c: string): boolean {\n return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');\n}\n", "/**\n * Check if character is a digit (0-9)\n * @param c - the character to check\n * @returns true if character is a digit, false otherwise\n */\nexport function isDigit(c: string) {\n return c >= '0' && c <= '9';\n}\n", "import { isAlpha } from './isAlpha.js';\nimport { isDigit } from './isDigit.js';\n\n/**\n * Check if character is valid inside bracket annotations\n * In default mode, IDENT is letters only (keeps date/time parsing clean).\n * In bracket mode, we allow broader \"words\" like:\n * - u-ca (has dash)\n * - Asia/Singapore (has slash)\n * - Etc/GMT+8 (has plus)\n * - iso8601 (has digits)\n * @param c - the character to check\n * @returns true if character is valid in bracket context, false otherwise\n */\nexport function isBracketWordChar(c: string): boolean {\n return (\n isAlpha(c) || isDigit(c) || c === '-' || c === '/' || c === '+' || c === '.' // allow dots in some TZ-ish values\n );\n}\n", "// lexer.ts\n// Temporal (IXDTF / ISO-8601-ish) lexer with support for *extensions/annotations* like calendar.\n//\n// Supports:\n// - Basic date/time tokens: numbers, identifiers, T, Z, punctuation\n// - Ranges: '/'\n// - Durations: 'P' (as IDENT; parser enforces rules)\n// - Time zone forms:\n// - 'Z'\n// - numeric offsets: +08:00 / -0530 / +09 (optionally combined via helper)\n// - bracketed IANA TZ: [Asia/Singapore]\n// - IXDTF-style annotations/extensions in brackets, e.g.:\n// - [u-ca=gregory] (calendar)\n// - [u-tz=Asia/Singapore] (timeZone)\n// - multiple bracket groups: 2025-01-01T00:00Z[u-ca=iso8601][u-tz=UTC]\n//\n// The lexer is permissive; your parser should validate semantics.\n\nimport { LexError } from './errors.js';\nimport { isAlpha } from './helpers/isAlpha.js';\nimport { isBracketWordChar } from './helpers/isBracketWordChar.js';\nimport { isDigit } from './helpers/isDigit.js';\nimport type { Token } from './lexer-types.js';\nimport { TokType } from './lexer-types.js';\n\nexport function lexTemporal(src: string): Token[] {\n const tokens: Token[] = [];\n let i = 0;\n\n const emit = (type: TokType, start: number, end: number, value?: string) => {\n tokens.push({ type, value: value ?? src.slice(start, end), start, end });\n };\n\n // Lex a number: consume consecutive digits\n // Examples: \"2025\", \"01\", \"59\"\n const lexNumber = () => {\n const start = i;\n i++;\n while (i < src.length && isDigit(src[i]!)) {\n i++;\n }\n emit(TokType.Number, start, i);\n };\n\n // Lex an identifier: consume consecutive alphabetic characters\n // This is where IDENT tokens are created!\n //\n // Examples of what becomes IDENT:\n // - Duration designators: P, Y, M, W, D, H, S\n // - Calendar names: gregory, hebrew, iso8601\n // - Any letter sequence: P, YMD, UTC, America\n //\n // Special cases:\n // - \"T\" gets its own token type (datetime separator)\n // - \"Z\" gets its own token type (UTC marker)\n // - Everything else becomes Ident\n //\n // IMPORTANT: We only consume a single letter at a time to allow T and Z\n // to be recognized individually (e.g., \"DT\" should be \"D\" then \"T\", not \"DT\")\n const lexIdent = () => {\n const start = i;\n const ch = src[i]!;\n i++;\n\n // Special handling for T and Z - emit them as special tokens\n if (ch === 'T') {\n emit(TokType.T, start, i, 'T');\n return;\n }\n if (ch === 'Z') {\n emit(TokType.Z, start, i, 'Z');\n return;\n }\n\n // For other letters, consume consecutive letters that are NOT T or Z\n // This allows multi-letter identifiers like \"gregory\" but keeps T and Z separate\n while (i < src.length && isAlpha(src[i]!) && src[i] !== 'T' && src[i] !== 'Z') {\n i++;\n }\n\n emit(TokType.Ident, start, i); // Generic identifier\n };\n\n const lexBracketContent = () => {\n // We are positioned after '['. Emit content tokens until ']'.\n while (i < src.length) {\n const ch = src[i]!;\n\n if (ch === ']') {\n return;\n }\n\n // Skip whitespace inside brackets (rare but harmless)\n if (/\\s/.test(ch)) {\n i++;\n continue;\n }\n\n // Single-char tokens inside brackets\n if (ch === '=') {\n emit(TokType.Equals, i, i + 1);\n i++;\n continue;\n }\n if (ch === '_') {\n emit(TokType.Underscore, i, i + 1);\n i++;\n continue;\n }\n if (ch === ':') {\n emit(TokType.Colon, i, i + 1);\n i++;\n continue;\n }\n if (ch === '-') {\n emit(TokType.Dash, i, i + 1);\n i++;\n continue;\n }\n if (ch === '+') {\n emit(TokType.Plus, i, i + 1);\n i++;\n continue;\n }\n if (ch === '/') {\n emit(TokType.Slash, i, i + 1);\n i++;\n continue;\n }\n if (ch === '.') {\n emit(TokType.Dot, i, i + 1);\n i++;\n continue;\n }\n if (ch === ',') {\n emit(TokType.Comma, i, i + 1);\n i++;\n continue;\n }\n if (ch === '!') {\n emit(TokType.Exclamation, i, i + 1);\n i++;\n continue;\n }\n\n // Words inside brackets (u-ca, gregory, Asia/Singapore, iso8601, Etc/GMT+8, etc.)\n if (isBracketWordChar(ch)) {\n const start = i;\n i++;\n while (i < src.length && isBracketWordChar(src[i]!)) {\n i++;\n }\n const text = src.slice(start, i);\n\n // Decision: Ident vs BracketText\n // - If purely letters (A-Z, a-z): emit as Ident\n // Examples: \"gregory\", \"hebrew\", \"u\", \"ca\"\n // - If contains other chars (digits, -, /, +, .): emit as BracketText\n // Examples: \"u-ca\", \"Asia/Singapore\", \"iso8601\", \"Etc/GMT+8\"\n if (/^[A-Za-z]+$/.test(text)) {\n emit(TokType.Ident, start, i, text);\n } else {\n emit(TokType.BracketText, start, i, text);\n }\n\n continue;\n }\n\n throw new LexError(`Unexpected character ${JSON.stringify(ch)} inside brackets`, i);\n }\n\n throw new LexError(\"Unterminated bracket annotation, expected ']'\", src.length);\n };\n\n while (i < src.length) {\n const ch = src[i]!;\n\n // Skip whitespace\n if (/\\s/.test(ch)) {\n i++;\n continue;\n }\n\n // Bracketed extensions/annotations/timezone IDs\n if (ch === '[') {\n emit(TokType.LBracket, i, i + 1);\n i++;\n\n lexBracketContent();\n\n if (i >= src.length || src[i] !== ']') {\n throw new LexError(\"Unterminated bracket annotation, expected ']'\", i);\n }\n emit(TokType.RBracket, i, i + 1);\n i++;\n continue;\n }\n\n // Numbers: sequences of digits\n if (isDigit(ch)) {\n lexNumber();\n continue;\n }\n\n // Letters: this is where IDENT tokens are created!\n // Any alphabetic character triggers identifier lexing.\n // Examples: P (duration), Y (year), M (month), gregory, UTC\n if (isAlpha(ch)) {\n lexIdent();\n continue;\n }\n\n // Punctuation (default mode)\n switch (ch) {\n case '-':\n emit(TokType.Dash, i, i + 1);\n i++;\n continue;\n case ':':\n emit(TokType.Colon, i, i + 1);\n i++;\n continue;\n case '.':\n emit(TokType.Dot, i, i + 1);\n i++;\n continue;\n case '+':\n emit(TokType.Plus, i, i + 1);\n i++;\n continue;\n case '/':\n emit(TokType.Slash, i, i + 1);\n i++;\n continue;\n case ',':\n emit(TokType.Comma, i, i + 1);\n i++;\n continue;\n case '=':\n emit(TokType.Equals, i, i + 1);\n i++;\n continue;\n case '_':\n emit(TokType.Underscore, i, i + 1);\n i++;\n continue;\n default:\n throw new LexError(`Unexpected character ${JSON.stringify(ch)}`, i);\n }\n }\n\n emit(TokType.EOF, src.length, src.length, '');\n return tokens;\n}\n", "import { ParseError } from '../errors.js';\n\n/**\n * Convert a string to an integer, throwing a ParseError if invalid\n * @param s - the string to convert\n * @param label - a descriptive label for error messages (e.g., \"year\", \"month\")\n * @param position - the position in the token stream for error reporting\n * @returns the parsed integer value\n * @throws {ParseError} if the string is not a valid integer\n */\nexport function toInt(s: string, label: string, position: number): number {\n const n = Number(s);\n if (!Number.isFinite(n) || !Number.isInteger(n)) {\n throw new ParseError(`Invalid integer for ${label}: ${JSON.stringify(s)}`, position);\n }\n return n;\n}\n", "// parseOffset.ts\n// Parse timezone offset strings into structured components\n\nimport { ParseError } from './errors.js';\nimport { toInt } from './helpers/toInt.js';\nimport type { OffsetAst } from './parser-types.js';\n\n// Timezone offset validation constants\n// Per ISO 8601 and real-world usage:\n// - Westernmost: UTC-12:00 (Baker Island, Howland Island)\n// - Easternmost: UTC+14:00 (Line Islands, Kiritimati)\nconst MAX_OFFSET_HOURS = 14;\nconst MAX_MINUTES = 59;\n\n/**\n * Parse a timezone offset string into structured components.\n *\n * Supports three formats:\n * - Standard: +08:00, -05:30\n * - Compact: +0530, -0800\n * - Short: +09, -05\n *\n * Valid timezone offset ranges (per ISO 8601):\n * - Hours: 0-14 (UTC-12:00 to UTC+14:00)\n * - Minutes: 0-59\n *\n * Note: This function only parses numeric offsets (e.g., +08:00).\n * For UTC, use 'Z' (UtcOffset kind) which is semantically different from +00:00.\n * Per RFC 3339 section 4.3, -00:00 indicates \"local time with unknown offset\".\n *\n * @param offsetString - The offset string to parse (e.g., '+08:00', '-0530', '+09')\n * @param position - Position in token stream for error reporting (optional)\n * @returns Parsed offset with sign, hours, and minutes\n * @throws {ParseError} If the offset format is invalid or out of range\n *\n * @example\n * ```typescript\n * parseOffset('+08:00') // { kind: 'NumericOffset', sign: '+', hours: 8, minutes: 0, raw: '+08:00' }\n * parseOffset('-05:30') // { kind: 'NumericOffset', sign: '-', hours: 5, minutes: 30, raw: '-05:30' }\n * parseOffset('+0530') // { kind: 'NumericOffset', sign: '+', hours: 5, minutes: 30, raw: '+0530' }\n * parseOffset('+09') // { kind: 'NumericOffset', sign: '+', hours: 9, minutes: 0, raw: '+09' }\n * parseOffset('+14:00') // { kind: 'NumericOffset', sign: '+', hours: 14, minutes: 0, raw: '+14:00' }\n * ```\n */\nexport function parseOffset(offsetString: string, position = 0): OffsetAst {\n // Validate input is not empty\n if (offsetString.length === 0) {\n throw new ParseError('Offset string cannot be empty', position);\n }\n\n const raw = offsetString;\n\n // Validate first character is sign and assert type\n const sign = raw[0];\n if (sign !== '+' && sign !== '-') {\n throw new ParseError(`Offset must start with + or -, got ${JSON.stringify(sign)}`, position);\n }\n // Type assertion: TypeScript now knows sign is '+' | '-'\n const validSign: '+' | '-' = sign;\n\n const rest = raw.slice(1);\n\n // Validate rest is not empty\n if (rest.length === 0) {\n throw new ParseError(`Offset sign must be followed by digits`, position);\n }\n\n let hours: number;\n let minutes: number;\n\n if (rest.includes(':')) {\n // Format: +08:00 or -05:30\n const parts = rest.split(':');\n if (parts.length !== 2) {\n throw new ParseError(`Invalid offset format: ${raw} (expected HH:MM)`, position);\n }\n // After length check, we know parts[0] and parts[1] exist\n const [h, m] = parts;\n hours = toInt(h!, 'offset hours', position);\n minutes = toInt(m!, 'offset minutes', position);\n } else if (rest.length === 4) {\n // Format: +0530 or -0800\n hours = toInt(rest.slice(0, 2), 'offset hours', position);\n minutes = toInt(rest.slice(2, 4), 'offset minutes', position);\n } else if (rest.length === 2) {\n // Format: +08 or -05\n hours = toInt(rest, 'offset hours', position);\n minutes = 0;\n } else {\n throw new ParseError(\n `Invalid offset format: ${raw} (expected +HH:MM, +HHMM, or +HH)`,\n position,\n );\n }\n\n // Validate ranges\n if (hours < 0 || hours > MAX_OFFSET_HOURS) {\n throw new ParseError(`Offset hours must be 0-${MAX_OFFSET_HOURS}, got ${hours}`, position);\n }\n if (minutes < 0 || minutes > MAX_MINUTES) {\n throw new ParseError(`Offset minutes must be 0-${MAX_MINUTES}, got ${minutes}`, position);\n }\n\n return { kind: 'NumericOffset', sign: validSign, hours, minutes, raw };\n}\n", "// parser.ts\n// A practical recursive-descent parser that works with the lexer we wrote.\n// It builds an AST for a useful Temporal subset:\n// - date/time (with optional fractional seconds)\n// - timezone: Z | numeric offset (+08:00, -0530, +09) | bracket TZ id [Asia/Singapore]\n// - duration: P... with optional T part\n// - range: <expr> \"/\" <expr> where each side can be dateTime/date/duration, and either side may be empty (open range)\n// - bracket extensions like [u-ca=gregory], [u-tz=Asia/Singapore], etc. (stored as key/value pairs)\n\nimport { combineTimezoneOffsets } from './combineTimezoneOffsets.js';\nimport { ParseError } from './errors.js';\nimport { toInt } from './helpers/toInt.js';\nimport { lexTemporal } from './lexer.js';\nimport { type AnyToken, CombinedTokType, TokType } from './lexer-types.js';\nimport { parseOffset } from './parseOffset.js';\nimport type {\n AnnotationAst,\n DateAst,\n DateTimeAst,\n DurationAst,\n OffsetAst,\n TemporalAst,\n TimeAst,\n TimeZoneAst,\n ValueAst,\n} from './parser-types.js';\n\n// ---------- Parser ----------\n\nclass Parser {\n private i = 0;\n constructor(private toks: AnyToken[]) {}\n\n private peek(k = 0): AnyToken {\n return this.toks[Math.min(this.i + k, this.toks.length - 1)]!;\n }\n private at(type: TokType | CombinedTokType): boolean {\n return this.peek().type === type;\n }\n private eat(type: TokType | CombinedTokType): AnyToken {\n const t = this.peek();\n if (t.type !== type) {\n throw new ParseError(`Expected ${type} but got ${t.type}`, this.i);\n }\n this.i++;\n return t;\n }\n private tryEat(type: TokType | CombinedTokType): AnyToken | null {\n if (this.at(type)) {\n return this.eat(type);\n }\n return null;\n }\n private eof(): boolean {\n return this.at(TokType.EOF);\n }\n\n // Top-level: parse a range if we see '/', otherwise a single value.\n parseTemporal(): TemporalAst {\n // Open-start range: \"/...\"\n if (this.tryEat(TokType.Slash)) {\n const end = this.parseValueOrNull(); // allow empty end too\n this.eat(TokType.EOF);\n return { kind: 'Range', start: null, end };\n }\n\n const first = this.parseValueOrNull();\n // If first is null, only valid if it's \"/\" (handled above). So error:\n if (!first) {\n throw new ParseError('Expected a value', this.i);\n }\n\n if (this.tryEat(TokType.Slash)) {\n const second = this.parseValueOrNull(); // open-ended allowed\n this.eat(TokType.EOF);\n return { kind: 'Range', start: first, end: second };\n }\n\n this.eat(TokType.EOF);\n return first;\n }\n\n private parseValueOrNull(): ValueAst | null {\n // Empty side for open range:\n if (this.at(TokType.EOF) || this.at(TokType.Slash) || this.at(TokType.RBracket)) {\n return null;\n }\n\n // Duration starts with IDENT \"P\" (as produced by lexer)\n if (this.at(TokType.Ident) && String(this.peek().value) === 'P') {\n return this.parseDuration();\n }\n\n // Otherwise parse a date/datetime (common case)\n return this.parseDateTime();\n }\n\n // -------- DateTime parsing --------\n // Supports:\n // - YYYY\n // - YYYY-MM\n // - YYYY-MM-DD\n // - + time part with T: YYYY-MM-DDTHH:MM[:SS[.fff]]\n // - offset: Z | +08:00 | -0530\n // - timezone: [Asia/Singapore] (first bracketed IANA timezone)\n // - annotations: [u-ca=...][u-tz=...] (other bracketed content)\n private parseDateTime(): DateTimeAst {\n const date = this.parseDate();\n\n let time: DateTimeAst['time'] | undefined;\n\n // time separator is TokType.T (from lexer special-casing \"T\")\n if (this.tryEat(TokType.T)) {\n time = this.parseTime();\n }\n\n // Parse numeric offset (Z or +HH:MM)\n const offset = this.parseOffsetIfPresent();\n\n // Parse bracket groups: first IANA timezone becomes timeZone, rest are annotations\n const annotations: AnnotationAst[] = [];\n let timeZone: TimeZoneAst | undefined;\n\n while (this.at(TokType.LBracket)) {\n const { raw, critical, isLikelyTzId, pairs } = this.parseBracketGroup();\n\n // First timezone-like bracket becomes the timeZone field\n // Note: Even though IXDTF doesn't typically use critical flags for timezones,\n // we preserve it in case the input has it\n if (timeZone === undefined && isLikelyTzId) {\n // Strip leading ! from id (it's stored in the critical flag)\n const id = critical ? raw.slice(1) : raw;\n timeZone = { kind: 'IanaTimeZone', id, critical };\n } else {\n annotations.push({ kind: 'Annotation', raw, critical, pairs });\n }\n }\n\n return { kind: 'DateTime', date, time, offset, timeZone, annotations };\n }\n\n private parseDate(): DateAst {\n // Check for optional leading dash (negative year / BC date)\n // ISO 8601: Year 0 = 1 BC, Year -1 = 2 BC, etc.\n const isNegative = this.tryEat(TokType.Dash);\n \n const yTok = this.eat(TokType.Number);\n let year = toInt(yTok.value, 'year', this.i);\n if (isNegative) {\n year = -year;\n }\n\n // Optional -MM\n if (!this.tryEat(TokType.Dash)) {\n return { kind: 'Date', year };\n }\n const mTok = this.eat(TokType.Number);\n const month = toInt(mTok.value, 'month', this.i);\n\n // Optional -DD\n if (!this.tryEat(TokType.Dash)) {\n return { kind: 'Date', year, month };\n }\n const dTok = this.eat(TokType.Number);\n const day = toInt(dTok.value, 'day', this.i);\n\n return { kind: 'Date', year, month, day };\n }\n\n private parseTime(): TimeAst {\n const hTok = this.eat(TokType.Number);\n const hour = toInt(hTok.value, 'hour', this.i);\n\n this.eat(TokType.Colon);\n const minTok = this.eat(TokType.Number);\n const minute = toInt(minTok.value, 'minute', this.i);\n\n let second: number | undefined;\n let fraction: string | undefined;\n\n if (this.tryEat(TokType.Colon)) {\n const sTok = this.eat(TokType.Number);\n second = toInt(sTok.value, 'second', this.i);\n\n // ISO 8601 allows both . and , as decimal separators for fractional seconds\n if (this.tryEat(TokType.Dot) || this.tryEat(TokType.Comma)) {\n const fracTok = this.eat(TokType.Number);\n fraction = fracTok.value; // keep raw digits\n }\n }\n\n return { kind: 'Time', hour, minute, second, fraction };\n }\n\n /**\n * Parse timezone offset: Z | +HH:MM | -HH:MM\n *\n * Important semantic distinction per RFC 3339 and ISO 8601:\n *\n * - Z (Zulu time):\n * Explicitly indicates UTC. Used when the time is known to be in UTC.\n * Has no sign ambiguity - it's always UTC, never local time.\n *\n * - +00:00 (zero positive offset):\n * Indicates local time at the prime meridian (UTC+0 timezone).\n * Semantically different from Z - this is a local time that happens to match UTC.\n *\n * - -00:00 (zero negative offset):\n * Per RFC 3339 section 4.3: indicates local time with unknown UTC offset.\n * Used when the time is known to be local but the offset is not known.\n * This is semantically very different from both Z and +00:00.\n * https://www.rfc-editor.org/rfc/rfc3339.html#section-4.3\n *\n * We preserve this distinction by treating Z as UtcOffset (no sign, no components)\n * while +00:00 and -00:00 are NumericOffset (with sign and parsed components).\n */\n private parseOffsetIfPresent(): OffsetAst | undefined {\n if (this.tryEat(TokType.Z)) {\n return { kind: 'UtcOffset' };\n }\n\n // combined numeric offset token if you used combineTimezoneOffsets()\n if (this.at(CombinedTokType.TZOffset)) {\n const t = this.eat(CombinedTokType.TZOffset);\n return parseOffset(t.value, this.i);\n }\n\n return undefined;\n }\n\n // -------- Bracket group parsing --------\n // Consumes: [ ... ]\n // Returns:\n // - raw inner text (reconstructed)\n // - critical flag (true if starts with !)\n // - pairs if it looks like key=value (or flags)\n // - isLikelyTzId for things like [Asia/Singapore]\n private parseBracketGroup(): {\n raw: string;\n critical: boolean;\n pairs: Record<string, string | true>;\n isLikelyTzId: boolean;\n } {\n this.eat(TokType.LBracket);\n\n const parts: string[] = [];\n const pairs: Record<string, string | true> = {};\n\n // Check for critical flag (IXDTF: [!u-ca=gregory])\n const critical = this.tryEat(TokType.Exclamation) != null;\n if (critical) {\n parts.push('!');\n }\n\n // Gather tokens until RBracket\n while (!this.at(TokType.RBracket)) {\n if (this.eof()) {\n throw new ParseError('Unterminated bracket group', this.i);\n }\n\n const t = this.peek();\n this.i++;\n\n parts.push(String(t.value));\n }\n\n this.eat(TokType.RBracket);\n\n const raw = parts.join('');\n\n // Best-effort parse into key/value pairs:\n // Support \"key=value\" and \"flag\" and \"k=v,k2=v2\"\n // Strip leading ! if present for parsing\n const contentToParse = critical ? raw.slice(1) : raw;\n const segments = contentToParse\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n for (const seg of segments) {\n const eq = seg.indexOf('=');\n if (eq === -1) {\n pairs[seg] = true;\n } else {\n const k = seg.slice(0, eq).trim();\n const v = seg.slice(eq + 1).trim();\n if (k) {\n pairs[k] = v || true;\n }\n }\n }\n\n // Heuristic: likely TZ ID if no '=' present and contains '/' (e.g. Asia/Singapore) or starts with Etc/\n // We now preserve critical flag even for timezones, so don't exclude them\n const isLikelyTzId =\n contentToParse.indexOf('=') === -1 &&\n (contentToParse.includes('/') || contentToParse.startsWith('Etc/'));\n\n // Note: If you want STRICTLY separate tz-id brackets vs extension brackets, do it here.\n\n return { raw, critical, pairs, isLikelyTzId };\n }\n\n // -------- Duration parsing --------\n // Grammar (subset):\n // P (Y M W D)* (T (H M S)*)?\n // Examples:\n // P1Y2M\n // P3W\n // P10DT2H30M\n // PT1.5S\n private parseDuration(): DurationAst {\n // Collect raw string as we parse\n const rawParts: string[] = [];\n const annotations: AnnotationAst[] = [];\n\n const pTok = this.eat(TokType.Ident);\n if (String(pTok.value) !== 'P') {\n throw new ParseError(\"Duration must start with 'P'\", this.i);\n }\n rawParts.push('P');\n\n let inTime = false;\n\n const dur: Omit<DurationAst, 'kind' | 'raw' | 'annotations'> = {};\n\n // Parse designators until we hit bracket annotations, slash, or EOF\n while (!this.eof() && !this.at(TokType.Slash) && !this.at(TokType.LBracket)) {\n // Time marker T\n if (this.tryEat(TokType.T)) {\n rawParts.push('T');\n inTime = true;\n continue;\n }\n\n // Expect a number (possibly with fraction for seconds)\n const numTok = this.tryEat(TokType.Number);\n if (!numTok) {\n break;\n } // be permissive; let parser user decide if this is error-worthy\n rawParts.push(numTok.value);\n\n let fraction: string | undefined;\n // ISO 8601 allows both . and , as decimal separators\n const dotOrComma = this.tryEat(TokType.Dot) || this.tryEat(TokType.Comma);\n if (dotOrComma) {\n rawParts.push(dotOrComma.value); // Preserve the actual separator (. or ,)\n const fracTok = this.eat(TokType.Number);\n rawParts.push(fracTok.value);\n fraction = fracTok.value;\n }\n\n // Unit is IDENT (Y,M,W,D,H,M,S). Note M is months if !inTime else minutes.\n const unitTok = this.eat(TokType.Ident);\n const unit = String(unitTok.value);\n rawParts.push(unit);\n\n const n = toInt(numTok.value, 'duration number', this.i);\n\n if (!inTime) {\n if (unit === 'Y') {\n dur.years = (dur.years ?? 0) + n;\n } else if (unit === 'M') {\n dur.months = (dur.months ?? 0) + n;\n } else if (unit === 'W') {\n dur.weeks = (dur.weeks ?? 0) + n;\n } else if (unit === 'D') {\n dur.days = (dur.days ?? 0) + n;\n } else {\n throw new ParseError(`Invalid duration unit '${unit}' in date part`, this.i);\n }\n } else {\n if (unit === 'H') {\n dur.hours = (dur.hours ?? 0) + n;\n } else if (unit === 'M') {\n dur.minutes = (dur.minutes ?? 0) + n;\n } else if (unit === 'S') {\n dur.seconds = (dur.seconds ?? 0) + n;\n if (fraction !== undefined && fraction.length > 0) {\n dur.secondsFraction = fraction;\n }\n } else {\n throw new ParseError(`Invalid duration unit '${unit}' in time part`, this.i);\n }\n }\n }\n\n // bracket annotations after duration\n while (this.at(TokType.LBracket)) {\n const { raw, critical, pairs } = this.parseBracketGroup();\n annotations.push({ kind: 'Annotation', raw, critical, pairs });\n }\n\n return { kind: 'Duration', ...dur, raw: rawParts.join(''), annotations };\n }\n}\n\n// ---------- Public API ----------\nexport function parseTemporal(src: string): TemporalAst {\n const raw = lexTemporal(src);\n const toks = combineTimezoneOffsets(raw);\n const p = new Parser(toks);\n return p.parseTemporal();\n}\n", "// stringify.ts\n// Convert AST back to temporal string representation\n\nimport type {\n AnnotationAst,\n DateAst,\n DateTimeAst,\n DurationAst,\n OffsetAst,\n RangeAst,\n TemporalAst,\n TimeAst,\n TimeZoneAst,\n} from './parser-types.js';\n\n/**\n * Convert a temporal AST back to its string representation.\n *\n * @param ast - The AST to stringify\n * @returns ISO 8601 / IXDTF formatted string\n *\n * @example\n * ```typescript\n * const ast = parseTemporal('2025-01-12T10:00:00+08:00');\n * const str = stringifyTemporal(ast);\n * // '2025-01-12T10:00:00+08:00'\n * ```\n */\nexport function stringifyTemporal(ast: TemporalAst): string {\n if (ast.kind === 'Range') {\n return stringifyRange(ast);\n }\n if (ast.kind === 'Duration') {\n return stringifyDuration(ast);\n }\n return stringifyDateTime(ast);\n}\n\n/**\n * Stringify a date AST to ISO 8601 format.\n *\n * @param date - The date AST\n * @returns Date string (YYYY, YYYY-MM, or YYYY-MM-DD)\n */\nexport function stringifyDate(date: DateAst): string {\n // Handle negative years (BC dates) - ISO 8601 uses negative years\n // Year 0 = 1 BC, Year -1 = 2 BC, etc.\n let yearStr: string;\n if (date.year < 0) {\n // For negative years, pad the absolute value and prepend the minus sign\n yearStr = '-' + Math.abs(date.year).toString().padStart(4, '0');\n } else {\n yearStr = date.year.toString().padStart(4, '0');\n }\n\n const parts: string[] = [yearStr];\n\n if (date.month != null) {\n parts.push(date.month.toString().padStart(2, '0'));\n\n if (date.day != null) {\n parts.push(date.day.toString().padStart(2, '0'));\n }\n }\n\n return parts.join('-');\n}\n\n/**\n * Stringify a time AST to ISO 8601 format.\n *\n * @param time - The time AST\n * @returns Time string (HH:MM, HH:MM:SS, or HH:MM:SS.fff)\n */\nexport function stringifyTime(time: TimeAst): string {\n const parts: string[] = [\n time.hour.toString().padStart(2, '0'),\n time.minute.toString().padStart(2, '0'),\n ];\n\n if (time.second != null) {\n let secondStr = time.second.toString().padStart(2, '0');\n if (time.fraction != null) {\n secondStr += `.${time.fraction}`;\n }\n parts.push(secondStr);\n }\n\n return parts.join(':');\n}\n\n/**\n * Stringify a timezone offset AST to canonical format.\n *\n * @param offset - The offset AST\n * @returns Offset string in canonical format (Z or \u00B1HH:MM)\n */\nexport function stringifyOffset(offset: OffsetAst): string {\n if (offset.kind === 'UtcOffset') {\n return 'Z';\n }\n // Return canonical format: +HH:MM or -HH:MM\n const hours = offset.hours.toString().padStart(2, '0');\n const minutes = offset.minutes.toString().padStart(2, '0');\n return `${offset.sign}${hours}:${minutes}`;\n}\n\n/**\n * Stringify a timezone AST.\n *\n * @param timeZone - The timezone AST\n * @returns Timezone string [Asia/Singapore] or [!Asia/Singapore]\n */\nexport function stringifyTimeZone(timeZone: TimeZoneAst): string {\n const id = timeZone.critical ? `!${timeZone.id}` : timeZone.id;\n return `[${id}]`;\n}\n\n/**\n * Stringify an annotation AST.\n *\n * @param annotation - The annotation AST\n * @returns Annotation string [u-ca=gregory] or [!u-ca=gregory]\n */\nexport function stringifyAnnotation(annotation: AnnotationAst): string {\n return `[${annotation.raw}]`;\n}\n\n/**\n * Stringify a datetime AST to ISO 8601 / IXDTF format.\n *\n * @param dateTime - The datetime AST\n * @returns DateTime string with optional time, offset, timezone, and annotations\n */\nexport function stringifyDateTime(dateTime: DateTimeAst): string {\n let result = stringifyDate(dateTime.date);\n\n if (dateTime.time) {\n result += `T${stringifyTime(dateTime.time)}`;\n }\n\n if (dateTime.offset) {\n result += stringifyOffset(dateTime.offset);\n }\n\n if (dateTime.timeZone) {\n result += stringifyTimeZone(dateTime.timeZone);\n }\n\n for (const annotation of dateTime.annotations) {\n result += stringifyAnnotation(annotation);\n }\n\n return result;\n}\n\n/**\n * Stringify a duration AST to ISO 8601 format.\n *\n * @param duration - The duration AST\n * @returns Duration string (P1Y2M3DT4H5M6S)\n */\nexport function stringifyDuration(duration: DurationAst): string {\n // Always reconstruct from components to ensure normalization\n let result = 'P';\n\n // Date part - include component if defined (even if zero)\n if (duration.years != null) {\n result += `${duration.years}Y`;\n }\n if (duration.months != null) {\n result += `${duration.months}M`;\n }\n if (duration.weeks != null) {\n result += `${duration.weeks}W`;\n }\n if (duration.days != null) {\n result += `${duration.days}D`;\n }\n\n // Time part - add T separator if any time component is defined\n const hasTimePart =\n duration.hours != null || duration.minutes != null || duration.seconds != null;\n if (hasTimePart) {\n result += 'T';\n if (duration.hours != null) {\n result += `${duration.hours}H`;\n }\n if (duration.minutes != null) {\n result += `${duration.minutes}M`;\n }\n if (duration.seconds != null) {\n result += `${duration.seconds}`;\n if (duration.secondsFraction != null && duration.secondsFraction.length > 0) {\n result += `.${duration.secondsFraction}`;\n }\n result += 'S';\n }\n }\n\n // Annotations\n for (const annotation of duration.annotations) {\n result += stringifyAnnotation(annotation);\n }\n\n return result;\n}\n\n/**\n * Stringify a range AST to ISO 8601 format.\n *\n * @param range - The range AST\n * @returns Range string (start/end, /end, or start/)\n */\nexport function stringifyRange(range: RangeAst): string {\n const start = range.start\n ? range.start.kind === 'Duration'\n ? stringifyDuration(range.start)\n : stringifyDateTime(range.start)\n : '';\n\n const end = range.end\n ? range.end.kind === 'Duration'\n ? stringifyDuration(range.end)\n : stringifyDateTime(range.end)\n : '';\n\n return `${start}/${end}`;\n}\n"],
"mappings": "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",
"names": ["TokType", "CombinedTokType"]
}

@@ -440,4 +440,8 @@ // src/lexer-types.ts

parseDate() {
const isNegative = this.tryEat("Dash" /* Dash */);
const yTok = this.eat("Number" /* Number */);
const year = toInt(yTok.value, "year", this.i);
let year = toInt(yTok.value, "year", this.i);
if (isNegative) {
year = -year;
}
if (!this.tryEat("Dash" /* Dash */)) {

@@ -466,3 +470,3 @@ return { kind: "Date", year };

second = toInt(sTok.value, "second", this.i);
if (this.tryEat("Dot" /* Dot */)) {
if (this.tryEat("Dot" /* Dot */) || this.tryEat("Comma" /* Comma */)) {
const fracTok = this.eat("Number" /* Number */);

@@ -578,4 +582,5 @@ fraction = fracTok.value;

let fraction;
if (this.tryEat("Dot" /* Dot */)) {
rawParts.push(".");
const dotOrComma = this.tryEat("Dot" /* Dot */) || this.tryEat("Comma" /* Comma */);
if (dotOrComma) {
rawParts.push(dotOrComma.value);
const fracTok = this.eat("Number" /* Number */);

@@ -629,2 +634,115 @@ rawParts.push(fracTok.value);

}
// src/stringify.ts
function stringifyTemporal(ast) {
if (ast.kind === "Range") {
return stringifyRange(ast);
}
if (ast.kind === "Duration") {
return stringifyDuration(ast);
}
return stringifyDateTime(ast);
}
function stringifyDate(date) {
let yearStr;
if (date.year < 0) {
yearStr = "-" + Math.abs(date.year).toString().padStart(4, "0");
} else {
yearStr = date.year.toString().padStart(4, "0");
}
const parts = [yearStr];
if (date.month != null) {
parts.push(date.month.toString().padStart(2, "0"));
if (date.day != null) {
parts.push(date.day.toString().padStart(2, "0"));
}
}
return parts.join("-");
}
function stringifyTime(time) {
const parts = [
time.hour.toString().padStart(2, "0"),
time.minute.toString().padStart(2, "0")
];
if (time.second != null) {
let secondStr = time.second.toString().padStart(2, "0");
if (time.fraction != null) {
secondStr += `.${time.fraction}`;
}
parts.push(secondStr);
}
return parts.join(":");
}
function stringifyOffset(offset) {
if (offset.kind === "UtcOffset") {
return "Z";
}
const hours = offset.hours.toString().padStart(2, "0");
const minutes = offset.minutes.toString().padStart(2, "0");
return `${offset.sign}${hours}:${minutes}`;
}
function stringifyTimeZone(timeZone) {
const id = timeZone.critical ? `!${timeZone.id}` : timeZone.id;
return `[${id}]`;
}
function stringifyAnnotation(annotation) {
return `[${annotation.raw}]`;
}
function stringifyDateTime(dateTime) {
let result = stringifyDate(dateTime.date);
if (dateTime.time) {
result += `T${stringifyTime(dateTime.time)}`;
}
if (dateTime.offset) {
result += stringifyOffset(dateTime.offset);
}
if (dateTime.timeZone) {
result += stringifyTimeZone(dateTime.timeZone);
}
for (const annotation of dateTime.annotations) {
result += stringifyAnnotation(annotation);
}
return result;
}
function stringifyDuration(duration) {
let result = "P";
if (duration.years != null) {
result += `${duration.years}Y`;
}
if (duration.months != null) {
result += `${duration.months}M`;
}
if (duration.weeks != null) {
result += `${duration.weeks}W`;
}
if (duration.days != null) {
result += `${duration.days}D`;
}
const hasTimePart = duration.hours != null || duration.minutes != null || duration.seconds != null;
if (hasTimePart) {
result += "T";
if (duration.hours != null) {
result += `${duration.hours}H`;
}
if (duration.minutes != null) {
result += `${duration.minutes}M`;
}
if (duration.seconds != null) {
result += `${duration.seconds}`;
if (duration.secondsFraction != null && duration.secondsFraction.length > 0) {
result += `.${duration.secondsFraction}`;
}
result += "S";
}
}
for (const annotation of duration.annotations) {
result += stringifyAnnotation(annotation);
}
return result;
}
function stringifyRange(range) {
const start = range.start ? range.start.kind === "Duration" ? stringifyDuration(range.start) : stringifyDateTime(range.start) : "";
const end = range.end ? range.end.kind === "Duration" ? stringifyDuration(range.end) : stringifyDateTime(range.end) : "";
return `${start}/${end}`;
}
export {

@@ -638,4 +756,13 @@ CombinedTokType,

parseOffset,
parseTemporal
parseTemporal,
stringifyAnnotation,
stringifyDate,
stringifyDateTime,
stringifyDuration,
stringifyOffset,
stringifyRange,
stringifyTemporal,
stringifyTime,
stringifyTimeZone
};
//# sourceMappingURL=index.mjs.map
{
"version": 3,
"sources": ["../../src/lexer-types.ts", "../../src/combineTimezoneOffsets.ts", "../../src/errors.ts", "../../src/helpers/isAlpha.ts", "../../src/helpers/isDigit.ts", "../../src/helpers/isBracketWordChar.ts", "../../src/lexer.ts", "../../src/helpers/toInt.ts", "../../src/parseOffset.ts", "../../src/parser.ts"],
"sourcesContent": ["// lexer-types.ts\n// Token types and interfaces for the lexer\n\nexport enum TokType {\n // Numbers: sequences of digits (0-9)\n // Examples: \"2025\", \"01\", \"12\", \"59\"\n Number = 'Number',\n\n // Ident (Identifier): sequences of alphabetic characters (A-Z, a-z)\n // This is the generic \"text\" token for letter-based designators.\n // Examples: \"P\" (duration), \"Y\" (year), \"M\" (month), \"gregory\" (calendar)\n // The lexer keeps it simple; the parser interprets the meaning.\n Ident = 'Ident',\n\n // Single-character punctuation tokens\n Dash = 'Dash', // -\n Colon = 'Colon', // :\n Dot = 'Dot', // .\n Plus = 'Plus', // +\n Slash = 'Slash', // /\n Comma = 'Comma', // ,\n Equals = 'Equals', // =\n Underscore = 'Underscore', // _\n Exclamation = 'Exclamation', // ! (critical flag in IXDTF)\n\n // Special letter tokens with dedicated meaning in ISO 8601\n T = 'T', // Date/time separator: 2025-01-01T10:00:00\n Z = 'Z', // UTC timezone marker: 2025-01-01T10:00:00Z\n\n // Bracket tokens for IXDTF annotations/extensions\n LBracket = 'LBracket', // [\n RBracket = 'RBracket', // ]\n\n // BracketText: complex text inside brackets that contains non-letter chars\n // Example: in [u-ca=gregory], \"u-ca\" is BracketText (has dash), \"gregory\" is Ident (letters only)\n // Example: in [Asia/Singapore], \"Asia/Singapore\" is BracketText (has slash)\n BracketText = 'BracketText',\n\n EOF = 'EOF',\n}\n\nexport type Token = {\n type: TokType;\n value: string;\n start: number; // inclusive\n end: number; // exclusive\n};\n\n// Combined token types for timezone offsets\nexport enum CombinedTokType {\n TZOffset = 'TZOffset', // +08:00, -0530, +09\n}\n\nexport type CombinedToken = {\n type: CombinedTokType;\n value: string;\n tokens: Token[];\n start: number;\n end: number;\n};\n\nexport type AnyToken = Token | CombinedToken;\n", "// combineTimezoneOffsets.ts\n// Combines numeric timezone offset tokens into single tokens for easier parsing\n\nimport { type AnyToken, CombinedTokType, type Token, TokType } from './lexer-types.js';\n\n/**\n * Combine numeric timezone offsets into single tokens for easier parsing.\n * This is an optional post-processing step for the lexer output.\n *\n * Combines patterns like:\n * - (+|-) Number Colon Number => +08:00, -05:30\n * - (+|-) Number (2 or 4 digits) => +09, -0530\n *\n * Only combines when context suggests a timezone offset (after time components),\n * NOT after:\n * - Z (mutually exclusive per ISO 8601)\n * - brackets (offset comes BEFORE brackets per RFC 9557/IXDTF)\n * - standalone dates (e.g., 2025-01 where - is a date separator)\n *\n * @param tokens - The raw token array from lexTemporal\n * @returns Array of tokens (either original Token or combined CombinedToken with TZOffset type where applicable)\n *\n * @example\n * ```typescript\n * const raw = lexTemporal('10:00:00+08:00');\n * const combined = combineTimezoneOffsets(raw);\n * // Result includes: { type: 'TZOffset', value: '+08:00' }\n * ```\n */\nexport function combineTimezoneOffsets(tokens: Token[]): AnyToken[] {\n const out: AnyToken[] = [];\n let i = 0;\n\n const peek = (k: number) => tokens[i + k];\n\n // Helper to check if previous tokens suggest this could be a timezone offset\n // Timezone offsets come after time components (HH:MM:SS)\n // NOT after just a date like 2025-01\n // NOT after Z (Z and numeric offsets are mutually exclusive per ISO 8601)\n // NOT after brackets (per RFC 9557/IXDTF: offset comes BEFORE brackets)\n const couldBeTzOffset = () => {\n if (out.length < 1) {\n return false;\n }\n const prev: AnyToken | undefined = out[out.length - 1];\n if (prev == null) {\n return false;\n }\n\n // After Z - NOT valid (Z and numeric offsets are mutually exclusive)\n // Per ISO 8601: use either Z OR +HH:MM, never both\n if (prev.type === TokType.Z) {\n return false;\n }\n\n // After bracket - NOT valid (offset must come BEFORE brackets per RFC 9557)\n // Valid: Time+08:00[Asia/Tokyo]\n // Invalid: [Asia/Tokyo]+08:00\n if (prev.type === TokType.RBracket) {\n return false;\n }\n\n // After a number, check context\n if (prev.type === TokType.Number) {\n if (out.length < 2) {\n return false;\n }\n const prevPrev = out[out.length - 2];\n\n // After a number with colon before it (time component)\n // e.g., ...10:00:00+08:00 - the number before + has a colon before it\n if (prevPrev?.type === TokType.Colon) {\n return true;\n }\n\n // After a number with dot before it (milliseconds)\n // e.g., ...10:00:00.999+08:00 - the number before + has a dot before it\n if (prevPrev?.type === TokType.Dot) {\n return true;\n }\n }\n\n return false;\n };\n\n while (i < tokens.length) {\n const t = tokens[i]!;\n const isSign = t.type === TokType.Plus || t.type === TokType.Dash;\n\n // Only try to combine if context suggests timezone offset\n if (isSign && couldBeTzOffset()) {\n // (+|-) Number Colon Number => +08:00\n if (\n peek(1)?.type === TokType.Number &&\n peek(2)?.type === TokType.Colon &&\n peek(3)?.type === TokType.Number\n ) {\n const originalTokens = [t, peek(1)!, peek(2)!, peek(3)!];\n const start = t.start;\n const end = peek(3)!.end;\n const value = `${t.value}${peek(1)!.value}:${peek(3)!.value}`;\n out.push({ type: CombinedTokType.TZOffset, value, tokens: originalTokens, start, end });\n i += 4;\n continue;\n }\n\n // (+|-) Number where Number is 2 or 4 digits => +09 or -0530\n if (peek(1)?.type === TokType.Number) {\n const num = peek(1)!.value;\n if (num.length === 2 || num.length === 4) {\n const originalTokens = [t, peek(1)!];\n const start = t.start;\n const end = peek(1)!.end;\n const value = `${t.value}${num}`;\n out.push({ type: CombinedTokType.TZOffset, value, tokens: originalTokens, start, end });\n i += 2;\n continue;\n }\n }\n }\n\n out.push(t);\n i++;\n }\n\n return out;\n}\n", "// errors.ts\n// Error classes for lexer and parser\n\nexport class LexError extends Error {\n public readonly position: number;\n constructor(message: string, position: number) {\n super(`${message} at position ${position}`);\n this.name = 'LexError';\n this.position = position;\n }\n}\n\nexport class ParseError extends Error {\n public readonly position: number;\n constructor(message: string, position: number) {\n super(`${message} at token index ${position}`);\n this.name = 'ParseError';\n this.position = position;\n }\n}\n", "/**\n * Check if character is alphabetic (A-Z or a-z)\n * This defines what can be part of an IDENT token in default mode\n * @param c - the character to check\n * @returns true if character is alphabetic, false otherwise\n */\nexport function isAlpha(c: string): boolean {\n return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');\n}\n", "/**\n * Check if character is a digit (0-9)\n * @param c - the character to check\n * @returns true if character is a digit, false otherwise\n */\nexport function isDigit(c: string) {\n return c >= '0' && c <= '9';\n}\n", "import { isAlpha } from './isAlpha.js';\nimport { isDigit } from './isDigit.js';\n\n/**\n * Check if character is valid inside bracket annotations\n * In default mode, IDENT is letters only (keeps date/time parsing clean).\n * In bracket mode, we allow broader \"words\" like:\n * - u-ca (has dash)\n * - Asia/Singapore (has slash)\n * - Etc/GMT+8 (has plus)\n * - iso8601 (has digits)\n * @param c - the character to check\n * @returns true if character is valid in bracket context, false otherwise\n */\nexport function isBracketWordChar(c: string): boolean {\n return (\n isAlpha(c) || isDigit(c) || c === '-' || c === '/' || c === '+' || c === '.' // allow dots in some TZ-ish values\n );\n}\n", "// lexer.ts\n// Temporal (IXDTF / ISO-8601-ish) lexer with support for *extensions/annotations* like calendar.\n//\n// Supports:\n// - Basic date/time tokens: numbers, identifiers, T, Z, punctuation\n// - Ranges: '/'\n// - Durations: 'P' (as IDENT; parser enforces rules)\n// - Time zone forms:\n// - 'Z'\n// - numeric offsets: +08:00 / -0530 / +09 (optionally combined via helper)\n// - bracketed IANA TZ: [Asia/Singapore]\n// - IXDTF-style annotations/extensions in brackets, e.g.:\n// - [u-ca=gregory] (calendar)\n// - [u-tz=Asia/Singapore] (timeZone)\n// - multiple bracket groups: 2025-01-01T00:00Z[u-ca=iso8601][u-tz=UTC]\n//\n// The lexer is permissive; your parser should validate semantics.\n\nimport { LexError } from './errors.js';\nimport { isAlpha } from './helpers/isAlpha.js';\nimport { isBracketWordChar } from './helpers/isBracketWordChar.js';\nimport { isDigit } from './helpers/isDigit.js';\nimport type { Token } from './lexer-types.js';\nimport { TokType } from './lexer-types.js';\n\nexport function lexTemporal(src: string): Token[] {\n const tokens: Token[] = [];\n let i = 0;\n\n const emit = (type: TokType, start: number, end: number, value?: string) => {\n tokens.push({ type, value: value ?? src.slice(start, end), start, end });\n };\n\n // Lex a number: consume consecutive digits\n // Examples: \"2025\", \"01\", \"59\"\n const lexNumber = () => {\n const start = i;\n i++;\n while (i < src.length && isDigit(src[i]!)) {\n i++;\n }\n emit(TokType.Number, start, i);\n };\n\n // Lex an identifier: consume consecutive alphabetic characters\n // This is where IDENT tokens are created!\n //\n // Examples of what becomes IDENT:\n // - Duration designators: P, Y, M, W, D, H, S\n // - Calendar names: gregory, hebrew, iso8601\n // - Any letter sequence: P, YMD, UTC, America\n //\n // Special cases:\n // - \"T\" gets its own token type (datetime separator)\n // - \"Z\" gets its own token type (UTC marker)\n // - Everything else becomes Ident\n //\n // IMPORTANT: We only consume a single letter at a time to allow T and Z\n // to be recognized individually (e.g., \"DT\" should be \"D\" then \"T\", not \"DT\")\n const lexIdent = () => {\n const start = i;\n const ch = src[i]!;\n i++;\n\n // Special handling for T and Z - emit them as special tokens\n if (ch === 'T') {\n emit(TokType.T, start, i, 'T');\n return;\n }\n if (ch === 'Z') {\n emit(TokType.Z, start, i, 'Z');\n return;\n }\n\n // For other letters, consume consecutive letters that are NOT T or Z\n // This allows multi-letter identifiers like \"gregory\" but keeps T and Z separate\n while (i < src.length && isAlpha(src[i]!) && src[i] !== 'T' && src[i] !== 'Z') {\n i++;\n }\n\n emit(TokType.Ident, start, i); // Generic identifier\n };\n\n const lexBracketContent = () => {\n // We are positioned after '['. Emit content tokens until ']'.\n while (i < src.length) {\n const ch = src[i]!;\n\n if (ch === ']') {\n return;\n }\n\n // Skip whitespace inside brackets (rare but harmless)\n if (/\\s/.test(ch)) {\n i++;\n continue;\n }\n\n // Single-char tokens inside brackets\n if (ch === '=') {\n emit(TokType.Equals, i, i + 1);\n i++;\n continue;\n }\n if (ch === '_') {\n emit(TokType.Underscore, i, i + 1);\n i++;\n continue;\n }\n if (ch === ':') {\n emit(TokType.Colon, i, i + 1);\n i++;\n continue;\n }\n if (ch === '-') {\n emit(TokType.Dash, i, i + 1);\n i++;\n continue;\n }\n if (ch === '+') {\n emit(TokType.Plus, i, i + 1);\n i++;\n continue;\n }\n if (ch === '/') {\n emit(TokType.Slash, i, i + 1);\n i++;\n continue;\n }\n if (ch === '.') {\n emit(TokType.Dot, i, i + 1);\n i++;\n continue;\n }\n if (ch === ',') {\n emit(TokType.Comma, i, i + 1);\n i++;\n continue;\n }\n if (ch === '!') {\n emit(TokType.Exclamation, i, i + 1);\n i++;\n continue;\n }\n\n // Words inside brackets (u-ca, gregory, Asia/Singapore, iso8601, Etc/GMT+8, etc.)\n if (isBracketWordChar(ch)) {\n const start = i;\n i++;\n while (i < src.length && isBracketWordChar(src[i]!)) {\n i++;\n }\n const text = src.slice(start, i);\n\n // Decision: Ident vs BracketText\n // - If purely letters (A-Z, a-z): emit as Ident\n // Examples: \"gregory\", \"hebrew\", \"u\", \"ca\"\n // - If contains other chars (digits, -, /, +, .): emit as BracketText\n // Examples: \"u-ca\", \"Asia/Singapore\", \"iso8601\", \"Etc/GMT+8\"\n if (/^[A-Za-z]+$/.test(text)) {\n emit(TokType.Ident, start, i, text);\n } else {\n emit(TokType.BracketText, start, i, text);\n }\n\n continue;\n }\n\n throw new LexError(`Unexpected character ${JSON.stringify(ch)} inside brackets`, i);\n }\n\n throw new LexError(\"Unterminated bracket annotation, expected ']'\", src.length);\n };\n\n while (i < src.length) {\n const ch = src[i]!;\n\n // Skip whitespace\n if (/\\s/.test(ch)) {\n i++;\n continue;\n }\n\n // Bracketed extensions/annotations/timezone IDs\n if (ch === '[') {\n emit(TokType.LBracket, i, i + 1);\n i++;\n\n lexBracketContent();\n\n if (i >= src.length || src[i] !== ']') {\n throw new LexError(\"Unterminated bracket annotation, expected ']'\", i);\n }\n emit(TokType.RBracket, i, i + 1);\n i++;\n continue;\n }\n\n // Numbers: sequences of digits\n if (isDigit(ch)) {\n lexNumber();\n continue;\n }\n\n // Letters: this is where IDENT tokens are created!\n // Any alphabetic character triggers identifier lexing.\n // Examples: P (duration), Y (year), M (month), gregory, UTC\n if (isAlpha(ch)) {\n lexIdent();\n continue;\n }\n\n // Punctuation (default mode)\n switch (ch) {\n case '-':\n emit(TokType.Dash, i, i + 1);\n i++;\n continue;\n case ':':\n emit(TokType.Colon, i, i + 1);\n i++;\n continue;\n case '.':\n emit(TokType.Dot, i, i + 1);\n i++;\n continue;\n case '+':\n emit(TokType.Plus, i, i + 1);\n i++;\n continue;\n case '/':\n emit(TokType.Slash, i, i + 1);\n i++;\n continue;\n case ',':\n emit(TokType.Comma, i, i + 1);\n i++;\n continue;\n case '=':\n emit(TokType.Equals, i, i + 1);\n i++;\n continue;\n case '_':\n emit(TokType.Underscore, i, i + 1);\n i++;\n continue;\n default:\n throw new LexError(`Unexpected character ${JSON.stringify(ch)}`, i);\n }\n }\n\n emit(TokType.EOF, src.length, src.length, '');\n return tokens;\n}\n", "import { ParseError } from '../errors.js';\n\n/**\n * Convert a string to an integer, throwing a ParseError if invalid\n * @param s - the string to convert\n * @param label - a descriptive label for error messages (e.g., \"year\", \"month\")\n * @param position - the position in the token stream for error reporting\n * @returns the parsed integer value\n * @throws {ParseError} if the string is not a valid integer\n */\nexport function toInt(s: string, label: string, position: number): number {\n const n = Number(s);\n if (!Number.isFinite(n) || !Number.isInteger(n)) {\n throw new ParseError(`Invalid integer for ${label}: ${JSON.stringify(s)}`, position);\n }\n return n;\n}\n", "// parseOffset.ts\n// Parse timezone offset strings into structured components\n\nimport { ParseError } from './errors.js';\nimport { toInt } from './helpers/toInt.js';\nimport type { OffsetAst } from './parser-types.js';\n\n// Timezone offset validation constants\n// Per ISO 8601 and real-world usage:\n// - Westernmost: UTC-12:00 (Baker Island, Howland Island)\n// - Easternmost: UTC+14:00 (Line Islands, Kiritimati)\nconst MAX_OFFSET_HOURS = 14;\nconst MAX_MINUTES = 59;\n\n/**\n * Parse a timezone offset string into structured components.\n *\n * Supports three formats:\n * - Standard: +08:00, -05:30\n * - Compact: +0530, -0800\n * - Short: +09, -05\n *\n * Valid timezone offset ranges (per ISO 8601):\n * - Hours: 0-14 (UTC-12:00 to UTC+14:00)\n * - Minutes: 0-59\n *\n * Note: This function only parses numeric offsets (e.g., +08:00).\n * For UTC, use 'Z' (UtcOffset kind) which is semantically different from +00:00.\n * Per RFC 3339 section 4.3, -00:00 indicates \"local time with unknown offset\".\n *\n * @param offsetString - The offset string to parse (e.g., '+08:00', '-0530', '+09')\n * @param position - Position in token stream for error reporting (optional)\n * @returns Parsed offset with sign, hours, and minutes\n * @throws {ParseError} If the offset format is invalid or out of range\n *\n * @example\n * ```typescript\n * parseOffset('+08:00') // { kind: 'NumericOffset', sign: '+', hours: 8, minutes: 0, raw: '+08:00' }\n * parseOffset('-05:30') // { kind: 'NumericOffset', sign: '-', hours: 5, minutes: 30, raw: '-05:30' }\n * parseOffset('+0530') // { kind: 'NumericOffset', sign: '+', hours: 5, minutes: 30, raw: '+0530' }\n * parseOffset('+09') // { kind: 'NumericOffset', sign: '+', hours: 9, minutes: 0, raw: '+09' }\n * parseOffset('+14:00') // { kind: 'NumericOffset', sign: '+', hours: 14, minutes: 0, raw: '+14:00' }\n * ```\n */\nexport function parseOffset(offsetString: string, position = 0): OffsetAst {\n // Validate input is not empty\n if (offsetString.length === 0) {\n throw new ParseError('Offset string cannot be empty', position);\n }\n\n const raw = offsetString;\n\n // Validate first character is sign and assert type\n const sign = raw[0];\n if (sign !== '+' && sign !== '-') {\n throw new ParseError(`Offset must start with + or -, got ${JSON.stringify(sign)}`, position);\n }\n // Type assertion: TypeScript now knows sign is '+' | '-'\n const validSign: '+' | '-' = sign;\n\n const rest = raw.slice(1);\n\n // Validate rest is not empty\n if (rest.length === 0) {\n throw new ParseError(`Offset sign must be followed by digits`, position);\n }\n\n let hours: number;\n let minutes: number;\n\n if (rest.includes(':')) {\n // Format: +08:00 or -05:30\n const parts = rest.split(':');\n if (parts.length !== 2) {\n throw new ParseError(`Invalid offset format: ${raw} (expected HH:MM)`, position);\n }\n // After length check, we know parts[0] and parts[1] exist\n const [h, m] = parts;\n hours = toInt(h!, 'offset hours', position);\n minutes = toInt(m!, 'offset minutes', position);\n } else if (rest.length === 4) {\n // Format: +0530 or -0800\n hours = toInt(rest.slice(0, 2), 'offset hours', position);\n minutes = toInt(rest.slice(2, 4), 'offset minutes', position);\n } else if (rest.length === 2) {\n // Format: +08 or -05\n hours = toInt(rest, 'offset hours', position);\n minutes = 0;\n } else {\n throw new ParseError(\n `Invalid offset format: ${raw} (expected +HH:MM, +HHMM, or +HH)`,\n position,\n );\n }\n\n // Validate ranges\n if (hours < 0 || hours > MAX_OFFSET_HOURS) {\n throw new ParseError(`Offset hours must be 0-${MAX_OFFSET_HOURS}, got ${hours}`, position);\n }\n if (minutes < 0 || minutes > MAX_MINUTES) {\n throw new ParseError(`Offset minutes must be 0-${MAX_MINUTES}, got ${minutes}`, position);\n }\n\n return { kind: 'NumericOffset', sign: validSign, hours, minutes, raw };\n}\n", "// parser.ts\n// A practical recursive-descent parser that works with the lexer we wrote.\n// It builds an AST for a useful Temporal subset:\n// - date/time (with optional fractional seconds)\n// - timezone: Z | numeric offset (+08:00, -0530, +09) | bracket TZ id [Asia/Singapore]\n// - duration: P... with optional T part\n// - range: <expr> \"/\" <expr> where each side can be dateTime/date/duration, and either side may be empty (open range)\n// - bracket extensions like [u-ca=gregory], [u-tz=Asia/Singapore], etc. (stored as key/value pairs)\n\nimport { combineTimezoneOffsets } from './combineTimezoneOffsets.js';\nimport { ParseError } from './errors.js';\nimport { toInt } from './helpers/toInt.js';\nimport { lexTemporal } from './lexer.js';\nimport { type AnyToken, CombinedTokType, TokType } from './lexer-types.js';\nimport { parseOffset } from './parseOffset.js';\nimport type {\n AnnotationAst,\n DateAst,\n DateTimeAst,\n DurationAst,\n OffsetAst,\n TemporalAst,\n TimeAst,\n TimeZoneAst,\n ValueAst,\n} from './parser-types.js';\n\n// ---------- Parser ----------\n\nclass Parser {\n private i = 0;\n constructor(private toks: AnyToken[]) {}\n\n private peek(k = 0): AnyToken {\n return this.toks[Math.min(this.i + k, this.toks.length - 1)]!;\n }\n private at(type: TokType | CombinedTokType): boolean {\n return this.peek().type === type;\n }\n private eat(type: TokType | CombinedTokType): AnyToken {\n const t = this.peek();\n if (t.type !== type) {\n throw new ParseError(`Expected ${type} but got ${t.type}`, this.i);\n }\n this.i++;\n return t;\n }\n private tryEat(type: TokType | CombinedTokType): AnyToken | null {\n if (this.at(type)) {\n return this.eat(type);\n }\n return null;\n }\n private eof(): boolean {\n return this.at(TokType.EOF);\n }\n\n // Top-level: parse a range if we see '/', otherwise a single value.\n parseTemporal(): TemporalAst {\n // Open-start range: \"/...\"\n if (this.tryEat(TokType.Slash)) {\n const end = this.parseValueOrNull(); // allow empty end too\n this.eat(TokType.EOF);\n return { kind: 'Range', start: null, end };\n }\n\n const first = this.parseValueOrNull();\n // If first is null, only valid if it's \"/\" (handled above). So error:\n if (!first) {\n throw new ParseError('Expected a value', this.i);\n }\n\n if (this.tryEat(TokType.Slash)) {\n const second = this.parseValueOrNull(); // open-ended allowed\n this.eat(TokType.EOF);\n return { kind: 'Range', start: first, end: second };\n }\n\n this.eat(TokType.EOF);\n return first;\n }\n\n private parseValueOrNull(): ValueAst | null {\n // Empty side for open range:\n if (this.at(TokType.EOF) || this.at(TokType.Slash) || this.at(TokType.RBracket)) {\n return null;\n }\n\n // Duration starts with IDENT \"P\" (as produced by lexer)\n if (this.at(TokType.Ident) && String(this.peek().value) === 'P') {\n return this.parseDuration();\n }\n\n // Otherwise parse a date/datetime (common case)\n return this.parseDateTime();\n }\n\n // -------- DateTime parsing --------\n // Supports:\n // - YYYY\n // - YYYY-MM\n // - YYYY-MM-DD\n // - + time part with T: YYYY-MM-DDTHH:MM[:SS[.fff]]\n // - offset: Z | +08:00 | -0530\n // - timezone: [Asia/Singapore] (first bracketed IANA timezone)\n // - annotations: [u-ca=...][u-tz=...] (other bracketed content)\n private parseDateTime(): DateTimeAst {\n const date = this.parseDate();\n\n let time: DateTimeAst['time'] | undefined;\n\n // time separator is TokType.T (from lexer special-casing \"T\")\n if (this.tryEat(TokType.T)) {\n time = this.parseTime();\n }\n\n // Parse numeric offset (Z or +HH:MM)\n const offset = this.parseOffsetIfPresent();\n\n // Parse bracket groups: first IANA timezone becomes timeZone, rest are annotations\n const annotations: AnnotationAst[] = [];\n let timeZone: TimeZoneAst | undefined;\n\n while (this.at(TokType.LBracket)) {\n const { raw, critical, isLikelyTzId, pairs } = this.parseBracketGroup();\n\n // First timezone-like bracket becomes the timeZone field\n // Note: Even though IXDTF doesn't typically use critical flags for timezones,\n // we preserve it in case the input has it\n if (timeZone === undefined && isLikelyTzId) {\n // Strip leading ! from id (it's stored in the critical flag)\n const id = critical ? raw.slice(1) : raw;\n timeZone = { kind: 'IanaTimeZone', id, critical };\n } else {\n annotations.push({ kind: 'Annotation', raw, critical, pairs });\n }\n }\n\n return { kind: 'DateTime', date, time, offset, timeZone, annotations };\n }\n\n private parseDate(): DateAst {\n const yTok = this.eat(TokType.Number);\n const year = toInt(yTok.value, 'year', this.i);\n\n // Optional -MM\n if (!this.tryEat(TokType.Dash)) {\n return { kind: 'Date', year };\n }\n const mTok = this.eat(TokType.Number);\n const month = toInt(mTok.value, 'month', this.i);\n\n // Optional -DD\n if (!this.tryEat(TokType.Dash)) {\n return { kind: 'Date', year, month };\n }\n const dTok = this.eat(TokType.Number);\n const day = toInt(dTok.value, 'day', this.i);\n\n return { kind: 'Date', year, month, day };\n }\n\n private parseTime(): TimeAst {\n const hTok = this.eat(TokType.Number);\n const hour = toInt(hTok.value, 'hour', this.i);\n\n this.eat(TokType.Colon);\n const minTok = this.eat(TokType.Number);\n const minute = toInt(minTok.value, 'minute', this.i);\n\n let second: number | undefined;\n let fraction: string | undefined;\n\n if (this.tryEat(TokType.Colon)) {\n const sTok = this.eat(TokType.Number);\n second = toInt(sTok.value, 'second', this.i);\n\n if (this.tryEat(TokType.Dot)) {\n const fracTok = this.eat(TokType.Number);\n fraction = fracTok.value; // keep raw digits\n }\n }\n\n return { kind: 'Time', hour, minute, second, fraction };\n }\n\n /**\n * Parse timezone offset: Z | +HH:MM | -HH:MM\n *\n * Important semantic distinction per RFC 3339 and ISO 8601:\n *\n * - Z (Zulu time):\n * Explicitly indicates UTC. Used when the time is known to be in UTC.\n * Has no sign ambiguity - it's always UTC, never local time.\n *\n * - +00:00 (zero positive offset):\n * Indicates local time at the prime meridian (UTC+0 timezone).\n * Semantically different from Z - this is a local time that happens to match UTC.\n *\n * - -00:00 (zero negative offset):\n * Per RFC 3339 section 4.3: indicates local time with unknown UTC offset.\n * Used when the time is known to be local but the offset is not known.\n * This is semantically very different from both Z and +00:00.\n * https://www.rfc-editor.org/rfc/rfc3339.html#section-4.3\n *\n * We preserve this distinction by treating Z as UtcOffset (no sign, no components)\n * while +00:00 and -00:00 are NumericOffset (with sign and parsed components).\n */\n private parseOffsetIfPresent(): OffsetAst | undefined {\n if (this.tryEat(TokType.Z)) {\n return { kind: 'UtcOffset' };\n }\n\n // combined numeric offset token if you used combineTimezoneOffsets()\n if (this.at(CombinedTokType.TZOffset)) {\n const t = this.eat(CombinedTokType.TZOffset);\n return parseOffset(t.value, this.i);\n }\n\n return undefined;\n }\n\n // -------- Bracket group parsing --------\n // Consumes: [ ... ]\n // Returns:\n // - raw inner text (reconstructed)\n // - critical flag (true if starts with !)\n // - pairs if it looks like key=value (or flags)\n // - isLikelyTzId for things like [Asia/Singapore]\n private parseBracketGroup(): {\n raw: string;\n critical: boolean;\n pairs: Record<string, string | true>;\n isLikelyTzId: boolean;\n } {\n this.eat(TokType.LBracket);\n\n const parts: string[] = [];\n const pairs: Record<string, string | true> = {};\n\n // Check for critical flag (IXDTF: [!u-ca=gregory])\n const critical = this.tryEat(TokType.Exclamation) != null;\n if (critical) {\n parts.push('!');\n }\n\n // Gather tokens until RBracket\n while (!this.at(TokType.RBracket)) {\n if (this.eof()) {\n throw new ParseError('Unterminated bracket group', this.i);\n }\n\n const t = this.peek();\n this.i++;\n\n parts.push(String(t.value));\n }\n\n this.eat(TokType.RBracket);\n\n const raw = parts.join('');\n\n // Best-effort parse into key/value pairs:\n // Support \"key=value\" and \"flag\" and \"k=v,k2=v2\"\n // Strip leading ! if present for parsing\n const contentToParse = critical ? raw.slice(1) : raw;\n const segments = contentToParse\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n for (const seg of segments) {\n const eq = seg.indexOf('=');\n if (eq === -1) {\n pairs[seg] = true;\n } else {\n const k = seg.slice(0, eq).trim();\n const v = seg.slice(eq + 1).trim();\n if (k) {\n pairs[k] = v || true;\n }\n }\n }\n\n // Heuristic: likely TZ ID if no '=' present and contains '/' (e.g. Asia/Singapore) or starts with Etc/\n // We now preserve critical flag even for timezones, so don't exclude them\n const isLikelyTzId =\n contentToParse.indexOf('=') === -1 &&\n (contentToParse.includes('/') || contentToParse.startsWith('Etc/'));\n\n // Note: If you want STRICTLY separate tz-id brackets vs extension brackets, do it here.\n\n return { raw, critical, pairs, isLikelyTzId };\n }\n\n // -------- Duration parsing --------\n // Grammar (subset):\n // P (Y M W D)* (T (H M S)*)?\n // Examples:\n // P1Y2M\n // P3W\n // P10DT2H30M\n // PT1.5S\n private parseDuration(): DurationAst {\n // Collect raw string as we parse\n const rawParts: string[] = [];\n const annotations: AnnotationAst[] = [];\n\n const pTok = this.eat(TokType.Ident);\n if (String(pTok.value) !== 'P') {\n throw new ParseError(\"Duration must start with 'P'\", this.i);\n }\n rawParts.push('P');\n\n let inTime = false;\n\n const dur: Omit<DurationAst, 'kind' | 'raw' | 'annotations'> = {};\n\n // Parse designators until we hit bracket annotations, slash, or EOF\n while (!this.eof() && !this.at(TokType.Slash) && !this.at(TokType.LBracket)) {\n // Time marker T\n if (this.tryEat(TokType.T)) {\n rawParts.push('T');\n inTime = true;\n continue;\n }\n\n // Expect a number (possibly with fraction for seconds)\n const numTok = this.tryEat(TokType.Number);\n if (!numTok) {\n break;\n } // be permissive; let parser user decide if this is error-worthy\n rawParts.push(numTok.value);\n\n let fraction: string | undefined;\n if (this.tryEat(TokType.Dot)) {\n rawParts.push('.');\n const fracTok = this.eat(TokType.Number);\n rawParts.push(fracTok.value);\n fraction = fracTok.value;\n }\n\n // Unit is IDENT (Y,M,W,D,H,M,S). Note M is months if !inTime else minutes.\n const unitTok = this.eat(TokType.Ident);\n const unit = String(unitTok.value);\n rawParts.push(unit);\n\n const n = toInt(numTok.value, 'duration number', this.i);\n\n if (!inTime) {\n if (unit === 'Y') {\n dur.years = (dur.years ?? 0) + n;\n } else if (unit === 'M') {\n dur.months = (dur.months ?? 0) + n;\n } else if (unit === 'W') {\n dur.weeks = (dur.weeks ?? 0) + n;\n } else if (unit === 'D') {\n dur.days = (dur.days ?? 0) + n;\n } else {\n throw new ParseError(`Invalid duration unit '${unit}' in date part`, this.i);\n }\n } else {\n if (unit === 'H') {\n dur.hours = (dur.hours ?? 0) + n;\n } else if (unit === 'M') {\n dur.minutes = (dur.minutes ?? 0) + n;\n } else if (unit === 'S') {\n dur.seconds = (dur.seconds ?? 0) + n;\n if (fraction !== undefined && fraction.length > 0) {\n dur.secondsFraction = fraction;\n }\n } else {\n throw new ParseError(`Invalid duration unit '${unit}' in time part`, this.i);\n }\n }\n }\n\n // bracket annotations after duration\n while (this.at(TokType.LBracket)) {\n const { raw, critical, pairs } = this.parseBracketGroup();\n annotations.push({ kind: 'Annotation', raw, critical, pairs });\n }\n\n return { kind: 'Duration', ...dur, raw: rawParts.join(''), annotations };\n }\n}\n\n// ---------- Public API ----------\nexport function parseTemporal(src: string): TemporalAst {\n const raw = lexTemporal(src);\n const toks = combineTimezoneOffsets(raw);\n const p = new Parser(toks);\n return p.parseTemporal();\n}\n"],
"mappings": "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",
"sources": ["../../src/lexer-types.ts", "../../src/combineTimezoneOffsets.ts", "../../src/errors.ts", "../../src/helpers/isAlpha.ts", "../../src/helpers/isDigit.ts", "../../src/helpers/isBracketWordChar.ts", "../../src/lexer.ts", "../../src/helpers/toInt.ts", "../../src/parseOffset.ts", "../../src/parser.ts", "../../src/stringify.ts"],
"sourcesContent": ["// lexer-types.ts\n// Token types and interfaces for the lexer\n\nexport enum TokType {\n // Numbers: sequences of digits (0-9)\n // Examples: \"2025\", \"01\", \"12\", \"59\"\n Number = 'Number',\n\n // Ident (Identifier): sequences of alphabetic characters (A-Z, a-z)\n // This is the generic \"text\" token for letter-based designators.\n // Examples: \"P\" (duration), \"Y\" (year), \"M\" (month), \"gregory\" (calendar)\n // The lexer keeps it simple; the parser interprets the meaning.\n Ident = 'Ident',\n\n // Single-character punctuation tokens\n Dash = 'Dash', // -\n Colon = 'Colon', // :\n Dot = 'Dot', // .\n Plus = 'Plus', // +\n Slash = 'Slash', // /\n Comma = 'Comma', // ,\n Equals = 'Equals', // =\n Underscore = 'Underscore', // _\n Exclamation = 'Exclamation', // ! (critical flag in IXDTF)\n\n // Special letter tokens with dedicated meaning in ISO 8601\n T = 'T', // Date/time separator: 2025-01-01T10:00:00\n Z = 'Z', // UTC timezone marker: 2025-01-01T10:00:00Z\n\n // Bracket tokens for IXDTF annotations/extensions\n LBracket = 'LBracket', // [\n RBracket = 'RBracket', // ]\n\n // BracketText: complex text inside brackets that contains non-letter chars\n // Example: in [u-ca=gregory], \"u-ca\" is BracketText (has dash), \"gregory\" is Ident (letters only)\n // Example: in [Asia/Singapore], \"Asia/Singapore\" is BracketText (has slash)\n BracketText = 'BracketText',\n\n EOF = 'EOF',\n}\n\nexport type Token = {\n type: TokType;\n value: string;\n start: number; // inclusive\n end: number; // exclusive\n};\n\n// Combined token types for timezone offsets\nexport enum CombinedTokType {\n TZOffset = 'TZOffset', // +08:00, -0530, +09\n}\n\nexport type CombinedToken = {\n type: CombinedTokType;\n value: string;\n tokens: Token[];\n start: number;\n end: number;\n};\n\nexport type AnyToken = Token | CombinedToken;\n", "// combineTimezoneOffsets.ts\n// Combines numeric timezone offset tokens into single tokens for easier parsing\n\nimport { type AnyToken, CombinedTokType, type Token, TokType } from './lexer-types.js';\n\n/**\n * Combine numeric timezone offsets into single tokens for easier parsing.\n * This is an optional post-processing step for the lexer output.\n *\n * Combines patterns like:\n * - (+|-) Number Colon Number => +08:00, -05:30\n * - (+|-) Number (2 or 4 digits) => +09, -0530\n *\n * Only combines when context suggests a timezone offset (after time components),\n * NOT after:\n * - Z (mutually exclusive per ISO 8601)\n * - brackets (offset comes BEFORE brackets per RFC 9557/IXDTF)\n * - standalone dates (e.g., 2025-01 where - is a date separator)\n *\n * @param tokens - The raw token array from lexTemporal\n * @returns Array of tokens (either original Token or combined CombinedToken with TZOffset type where applicable)\n *\n * @example\n * ```typescript\n * const raw = lexTemporal('10:00:00+08:00');\n * const combined = combineTimezoneOffsets(raw);\n * // Result includes: { type: 'TZOffset', value: '+08:00' }\n * ```\n */\nexport function combineTimezoneOffsets(tokens: Token[]): AnyToken[] {\n const out: AnyToken[] = [];\n let i = 0;\n\n const peek = (k: number) => tokens[i + k];\n\n // Helper to check if previous tokens suggest this could be a timezone offset\n // Timezone offsets come after time components (HH:MM:SS)\n // NOT after just a date like 2025-01\n // NOT after Z (Z and numeric offsets are mutually exclusive per ISO 8601)\n // NOT after brackets (per RFC 9557/IXDTF: offset comes BEFORE brackets)\n const couldBeTzOffset = () => {\n if (out.length < 1) {\n return false;\n }\n const prev: AnyToken | undefined = out[out.length - 1];\n if (prev == null) {\n return false;\n }\n\n // After Z - NOT valid (Z and numeric offsets are mutually exclusive)\n // Per ISO 8601: use either Z OR +HH:MM, never both\n if (prev.type === TokType.Z) {\n return false;\n }\n\n // After bracket - NOT valid (offset must come BEFORE brackets per RFC 9557)\n // Valid: Time+08:00[Asia/Tokyo]\n // Invalid: [Asia/Tokyo]+08:00\n if (prev.type === TokType.RBracket) {\n return false;\n }\n\n // After a number, check context\n if (prev.type === TokType.Number) {\n if (out.length < 2) {\n return false;\n }\n const prevPrev = out[out.length - 2];\n\n // After a number with colon before it (time component)\n // e.g., ...10:00:00+08:00 - the number before + has a colon before it\n if (prevPrev?.type === TokType.Colon) {\n return true;\n }\n\n // After a number with dot before it (milliseconds)\n // e.g., ...10:00:00.999+08:00 - the number before + has a dot before it\n if (prevPrev?.type === TokType.Dot) {\n return true;\n }\n }\n\n return false;\n };\n\n while (i < tokens.length) {\n const t = tokens[i]!;\n const isSign = t.type === TokType.Plus || t.type === TokType.Dash;\n\n // Only try to combine if context suggests timezone offset\n if (isSign && couldBeTzOffset()) {\n // (+|-) Number Colon Number => +08:00\n if (\n peek(1)?.type === TokType.Number &&\n peek(2)?.type === TokType.Colon &&\n peek(3)?.type === TokType.Number\n ) {\n const originalTokens = [t, peek(1)!, peek(2)!, peek(3)!];\n const start = t.start;\n const end = peek(3)!.end;\n const value = `${t.value}${peek(1)!.value}:${peek(3)!.value}`;\n out.push({ type: CombinedTokType.TZOffset, value, tokens: originalTokens, start, end });\n i += 4;\n continue;\n }\n\n // (+|-) Number where Number is 2 or 4 digits => +09 or -0530\n if (peek(1)?.type === TokType.Number) {\n const num = peek(1)!.value;\n if (num.length === 2 || num.length === 4) {\n const originalTokens = [t, peek(1)!];\n const start = t.start;\n const end = peek(1)!.end;\n const value = `${t.value}${num}`;\n out.push({ type: CombinedTokType.TZOffset, value, tokens: originalTokens, start, end });\n i += 2;\n continue;\n }\n }\n }\n\n out.push(t);\n i++;\n }\n\n return out;\n}\n", "// errors.ts\n// Error classes for lexer and parser\n\nexport class LexError extends Error {\n public readonly position: number;\n constructor(message: string, position: number) {\n super(`${message} at position ${position}`);\n this.name = 'LexError';\n this.position = position;\n }\n}\n\nexport class ParseError extends Error {\n public readonly position: number;\n constructor(message: string, position: number) {\n super(`${message} at token index ${position}`);\n this.name = 'ParseError';\n this.position = position;\n }\n}\n", "/**\n * Check if character is alphabetic (A-Z or a-z)\n * This defines what can be part of an IDENT token in default mode\n * @param c - the character to check\n * @returns true if character is alphabetic, false otherwise\n */\nexport function isAlpha(c: string): boolean {\n return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');\n}\n", "/**\n * Check if character is a digit (0-9)\n * @param c - the character to check\n * @returns true if character is a digit, false otherwise\n */\nexport function isDigit(c: string) {\n return c >= '0' && c <= '9';\n}\n", "import { isAlpha } from './isAlpha.js';\nimport { isDigit } from './isDigit.js';\n\n/**\n * Check if character is valid inside bracket annotations\n * In default mode, IDENT is letters only (keeps date/time parsing clean).\n * In bracket mode, we allow broader \"words\" like:\n * - u-ca (has dash)\n * - Asia/Singapore (has slash)\n * - Etc/GMT+8 (has plus)\n * - iso8601 (has digits)\n * @param c - the character to check\n * @returns true if character is valid in bracket context, false otherwise\n */\nexport function isBracketWordChar(c: string): boolean {\n return (\n isAlpha(c) || isDigit(c) || c === '-' || c === '/' || c === '+' || c === '.' // allow dots in some TZ-ish values\n );\n}\n", "// lexer.ts\n// Temporal (IXDTF / ISO-8601-ish) lexer with support for *extensions/annotations* like calendar.\n//\n// Supports:\n// - Basic date/time tokens: numbers, identifiers, T, Z, punctuation\n// - Ranges: '/'\n// - Durations: 'P' (as IDENT; parser enforces rules)\n// - Time zone forms:\n// - 'Z'\n// - numeric offsets: +08:00 / -0530 / +09 (optionally combined via helper)\n// - bracketed IANA TZ: [Asia/Singapore]\n// - IXDTF-style annotations/extensions in brackets, e.g.:\n// - [u-ca=gregory] (calendar)\n// - [u-tz=Asia/Singapore] (timeZone)\n// - multiple bracket groups: 2025-01-01T00:00Z[u-ca=iso8601][u-tz=UTC]\n//\n// The lexer is permissive; your parser should validate semantics.\n\nimport { LexError } from './errors.js';\nimport { isAlpha } from './helpers/isAlpha.js';\nimport { isBracketWordChar } from './helpers/isBracketWordChar.js';\nimport { isDigit } from './helpers/isDigit.js';\nimport type { Token } from './lexer-types.js';\nimport { TokType } from './lexer-types.js';\n\nexport function lexTemporal(src: string): Token[] {\n const tokens: Token[] = [];\n let i = 0;\n\n const emit = (type: TokType, start: number, end: number, value?: string) => {\n tokens.push({ type, value: value ?? src.slice(start, end), start, end });\n };\n\n // Lex a number: consume consecutive digits\n // Examples: \"2025\", \"01\", \"59\"\n const lexNumber = () => {\n const start = i;\n i++;\n while (i < src.length && isDigit(src[i]!)) {\n i++;\n }\n emit(TokType.Number, start, i);\n };\n\n // Lex an identifier: consume consecutive alphabetic characters\n // This is where IDENT tokens are created!\n //\n // Examples of what becomes IDENT:\n // - Duration designators: P, Y, M, W, D, H, S\n // - Calendar names: gregory, hebrew, iso8601\n // - Any letter sequence: P, YMD, UTC, America\n //\n // Special cases:\n // - \"T\" gets its own token type (datetime separator)\n // - \"Z\" gets its own token type (UTC marker)\n // - Everything else becomes Ident\n //\n // IMPORTANT: We only consume a single letter at a time to allow T and Z\n // to be recognized individually (e.g., \"DT\" should be \"D\" then \"T\", not \"DT\")\n const lexIdent = () => {\n const start = i;\n const ch = src[i]!;\n i++;\n\n // Special handling for T and Z - emit them as special tokens\n if (ch === 'T') {\n emit(TokType.T, start, i, 'T');\n return;\n }\n if (ch === 'Z') {\n emit(TokType.Z, start, i, 'Z');\n return;\n }\n\n // For other letters, consume consecutive letters that are NOT T or Z\n // This allows multi-letter identifiers like \"gregory\" but keeps T and Z separate\n while (i < src.length && isAlpha(src[i]!) && src[i] !== 'T' && src[i] !== 'Z') {\n i++;\n }\n\n emit(TokType.Ident, start, i); // Generic identifier\n };\n\n const lexBracketContent = () => {\n // We are positioned after '['. Emit content tokens until ']'.\n while (i < src.length) {\n const ch = src[i]!;\n\n if (ch === ']') {\n return;\n }\n\n // Skip whitespace inside brackets (rare but harmless)\n if (/\\s/.test(ch)) {\n i++;\n continue;\n }\n\n // Single-char tokens inside brackets\n if (ch === '=') {\n emit(TokType.Equals, i, i + 1);\n i++;\n continue;\n }\n if (ch === '_') {\n emit(TokType.Underscore, i, i + 1);\n i++;\n continue;\n }\n if (ch === ':') {\n emit(TokType.Colon, i, i + 1);\n i++;\n continue;\n }\n if (ch === '-') {\n emit(TokType.Dash, i, i + 1);\n i++;\n continue;\n }\n if (ch === '+') {\n emit(TokType.Plus, i, i + 1);\n i++;\n continue;\n }\n if (ch === '/') {\n emit(TokType.Slash, i, i + 1);\n i++;\n continue;\n }\n if (ch === '.') {\n emit(TokType.Dot, i, i + 1);\n i++;\n continue;\n }\n if (ch === ',') {\n emit(TokType.Comma, i, i + 1);\n i++;\n continue;\n }\n if (ch === '!') {\n emit(TokType.Exclamation, i, i + 1);\n i++;\n continue;\n }\n\n // Words inside brackets (u-ca, gregory, Asia/Singapore, iso8601, Etc/GMT+8, etc.)\n if (isBracketWordChar(ch)) {\n const start = i;\n i++;\n while (i < src.length && isBracketWordChar(src[i]!)) {\n i++;\n }\n const text = src.slice(start, i);\n\n // Decision: Ident vs BracketText\n // - If purely letters (A-Z, a-z): emit as Ident\n // Examples: \"gregory\", \"hebrew\", \"u\", \"ca\"\n // - If contains other chars (digits, -, /, +, .): emit as BracketText\n // Examples: \"u-ca\", \"Asia/Singapore\", \"iso8601\", \"Etc/GMT+8\"\n if (/^[A-Za-z]+$/.test(text)) {\n emit(TokType.Ident, start, i, text);\n } else {\n emit(TokType.BracketText, start, i, text);\n }\n\n continue;\n }\n\n throw new LexError(`Unexpected character ${JSON.stringify(ch)} inside brackets`, i);\n }\n\n throw new LexError(\"Unterminated bracket annotation, expected ']'\", src.length);\n };\n\n while (i < src.length) {\n const ch = src[i]!;\n\n // Skip whitespace\n if (/\\s/.test(ch)) {\n i++;\n continue;\n }\n\n // Bracketed extensions/annotations/timezone IDs\n if (ch === '[') {\n emit(TokType.LBracket, i, i + 1);\n i++;\n\n lexBracketContent();\n\n if (i >= src.length || src[i] !== ']') {\n throw new LexError(\"Unterminated bracket annotation, expected ']'\", i);\n }\n emit(TokType.RBracket, i, i + 1);\n i++;\n continue;\n }\n\n // Numbers: sequences of digits\n if (isDigit(ch)) {\n lexNumber();\n continue;\n }\n\n // Letters: this is where IDENT tokens are created!\n // Any alphabetic character triggers identifier lexing.\n // Examples: P (duration), Y (year), M (month), gregory, UTC\n if (isAlpha(ch)) {\n lexIdent();\n continue;\n }\n\n // Punctuation (default mode)\n switch (ch) {\n case '-':\n emit(TokType.Dash, i, i + 1);\n i++;\n continue;\n case ':':\n emit(TokType.Colon, i, i + 1);\n i++;\n continue;\n case '.':\n emit(TokType.Dot, i, i + 1);\n i++;\n continue;\n case '+':\n emit(TokType.Plus, i, i + 1);\n i++;\n continue;\n case '/':\n emit(TokType.Slash, i, i + 1);\n i++;\n continue;\n case ',':\n emit(TokType.Comma, i, i + 1);\n i++;\n continue;\n case '=':\n emit(TokType.Equals, i, i + 1);\n i++;\n continue;\n case '_':\n emit(TokType.Underscore, i, i + 1);\n i++;\n continue;\n default:\n throw new LexError(`Unexpected character ${JSON.stringify(ch)}`, i);\n }\n }\n\n emit(TokType.EOF, src.length, src.length, '');\n return tokens;\n}\n", "import { ParseError } from '../errors.js';\n\n/**\n * Convert a string to an integer, throwing a ParseError if invalid\n * @param s - the string to convert\n * @param label - a descriptive label for error messages (e.g., \"year\", \"month\")\n * @param position - the position in the token stream for error reporting\n * @returns the parsed integer value\n * @throws {ParseError} if the string is not a valid integer\n */\nexport function toInt(s: string, label: string, position: number): number {\n const n = Number(s);\n if (!Number.isFinite(n) || !Number.isInteger(n)) {\n throw new ParseError(`Invalid integer for ${label}: ${JSON.stringify(s)}`, position);\n }\n return n;\n}\n", "// parseOffset.ts\n// Parse timezone offset strings into structured components\n\nimport { ParseError } from './errors.js';\nimport { toInt } from './helpers/toInt.js';\nimport type { OffsetAst } from './parser-types.js';\n\n// Timezone offset validation constants\n// Per ISO 8601 and real-world usage:\n// - Westernmost: UTC-12:00 (Baker Island, Howland Island)\n// - Easternmost: UTC+14:00 (Line Islands, Kiritimati)\nconst MAX_OFFSET_HOURS = 14;\nconst MAX_MINUTES = 59;\n\n/**\n * Parse a timezone offset string into structured components.\n *\n * Supports three formats:\n * - Standard: +08:00, -05:30\n * - Compact: +0530, -0800\n * - Short: +09, -05\n *\n * Valid timezone offset ranges (per ISO 8601):\n * - Hours: 0-14 (UTC-12:00 to UTC+14:00)\n * - Minutes: 0-59\n *\n * Note: This function only parses numeric offsets (e.g., +08:00).\n * For UTC, use 'Z' (UtcOffset kind) which is semantically different from +00:00.\n * Per RFC 3339 section 4.3, -00:00 indicates \"local time with unknown offset\".\n *\n * @param offsetString - The offset string to parse (e.g., '+08:00', '-0530', '+09')\n * @param position - Position in token stream for error reporting (optional)\n * @returns Parsed offset with sign, hours, and minutes\n * @throws {ParseError} If the offset format is invalid or out of range\n *\n * @example\n * ```typescript\n * parseOffset('+08:00') // { kind: 'NumericOffset', sign: '+', hours: 8, minutes: 0, raw: '+08:00' }\n * parseOffset('-05:30') // { kind: 'NumericOffset', sign: '-', hours: 5, minutes: 30, raw: '-05:30' }\n * parseOffset('+0530') // { kind: 'NumericOffset', sign: '+', hours: 5, minutes: 30, raw: '+0530' }\n * parseOffset('+09') // { kind: 'NumericOffset', sign: '+', hours: 9, minutes: 0, raw: '+09' }\n * parseOffset('+14:00') // { kind: 'NumericOffset', sign: '+', hours: 14, minutes: 0, raw: '+14:00' }\n * ```\n */\nexport function parseOffset(offsetString: string, position = 0): OffsetAst {\n // Validate input is not empty\n if (offsetString.length === 0) {\n throw new ParseError('Offset string cannot be empty', position);\n }\n\n const raw = offsetString;\n\n // Validate first character is sign and assert type\n const sign = raw[0];\n if (sign !== '+' && sign !== '-') {\n throw new ParseError(`Offset must start with + or -, got ${JSON.stringify(sign)}`, position);\n }\n // Type assertion: TypeScript now knows sign is '+' | '-'\n const validSign: '+' | '-' = sign;\n\n const rest = raw.slice(1);\n\n // Validate rest is not empty\n if (rest.length === 0) {\n throw new ParseError(`Offset sign must be followed by digits`, position);\n }\n\n let hours: number;\n let minutes: number;\n\n if (rest.includes(':')) {\n // Format: +08:00 or -05:30\n const parts = rest.split(':');\n if (parts.length !== 2) {\n throw new ParseError(`Invalid offset format: ${raw} (expected HH:MM)`, position);\n }\n // After length check, we know parts[0] and parts[1] exist\n const [h, m] = parts;\n hours = toInt(h!, 'offset hours', position);\n minutes = toInt(m!, 'offset minutes', position);\n } else if (rest.length === 4) {\n // Format: +0530 or -0800\n hours = toInt(rest.slice(0, 2), 'offset hours', position);\n minutes = toInt(rest.slice(2, 4), 'offset minutes', position);\n } else if (rest.length === 2) {\n // Format: +08 or -05\n hours = toInt(rest, 'offset hours', position);\n minutes = 0;\n } else {\n throw new ParseError(\n `Invalid offset format: ${raw} (expected +HH:MM, +HHMM, or +HH)`,\n position,\n );\n }\n\n // Validate ranges\n if (hours < 0 || hours > MAX_OFFSET_HOURS) {\n throw new ParseError(`Offset hours must be 0-${MAX_OFFSET_HOURS}, got ${hours}`, position);\n }\n if (minutes < 0 || minutes > MAX_MINUTES) {\n throw new ParseError(`Offset minutes must be 0-${MAX_MINUTES}, got ${minutes}`, position);\n }\n\n return { kind: 'NumericOffset', sign: validSign, hours, minutes, raw };\n}\n", "// parser.ts\n// A practical recursive-descent parser that works with the lexer we wrote.\n// It builds an AST for a useful Temporal subset:\n// - date/time (with optional fractional seconds)\n// - timezone: Z | numeric offset (+08:00, -0530, +09) | bracket TZ id [Asia/Singapore]\n// - duration: P... with optional T part\n// - range: <expr> \"/\" <expr> where each side can be dateTime/date/duration, and either side may be empty (open range)\n// - bracket extensions like [u-ca=gregory], [u-tz=Asia/Singapore], etc. (stored as key/value pairs)\n\nimport { combineTimezoneOffsets } from './combineTimezoneOffsets.js';\nimport { ParseError } from './errors.js';\nimport { toInt } from './helpers/toInt.js';\nimport { lexTemporal } from './lexer.js';\nimport { type AnyToken, CombinedTokType, TokType } from './lexer-types.js';\nimport { parseOffset } from './parseOffset.js';\nimport type {\n AnnotationAst,\n DateAst,\n DateTimeAst,\n DurationAst,\n OffsetAst,\n TemporalAst,\n TimeAst,\n TimeZoneAst,\n ValueAst,\n} from './parser-types.js';\n\n// ---------- Parser ----------\n\nclass Parser {\n private i = 0;\n constructor(private toks: AnyToken[]) {}\n\n private peek(k = 0): AnyToken {\n return this.toks[Math.min(this.i + k, this.toks.length - 1)]!;\n }\n private at(type: TokType | CombinedTokType): boolean {\n return this.peek().type === type;\n }\n private eat(type: TokType | CombinedTokType): AnyToken {\n const t = this.peek();\n if (t.type !== type) {\n throw new ParseError(`Expected ${type} but got ${t.type}`, this.i);\n }\n this.i++;\n return t;\n }\n private tryEat(type: TokType | CombinedTokType): AnyToken | null {\n if (this.at(type)) {\n return this.eat(type);\n }\n return null;\n }\n private eof(): boolean {\n return this.at(TokType.EOF);\n }\n\n // Top-level: parse a range if we see '/', otherwise a single value.\n parseTemporal(): TemporalAst {\n // Open-start range: \"/...\"\n if (this.tryEat(TokType.Slash)) {\n const end = this.parseValueOrNull(); // allow empty end too\n this.eat(TokType.EOF);\n return { kind: 'Range', start: null, end };\n }\n\n const first = this.parseValueOrNull();\n // If first is null, only valid if it's \"/\" (handled above). So error:\n if (!first) {\n throw new ParseError('Expected a value', this.i);\n }\n\n if (this.tryEat(TokType.Slash)) {\n const second = this.parseValueOrNull(); // open-ended allowed\n this.eat(TokType.EOF);\n return { kind: 'Range', start: first, end: second };\n }\n\n this.eat(TokType.EOF);\n return first;\n }\n\n private parseValueOrNull(): ValueAst | null {\n // Empty side for open range:\n if (this.at(TokType.EOF) || this.at(TokType.Slash) || this.at(TokType.RBracket)) {\n return null;\n }\n\n // Duration starts with IDENT \"P\" (as produced by lexer)\n if (this.at(TokType.Ident) && String(this.peek().value) === 'P') {\n return this.parseDuration();\n }\n\n // Otherwise parse a date/datetime (common case)\n return this.parseDateTime();\n }\n\n // -------- DateTime parsing --------\n // Supports:\n // - YYYY\n // - YYYY-MM\n // - YYYY-MM-DD\n // - + time part with T: YYYY-MM-DDTHH:MM[:SS[.fff]]\n // - offset: Z | +08:00 | -0530\n // - timezone: [Asia/Singapore] (first bracketed IANA timezone)\n // - annotations: [u-ca=...][u-tz=...] (other bracketed content)\n private parseDateTime(): DateTimeAst {\n const date = this.parseDate();\n\n let time: DateTimeAst['time'] | undefined;\n\n // time separator is TokType.T (from lexer special-casing \"T\")\n if (this.tryEat(TokType.T)) {\n time = this.parseTime();\n }\n\n // Parse numeric offset (Z or +HH:MM)\n const offset = this.parseOffsetIfPresent();\n\n // Parse bracket groups: first IANA timezone becomes timeZone, rest are annotations\n const annotations: AnnotationAst[] = [];\n let timeZone: TimeZoneAst | undefined;\n\n while (this.at(TokType.LBracket)) {\n const { raw, critical, isLikelyTzId, pairs } = this.parseBracketGroup();\n\n // First timezone-like bracket becomes the timeZone field\n // Note: Even though IXDTF doesn't typically use critical flags for timezones,\n // we preserve it in case the input has it\n if (timeZone === undefined && isLikelyTzId) {\n // Strip leading ! from id (it's stored in the critical flag)\n const id = critical ? raw.slice(1) : raw;\n timeZone = { kind: 'IanaTimeZone', id, critical };\n } else {\n annotations.push({ kind: 'Annotation', raw, critical, pairs });\n }\n }\n\n return { kind: 'DateTime', date, time, offset, timeZone, annotations };\n }\n\n private parseDate(): DateAst {\n // Check for optional leading dash (negative year / BC date)\n // ISO 8601: Year 0 = 1 BC, Year -1 = 2 BC, etc.\n const isNegative = this.tryEat(TokType.Dash);\n \n const yTok = this.eat(TokType.Number);\n let year = toInt(yTok.value, 'year', this.i);\n if (isNegative) {\n year = -year;\n }\n\n // Optional -MM\n if (!this.tryEat(TokType.Dash)) {\n return { kind: 'Date', year };\n }\n const mTok = this.eat(TokType.Number);\n const month = toInt(mTok.value, 'month', this.i);\n\n // Optional -DD\n if (!this.tryEat(TokType.Dash)) {\n return { kind: 'Date', year, month };\n }\n const dTok = this.eat(TokType.Number);\n const day = toInt(dTok.value, 'day', this.i);\n\n return { kind: 'Date', year, month, day };\n }\n\n private parseTime(): TimeAst {\n const hTok = this.eat(TokType.Number);\n const hour = toInt(hTok.value, 'hour', this.i);\n\n this.eat(TokType.Colon);\n const minTok = this.eat(TokType.Number);\n const minute = toInt(minTok.value, 'minute', this.i);\n\n let second: number | undefined;\n let fraction: string | undefined;\n\n if (this.tryEat(TokType.Colon)) {\n const sTok = this.eat(TokType.Number);\n second = toInt(sTok.value, 'second', this.i);\n\n // ISO 8601 allows both . and , as decimal separators for fractional seconds\n if (this.tryEat(TokType.Dot) || this.tryEat(TokType.Comma)) {\n const fracTok = this.eat(TokType.Number);\n fraction = fracTok.value; // keep raw digits\n }\n }\n\n return { kind: 'Time', hour, minute, second, fraction };\n }\n\n /**\n * Parse timezone offset: Z | +HH:MM | -HH:MM\n *\n * Important semantic distinction per RFC 3339 and ISO 8601:\n *\n * - Z (Zulu time):\n * Explicitly indicates UTC. Used when the time is known to be in UTC.\n * Has no sign ambiguity - it's always UTC, never local time.\n *\n * - +00:00 (zero positive offset):\n * Indicates local time at the prime meridian (UTC+0 timezone).\n * Semantically different from Z - this is a local time that happens to match UTC.\n *\n * - -00:00 (zero negative offset):\n * Per RFC 3339 section 4.3: indicates local time with unknown UTC offset.\n * Used when the time is known to be local but the offset is not known.\n * This is semantically very different from both Z and +00:00.\n * https://www.rfc-editor.org/rfc/rfc3339.html#section-4.3\n *\n * We preserve this distinction by treating Z as UtcOffset (no sign, no components)\n * while +00:00 and -00:00 are NumericOffset (with sign and parsed components).\n */\n private parseOffsetIfPresent(): OffsetAst | undefined {\n if (this.tryEat(TokType.Z)) {\n return { kind: 'UtcOffset' };\n }\n\n // combined numeric offset token if you used combineTimezoneOffsets()\n if (this.at(CombinedTokType.TZOffset)) {\n const t = this.eat(CombinedTokType.TZOffset);\n return parseOffset(t.value, this.i);\n }\n\n return undefined;\n }\n\n // -------- Bracket group parsing --------\n // Consumes: [ ... ]\n // Returns:\n // - raw inner text (reconstructed)\n // - critical flag (true if starts with !)\n // - pairs if it looks like key=value (or flags)\n // - isLikelyTzId for things like [Asia/Singapore]\n private parseBracketGroup(): {\n raw: string;\n critical: boolean;\n pairs: Record<string, string | true>;\n isLikelyTzId: boolean;\n } {\n this.eat(TokType.LBracket);\n\n const parts: string[] = [];\n const pairs: Record<string, string | true> = {};\n\n // Check for critical flag (IXDTF: [!u-ca=gregory])\n const critical = this.tryEat(TokType.Exclamation) != null;\n if (critical) {\n parts.push('!');\n }\n\n // Gather tokens until RBracket\n while (!this.at(TokType.RBracket)) {\n if (this.eof()) {\n throw new ParseError('Unterminated bracket group', this.i);\n }\n\n const t = this.peek();\n this.i++;\n\n parts.push(String(t.value));\n }\n\n this.eat(TokType.RBracket);\n\n const raw = parts.join('');\n\n // Best-effort parse into key/value pairs:\n // Support \"key=value\" and \"flag\" and \"k=v,k2=v2\"\n // Strip leading ! if present for parsing\n const contentToParse = critical ? raw.slice(1) : raw;\n const segments = contentToParse\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n for (const seg of segments) {\n const eq = seg.indexOf('=');\n if (eq === -1) {\n pairs[seg] = true;\n } else {\n const k = seg.slice(0, eq).trim();\n const v = seg.slice(eq + 1).trim();\n if (k) {\n pairs[k] = v || true;\n }\n }\n }\n\n // Heuristic: likely TZ ID if no '=' present and contains '/' (e.g. Asia/Singapore) or starts with Etc/\n // We now preserve critical flag even for timezones, so don't exclude them\n const isLikelyTzId =\n contentToParse.indexOf('=') === -1 &&\n (contentToParse.includes('/') || contentToParse.startsWith('Etc/'));\n\n // Note: If you want STRICTLY separate tz-id brackets vs extension brackets, do it here.\n\n return { raw, critical, pairs, isLikelyTzId };\n }\n\n // -------- Duration parsing --------\n // Grammar (subset):\n // P (Y M W D)* (T (H M S)*)?\n // Examples:\n // P1Y2M\n // P3W\n // P10DT2H30M\n // PT1.5S\n private parseDuration(): DurationAst {\n // Collect raw string as we parse\n const rawParts: string[] = [];\n const annotations: AnnotationAst[] = [];\n\n const pTok = this.eat(TokType.Ident);\n if (String(pTok.value) !== 'P') {\n throw new ParseError(\"Duration must start with 'P'\", this.i);\n }\n rawParts.push('P');\n\n let inTime = false;\n\n const dur: Omit<DurationAst, 'kind' | 'raw' | 'annotations'> = {};\n\n // Parse designators until we hit bracket annotations, slash, or EOF\n while (!this.eof() && !this.at(TokType.Slash) && !this.at(TokType.LBracket)) {\n // Time marker T\n if (this.tryEat(TokType.T)) {\n rawParts.push('T');\n inTime = true;\n continue;\n }\n\n // Expect a number (possibly with fraction for seconds)\n const numTok = this.tryEat(TokType.Number);\n if (!numTok) {\n break;\n } // be permissive; let parser user decide if this is error-worthy\n rawParts.push(numTok.value);\n\n let fraction: string | undefined;\n // ISO 8601 allows both . and , as decimal separators\n const dotOrComma = this.tryEat(TokType.Dot) || this.tryEat(TokType.Comma);\n if (dotOrComma) {\n rawParts.push(dotOrComma.value); // Preserve the actual separator (. or ,)\n const fracTok = this.eat(TokType.Number);\n rawParts.push(fracTok.value);\n fraction = fracTok.value;\n }\n\n // Unit is IDENT (Y,M,W,D,H,M,S). Note M is months if !inTime else minutes.\n const unitTok = this.eat(TokType.Ident);\n const unit = String(unitTok.value);\n rawParts.push(unit);\n\n const n = toInt(numTok.value, 'duration number', this.i);\n\n if (!inTime) {\n if (unit === 'Y') {\n dur.years = (dur.years ?? 0) + n;\n } else if (unit === 'M') {\n dur.months = (dur.months ?? 0) + n;\n } else if (unit === 'W') {\n dur.weeks = (dur.weeks ?? 0) + n;\n } else if (unit === 'D') {\n dur.days = (dur.days ?? 0) + n;\n } else {\n throw new ParseError(`Invalid duration unit '${unit}' in date part`, this.i);\n }\n } else {\n if (unit === 'H') {\n dur.hours = (dur.hours ?? 0) + n;\n } else if (unit === 'M') {\n dur.minutes = (dur.minutes ?? 0) + n;\n } else if (unit === 'S') {\n dur.seconds = (dur.seconds ?? 0) + n;\n if (fraction !== undefined && fraction.length > 0) {\n dur.secondsFraction = fraction;\n }\n } else {\n throw new ParseError(`Invalid duration unit '${unit}' in time part`, this.i);\n }\n }\n }\n\n // bracket annotations after duration\n while (this.at(TokType.LBracket)) {\n const { raw, critical, pairs } = this.parseBracketGroup();\n annotations.push({ kind: 'Annotation', raw, critical, pairs });\n }\n\n return { kind: 'Duration', ...dur, raw: rawParts.join(''), annotations };\n }\n}\n\n// ---------- Public API ----------\nexport function parseTemporal(src: string): TemporalAst {\n const raw = lexTemporal(src);\n const toks = combineTimezoneOffsets(raw);\n const p = new Parser(toks);\n return p.parseTemporal();\n}\n", "// stringify.ts\n// Convert AST back to temporal string representation\n\nimport type {\n AnnotationAst,\n DateAst,\n DateTimeAst,\n DurationAst,\n OffsetAst,\n RangeAst,\n TemporalAst,\n TimeAst,\n TimeZoneAst,\n} from './parser-types.js';\n\n/**\n * Convert a temporal AST back to its string representation.\n *\n * @param ast - The AST to stringify\n * @returns ISO 8601 / IXDTF formatted string\n *\n * @example\n * ```typescript\n * const ast = parseTemporal('2025-01-12T10:00:00+08:00');\n * const str = stringifyTemporal(ast);\n * // '2025-01-12T10:00:00+08:00'\n * ```\n */\nexport function stringifyTemporal(ast: TemporalAst): string {\n if (ast.kind === 'Range') {\n return stringifyRange(ast);\n }\n if (ast.kind === 'Duration') {\n return stringifyDuration(ast);\n }\n return stringifyDateTime(ast);\n}\n\n/**\n * Stringify a date AST to ISO 8601 format.\n *\n * @param date - The date AST\n * @returns Date string (YYYY, YYYY-MM, or YYYY-MM-DD)\n */\nexport function stringifyDate(date: DateAst): string {\n // Handle negative years (BC dates) - ISO 8601 uses negative years\n // Year 0 = 1 BC, Year -1 = 2 BC, etc.\n let yearStr: string;\n if (date.year < 0) {\n // For negative years, pad the absolute value and prepend the minus sign\n yearStr = '-' + Math.abs(date.year).toString().padStart(4, '0');\n } else {\n yearStr = date.year.toString().padStart(4, '0');\n }\n\n const parts: string[] = [yearStr];\n\n if (date.month != null) {\n parts.push(date.month.toString().padStart(2, '0'));\n\n if (date.day != null) {\n parts.push(date.day.toString().padStart(2, '0'));\n }\n }\n\n return parts.join('-');\n}\n\n/**\n * Stringify a time AST to ISO 8601 format.\n *\n * @param time - The time AST\n * @returns Time string (HH:MM, HH:MM:SS, or HH:MM:SS.fff)\n */\nexport function stringifyTime(time: TimeAst): string {\n const parts: string[] = [\n time.hour.toString().padStart(2, '0'),\n time.minute.toString().padStart(2, '0'),\n ];\n\n if (time.second != null) {\n let secondStr = time.second.toString().padStart(2, '0');\n if (time.fraction != null) {\n secondStr += `.${time.fraction}`;\n }\n parts.push(secondStr);\n }\n\n return parts.join(':');\n}\n\n/**\n * Stringify a timezone offset AST to canonical format.\n *\n * @param offset - The offset AST\n * @returns Offset string in canonical format (Z or \u00B1HH:MM)\n */\nexport function stringifyOffset(offset: OffsetAst): string {\n if (offset.kind === 'UtcOffset') {\n return 'Z';\n }\n // Return canonical format: +HH:MM or -HH:MM\n const hours = offset.hours.toString().padStart(2, '0');\n const minutes = offset.minutes.toString().padStart(2, '0');\n return `${offset.sign}${hours}:${minutes}`;\n}\n\n/**\n * Stringify a timezone AST.\n *\n * @param timeZone - The timezone AST\n * @returns Timezone string [Asia/Singapore] or [!Asia/Singapore]\n */\nexport function stringifyTimeZone(timeZone: TimeZoneAst): string {\n const id = timeZone.critical ? `!${timeZone.id}` : timeZone.id;\n return `[${id}]`;\n}\n\n/**\n * Stringify an annotation AST.\n *\n * @param annotation - The annotation AST\n * @returns Annotation string [u-ca=gregory] or [!u-ca=gregory]\n */\nexport function stringifyAnnotation(annotation: AnnotationAst): string {\n return `[${annotation.raw}]`;\n}\n\n/**\n * Stringify a datetime AST to ISO 8601 / IXDTF format.\n *\n * @param dateTime - The datetime AST\n * @returns DateTime string with optional time, offset, timezone, and annotations\n */\nexport function stringifyDateTime(dateTime: DateTimeAst): string {\n let result = stringifyDate(dateTime.date);\n\n if (dateTime.time) {\n result += `T${stringifyTime(dateTime.time)}`;\n }\n\n if (dateTime.offset) {\n result += stringifyOffset(dateTime.offset);\n }\n\n if (dateTime.timeZone) {\n result += stringifyTimeZone(dateTime.timeZone);\n }\n\n for (const annotation of dateTime.annotations) {\n result += stringifyAnnotation(annotation);\n }\n\n return result;\n}\n\n/**\n * Stringify a duration AST to ISO 8601 format.\n *\n * @param duration - The duration AST\n * @returns Duration string (P1Y2M3DT4H5M6S)\n */\nexport function stringifyDuration(duration: DurationAst): string {\n // Always reconstruct from components to ensure normalization\n let result = 'P';\n\n // Date part - include component if defined (even if zero)\n if (duration.years != null) {\n result += `${duration.years}Y`;\n }\n if (duration.months != null) {\n result += `${duration.months}M`;\n }\n if (duration.weeks != null) {\n result += `${duration.weeks}W`;\n }\n if (duration.days != null) {\n result += `${duration.days}D`;\n }\n\n // Time part - add T separator if any time component is defined\n const hasTimePart =\n duration.hours != null || duration.minutes != null || duration.seconds != null;\n if (hasTimePart) {\n result += 'T';\n if (duration.hours != null) {\n result += `${duration.hours}H`;\n }\n if (duration.minutes != null) {\n result += `${duration.minutes}M`;\n }\n if (duration.seconds != null) {\n result += `${duration.seconds}`;\n if (duration.secondsFraction != null && duration.secondsFraction.length > 0) {\n result += `.${duration.secondsFraction}`;\n }\n result += 'S';\n }\n }\n\n // Annotations\n for (const annotation of duration.annotations) {\n result += stringifyAnnotation(annotation);\n }\n\n return result;\n}\n\n/**\n * Stringify a range AST to ISO 8601 format.\n *\n * @param range - The range AST\n * @returns Range string (start/end, /end, or start/)\n */\nexport function stringifyRange(range: RangeAst): string {\n const start = range.start\n ? range.start.kind === 'Duration'\n ? stringifyDuration(range.start)\n : stringifyDateTime(range.start)\n : '';\n\n const end = range.end\n ? range.end.kind === 'Duration'\n ? stringifyDuration(range.end)\n : stringifyDateTime(range.end)\n : '';\n\n return `${start}/${end}`;\n}\n"],
"mappings": "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",
"names": ["TokType", "CombinedTokType"]
}

@@ -7,4 +7,5 @@ export { combineTimezoneOffsets } from './combineTimezoneOffsets.js';

export { parseOffset } from './parseOffset.js';
export { stringifyAnnotation, stringifyDate, stringifyDateTime, stringifyDuration, stringifyOffset, stringifyRange, stringifyTemporal, stringifyTime, stringifyTimeZone, } from './stringify.js';
export type { AnnotationAst, DateAst, DateTimeAst, DurationAst, OffsetAst, RangeAst, TemporalAst, TimeAst, TimeZoneAst, ValueAst, } from './parser-types.js';
export { LexError, ParseError } from './errors.js';
//# sourceMappingURL=index.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,YAAY,EACV,aAAa,EACb,OAAO,EACP,WAAW,EACX,WAAW,EACX,SAAS,EACT,QAAQ,EACR,WAAW,EACX,OAAO,EACP,WAAW,EACX,QAAQ,GACT,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAGxB,YAAY,EACV,aAAa,EACb,OAAO,EACP,WAAW,EACX,WAAW,EACX,SAAS,EACT,QAAQ,EACR,WAAW,EACX,OAAO,EACP,WAAW,EACX,QAAQ,GACT,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}

@@ -18,2 +18,6 @@ export type TemporalAst = RangeAst | ValueAst;

kind: 'Date';
/**
* Components are receivable by Temporal.PlainDate.from().
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDate/from
*/
year: number;

@@ -25,2 +29,6 @@ month?: number;

kind: 'Time';
/**
* Components are receivable by Temporal.PlainTime.from().
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/from
*/
hour: number;

@@ -27,0 +35,0 @@ minute: number;

@@ -1,1 +0,1 @@

{"version":3,"file":"parser-types.d.ts","sourceRoot":"","sources":["../../src/parser-types.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,WAAW,EAAE,aAAa,EAAE,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEN,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,YAAY,CAAC;IAEnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,UAAU,CAAC;IAGjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,aAAa,EAAE,CAAC;CAC9B,CAAC"}
{"version":3,"file":"parser-types.d.ts","sourceRoot":"","sources":["../../src/parser-types.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,WAAW,EAAE,aAAa,EAAE,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEN,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,YAAY,CAAC;IAEnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,UAAU,CAAC;IAKjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,aAAa,EAAE,CAAC;CAC9B,CAAC"}

@@ -1,1 +0,1 @@

{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAMV,WAAW,EAIZ,MAAM,mBAAmB,CAAC;AA0W3B,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAKtD"}
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAMV,WAAW,EAIZ,MAAM,mBAAmB,CAAC;AAoX3B,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAKtD"}
{
"name": "@taskade/temporal-parser",
"version": "1.0.5",
"version": "1.1.0",
"description": "A lexer/parser based temporal expression parser for ISO 8601 and IXDTF formats",

@@ -5,0 +5,0 @@ "type": "module",

@@ -45,2 +45,6 @@ # Temporal Parser

// { kind: 'Range', start: {...}, end: {...} }
// Parse BC dates (negative years in ISO 8601)
const bcDate = parseTemporal('-0044-03-15');
// { kind: 'DateTime', date: { year: -44, month: 3, day: 15 }, ... }
```

@@ -54,2 +58,3 @@

- Full date: `2025-01-12`
- BC dates (negative years): `-0044-03-15` (44 BC), `0000-01-01` (1 BC)

@@ -60,2 +65,3 @@ ### Times

- With fractional seconds: `T10:30:45.123456789`
- European format (comma): `T10:30:45,123` (normalized to dot in output)

@@ -71,2 +77,3 @@ ### Timezones

- Combined: `P1Y2M3DT4H5M6S`
- Fractional seconds: `PT1.5S` or `PT1,5S` (comma normalized to dot)

@@ -107,2 +114,30 @@ ### IXDTF Annotations

### Stringify AST Back to String
```typescript
import { parseTemporal, stringifyTemporal } from '@taskade/temporal-parser';
// Parse and stringify
const ast = parseTemporal('2025-01-12T10:00:00+08:00[Asia/Singapore]');
const str = stringifyTemporal(ast);
// '2025-01-12T10:00:00+08:00[Asia/Singapore]'
// Offsets are normalized to canonical format (±HH:MM)
const ast2 = parseTemporal('2025-01-12T10:00:00+0530'); // Compact format
const str2 = stringifyTemporal(ast2);
// '2025-01-12T10:00:00+05:30' (normalized)
// Stringify individual components
import { stringifyDate, stringifyTime, stringifyDuration } from '@taskade/temporal-parser';
stringifyDate({ kind: 'Date', year: 2025, month: 1, day: 12 });
// '2025-01-12'
stringifyTime({ kind: 'Time', hour: 10, minute: 30, second: 45 });
// '10:30:45'
stringifyDuration({ kind: 'Duration', years: 1, months: 2, raw: 'P1Y2M', annotations: [] });
// 'P1Y2M'
```
## Motivation

@@ -177,2 +212,18 @@

### `stringifyTemporal(ast: TemporalAst): string`
Converts a temporal AST back to its string representation.
**Returns:** ISO 8601 / IXDTF formatted string
**Also available:**
- `stringifyDate(date: DateAst): string`
- `stringifyTime(time: TimeAst): string`
- `stringifyDateTime(dateTime: DateTimeAst): string`
- `stringifyDuration(duration: DurationAst): string`
- `stringifyRange(range: RangeAst): string`
- `stringifyOffset(offset: OffsetAst): string`
- `stringifyTimeZone(timeZone: TimeZoneAst): string`
- `stringifyAnnotation(annotation: AnnotationAst): string`
## TypeScript Support

@@ -179,0 +230,0 @@