Skip to content
Merged
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# @digitalbazaar/cborld ChangeLog

## 8.0.2 - 2025-mm-dd

### Fixed
- Properly encode/decode dates from before the epoch.

## 8.0.1 - 2025-05-21

### Fixed
Expand Down
5 changes: 3 additions & 2 deletions lib/codecs/ValueEncoder.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2024 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2024-2025 Digital Bazaar, Inc. All rights reserved.
*/
import {
bytesFromInt,
Expand Down Expand Up @@ -37,7 +37,8 @@ export class ValueEncoder extends CborldEncoder {
const bytes = toBytes({intValue});
return new Token(Type.bytes, bytes);
}
return new Token(Type.uint, intValue);
const tokenType = intValue >= 0 ? Type.uint : Type.negint;
return new Token(tokenType, intValue);
}

static createEncoder({value, converter, termInfo, termType} = {}) {
Expand Down
5 changes: 3 additions & 2 deletions lib/codecs/XsdDateEncoder.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2021-2024 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2021-2025 Digital Bazaar, Inc. All rights reserved.
*/
import {Token, Type} from 'cborg';
import {CborldEncoder} from './CborldEncoder.js';
Expand All @@ -21,7 +21,8 @@ export class XsdDateEncoder extends CborldEncoder {
// compression would be lossy, do not compress
return new Token(Type.string, value);
}
return new Token(Type.uint, secondsSinceEpoch);
const tokenType = secondsSinceEpoch >= 0 ? Type.uint : Type.negint;
return new Token(tokenType, secondsSinceEpoch);
}

static createEncoder({value} = {}) {
Expand Down
5 changes: 3 additions & 2 deletions lib/codecs/XsdDateTimeEncoder.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2021-2024 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2021-2025 Digital Bazaar, Inc. All rights reserved.
*/
import {Token, Type} from 'cborg';
import {CborldEncoder} from './CborldEncoder.js';
Expand All @@ -14,7 +14,8 @@ export class XsdDateTimeEncoder extends CborldEncoder {
encode() {
const {value, parsed} = this;
const secondsSinceEpoch = Math.floor(parsed / 1000);
const secondsToken = new Token(Type.uint, secondsSinceEpoch);
const tokenType = secondsSinceEpoch >= 0 ? Type.uint : Type.negint;
const secondsToken = new Token(tokenType, secondsSinceEpoch);
const millisecondIndex = value.indexOf('.');
if(millisecondIndex === -1) {
const expectedDate = new Date(
Expand Down
102 changes: 102 additions & 0 deletions tests/roundtrip.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,108 @@ describe('cborld round trip', () => {
expect(decodedDocument).to.eql(jsonldDocument);
});

it('should handle wide dateTime range', async () => {
const CONTEXT = {
'@context': {
date: {
'@id': 'ex:date',
'@type': 'http://www.w3.org/2001/XMLSchema#dateTime'
},
}
};
const jsonldDocument = {
'@context': CONTEXT['@context'],
date: [
'-1000-01-01T00:00:00Z',
'0-01-01T00:00:00Z',
'1000-01-01T00:00:00Z',
'1000-01-01T00:00:00.123Z',
'1960-01-01T00:00:00Z',
'1960-01-01T23:59:59Z',
'1969-12-31T23:59:59Z',
'1970-01-01T00:00:00Z',
'1970-01-01T00:00:01Z',
'1970-12-31T23:59:59Z',
'2000-01-01T00:00:00Z',
'3000-01-01T00:00:00Z',
'3000-01-01T00:00:00.123Z',
'10000-01-01T00:00:00Z'
// TODO: increase possible xsd:dateTime value coverage
]
};

const documentLoader = url => {
throw new Error(`Refused to load URL "${url}".`);
};

const typeTable = new Map(TYPE_TABLE);

const cborldBytes = await encode({
jsonldDocument,
format: 'cbor-ld-1.0',
registryEntryId: 1,
documentLoader,
typeTableLoader: () => typeTable
});

const decodedDocument = await decode({
cborldBytes,
documentLoader,
typeTableLoader: () => typeTable
});
expect(decodedDocument).to.eql(jsonldDocument);
});

it('should handle wide date range', async () => {
const CONTEXT = {
'@context': {
date: {
'@id': 'ex:date',
'@type': 'http://www.w3.org/2001/XMLSchema#date'
},
}
};
const jsonldDocument = {
'@context': CONTEXT['@context'],
date: [
'-1000-01-01',
'0-01-01',
'1000-01-01',
'1960-01-01',
'1960-01-01',
'1969-12-31',
'1970-01-01',
'1970-01-01',
'1970-12-31',
'2000-01-01',
'3000-01-01',
'10000-01-01'
// TODO: increase possible xsd:date value coverage
]
};

const documentLoader = url => {
throw new Error(`Refused to load URL "${url}".`);
};

const typeTable = new Map(TYPE_TABLE);

const cborldBytes = await encode({
jsonldDocument,
format: 'cbor-ld-1.0',
registryEntryId: 1,
documentLoader,
typeTableLoader: () => typeTable
});

const decodedDocument = await decode({
cborldBytes,
documentLoader,
typeTableLoader: () => typeTable
});
expect(decodedDocument).to.eql(jsonldDocument);
});

it('should revert remote type-scope', async () => {
const CONTEXT_URL = 'urn:foo';
const CONTEXT = {
Expand Down