Skip to content

Commit 435a696

Browse files
committed
Added null/undefined encoding
1 parent 95c64b3 commit 435a696

2 files changed

Lines changed: 67 additions & 7 deletions

File tree

javascript/beve.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,10 @@
500500
}
501501

502502
function write_value(writer, value) {
503-
if (Array.isArray(value) && value.length > 1 && typeof value[0] === 'number') {
503+
if (value === null || value === undefined) {
504+
// null header: type 0, is_bool = 0
505+
writer.append_uint8(0);
506+
} else if (Array.isArray(value) && value.length > 1 && value.every(v => typeof v === 'number')) {
504507
let header = 4;
505508
if (typeof value[0] === 'number' && !Number.isInteger(value[0])) {
506509
header |= 0b01100000; // float64_t (double)
@@ -542,15 +545,17 @@
542545
for (let i = 0; i < value.length; i++) {
543546
write_value(writer, value[i]);
544547
}
545-
} else if (typeof value === 'object' && Object.keys(value).length > 0) {
548+
} else if (typeof value === 'object') {
549+
// Filter out undefined values (matching JSON.stringify behavior)
550+
const keys = Object.keys(value).filter(k => value[k] !== undefined);
546551
let header = 3;
547552
let keyType = 0; // Assuming keys are always strings
548553
let isSigned = false;
549554
header |= keyType << 3;
550555
header |= isSigned << 5;
551556
writer.append_uint8(header);
552-
writeCompressed(writer, Object.keys(value).length);
553-
for (const key in value) {
557+
writeCompressed(writer, keys.length);
558+
for (const key of keys) {
554559
const keyBytes = new TextEncoder().encode(key);
555560
writeCompressed(writer, keyBytes.length);
556561
writer.ensureCapacity(keyBytes.length);

javascript/beve.test.js

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,62 @@ describe('BEVE JavaScript Library', () => {
7676
});
7777
});
7878

79+
describe('Null and Undefined Handling (Issue #7)', () => {
80+
81+
test('null value', () => {
82+
expect(roundTrip(null)).toBe(null);
83+
});
84+
85+
test('undefined converts to null', () => {
86+
expect(roundTrip(undefined)).toBe(null);
87+
});
88+
89+
test('object with null value', () => {
90+
const input = { value: null };
91+
expect(roundTrip(input)).toEqual(input);
92+
});
93+
94+
test('object with undefined value is omitted', () => {
95+
const input = { defined: 'yes', notDefined: undefined };
96+
const expected = { defined: 'yes' };
97+
expect(roundTrip(input)).toEqual(expected);
98+
});
99+
100+
test('object with only undefined values becomes empty', () => {
101+
const input = { a: undefined, b: undefined };
102+
expect(roundTrip(input)).toEqual({});
103+
});
104+
105+
test('array with null elements', () => {
106+
const input = [1, null, 3];
107+
expect(roundTrip(input)).toEqual([1, null, 3]);
108+
});
109+
110+
test('array with undefined elements converts to null', () => {
111+
const input = [1, undefined, 3];
112+
const expected = [1, null, 3];
113+
expect(roundTrip(input)).toEqual(expected);
114+
});
115+
116+
test('nested object with null', () => {
117+
const input = { outer: { inner: null } };
118+
expect(roundTrip(input)).toEqual(input);
119+
});
120+
121+
test('mixed null and undefined in object', () => {
122+
const input = {
123+
present: 'value',
124+
isNull: null,
125+
isUndefined: undefined
126+
};
127+
const expected = {
128+
present: 'value',
129+
isNull: null
130+
};
131+
expect(roundTrip(input)).toEqual(expected);
132+
});
133+
});
134+
79135
describe('String Handling', () => {
80136

81137
test('empty string', () => {
@@ -194,9 +250,8 @@ describe('BEVE JavaScript Library', () => {
194250

195251
describe('Objects', () => {
196252

197-
test('empty object throws', () => {
198-
// Current implementation throws on empty objects
199-
expect(() => roundTrip({})).toThrow();
253+
test('empty object', () => {
254+
expect(roundTrip({})).toEqual({});
200255
});
201256

202257
test('simple object with string value', () => {

0 commit comments

Comments
 (0)