Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -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)
------------------

Expand Down
28 changes: 5 additions & 23 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
60 changes: 60 additions & 0 deletions test/parser-tests.js
Original file line number Diff line number Diff line change
@@ -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);

});

});

});