From 0847ecfee95022e78688c6d080ca92b68f41cbbb Mon Sep 17 00:00:00 2001 From: Wleeaf <179125857+wleeaf@users.noreply.github.com> Date: Mon, 26 Oct 2026 12:05:46 +0000 Subject: [PATCH] Parse dates followed by parameters or other members --- changelog.md | 7 ++++++ src/parser.ts | 28 ++++----------------- test/parser-tests.js | 60 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 23 deletions(-) create mode 100644 test/parser-tests.js diff --git a/changelog.md b/changelog.md index 000203a..440ee9e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,13 @@ ChangeLog ========= +2.1.2 (????-??-??) +------------------ + +* Dates followed by parameters or by more list or dictionary members, such as + `@1659578233;a=1` or `a=@1659578233, b=2`, failed to parse. (@wleeaf) + + 2.1.1 (2026-10-10) ------------------ diff --git a/src/parser.ts b/src/parser.ts index dba6c6e..47dd08e 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -368,31 +368,13 @@ export default class Parser { private parseDate(): Date { this.expectChar('@'); this.pos++; - let sign = 1; - let inputNumber = ''; - if (this.lookChar() === '-') { - sign = -1; - this.pos++; - } - - if (!isDigit(this.lookChar())) { - throw new ParseError(this.pos, 'Expected a digit (0-9)'); - } - - while (!this.eof()) { - const char = this.getChar(); - if (isDigit(char)) { - inputNumber += char; - } else { - throw new ParseError(this.pos, 'Expected a digit (0-9), whitespace or EOL'); - } - } - - if (inputNumber.length > 15) { - throw new ParseError(this.pos, 'Exceeded max length for a date value'); + const start = this.pos; + const seconds = this.parseIntegerOrDecimal(); + if (this.input.substring(start, this.pos).includes('.')) { + throw new ParseError(start, 'A date must be an integer'); } - return new Date(parseInt(inputNumber, 10) * sign * 1000); + return new Date(seconds * 1000); } private parseKey(): string { diff --git a/test/parser-tests.js b/test/parser-tests.js new file mode 100644 index 0000000..3789a28 --- /dev/null +++ b/test/parser-tests.js @@ -0,0 +1,60 @@ +import { + parseDictionary, + parseItem, + parseList, + ParseError +} from '../dist/index.js'; +import { describe, it } from 'node:test'; +import assert from 'node:assert'; + +/** + * These tests cover cases that aren't covered by the HTTPWG tests. + */ +describe('parser', () => { + + describe('parseDate', () => { + + const date = new Date(1659578233 * 1000); + + it('should parse a date with parameters', () => { + + assert.deepStrictEqual( + parseItem('@1659578233;a=1'), + [date, new Map([['a', 1]])] + ); + + }); + + it('should parse dates followed by other list members', () => { + + assert.deepStrictEqual( + parseList('@1659578233, (@0 @-1)'), + [ + [date, new Map()], + [[[new Date(0), new Map()], [new Date(-1000), new Map()]], new Map()], + ] + ); + + }); + + it('should parse a date followed by other dictionary members', () => { + + assert.deepStrictEqual( + parseDictionary('a=@1659578233, b=2'), + new Map([ + ['a', [date, new Map()]], + ['b', [2, new Map()]], + ]) + ); + + }); + + it('should reject a decimal date', () => { + + assert.throws(() => parseItem('@1659578233.5'), ParseError); + + }); + + }); + +});