Comparing version 1.0.8 to 1.0.9
@@ -27,6 +27,13 @@ /* eslint-env mocha */ | ||
const {Vector, String} = Types() | ||
const type = Vector(String()) | ||
throws(() => Vector('String'), /Vector type should be a serializer/) | ||
assertSerializer(type, ['z', 'a', 'z']) // does not sort | ||
assertRequired(type) | ||
const unsortedVector = Vector(String()) | ||
assertRequired(unsortedVector) | ||
assert.deepEqual(unsortedVector.fromObject(['z', 'z']), ['z', 'z']) // allows duplicates | ||
assert.deepEqual(unsortedVector.fromObject(['z', 'a']), ['z', 'a']) // does not sort | ||
assertSerializer(unsortedVector, ['z', 'a']) | ||
const sortedVector = Vector(String(), true) | ||
assert.deepEqual(sortedVector.fromObject(['z', 'a']), ['a', 'z']) //sorts | ||
assertSerializer(sortedVector, ['a', 'z']) | ||
}) | ||
@@ -203,3 +210,3 @@ | ||
const {Person} = assertCompile({Person: {fields: {friends: 'String[]'}}}) | ||
assertSerializer(Person, {friends: ['Jane', 'Dan']}) | ||
assertSerializer(Person, {friends: ['Dan', 'Jane']}) | ||
}) | ||
@@ -215,4 +222,27 @@ | ||
describe('Override', function () { | ||
it('Struct', function () { | ||
it('type', function () { | ||
const definitions = { | ||
Asset: { | ||
fields: { | ||
amount: 'String', // another definition (like transfer) | ||
symbol: 'String' | ||
} | ||
} | ||
} | ||
const override = { | ||
'Asset.fromObject': (value) => { | ||
const [amount, symbol] = value.split(' ') | ||
return {amount, symbol} | ||
} | ||
} | ||
const {structs, errors} = create(definitions, Types({override})) | ||
assert.equal(errors.length, 0) | ||
const asset = structs.Asset.fromObject('1 EOS') | ||
assert.deepEqual(asset, {amount: 1, symbol: 'EOS'}) | ||
assert.deepEqual(asset, structs.Asset.toObject(asset)) | ||
}) | ||
it('field', function () { | ||
const definitions = { | ||
Message: { | ||
@@ -231,29 +261,27 @@ fields: { | ||
} | ||
const config = { | ||
override: { | ||
'Message.data.fromByteBuffer': ({fields, object, b, config}) => { | ||
const ser = (object.type || '') == '' ? fields.data : structs[object.type] | ||
b.readVarint32() | ||
object.data = ser.fromByteBuffer(b, config) | ||
}, | ||
'Message.data.appendByteBuffer': ({fields, object, b}) => { | ||
const ser = (object.type || '') == '' ? fields.data : structs[object.type] | ||
const b2 = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN) | ||
ser.appendByteBuffer(b2, object.data) | ||
b.writeVarint32(b2.offset) | ||
b.append(b2.copy(0, b2.offset), 'binary') | ||
}, | ||
'Message.data.fromObject': ({fields, serializedObject, result}) => { | ||
const {data, type} = serializedObject | ||
const ser = (type || '') == '' ? fields.data : structs[type] | ||
result.data = ser.fromObject(data) | ||
}, | ||
'Message.data.toObject': ({fields, serializedObject, result, config}) => { | ||
const {data, type} = serializedObject || {} | ||
const ser = (type || '') == '' ? fields.data : structs[type] | ||
result.data = ser.toObject(data, config) | ||
}, | ||
const override = { | ||
'Message.data.fromByteBuffer': ({fields, object, b, config}) => { | ||
const ser = (object.type || '') == '' ? fields.data : structs[object.type] | ||
b.readVarint32() | ||
object.data = ser.fromByteBuffer(b, config) | ||
}, | ||
'Message.data.appendByteBuffer': ({fields, object, b}) => { | ||
const ser = (object.type || '') == '' ? fields.data : structs[object.type] | ||
const b2 = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN) | ||
ser.appendByteBuffer(b2, object.data) | ||
b.writeVarint32(b2.offset) | ||
b.append(b2.copy(0, b2.offset), 'binary') | ||
}, | ||
'Message.data.fromObject': ({fields, serializedObject, result}) => { | ||
const {data, type} = serializedObject | ||
const ser = (type || '') == '' ? fields.data : structs[type] | ||
result.data = ser.fromObject(data) | ||
}, | ||
'Message.data.toObject': ({fields, serializedObject, result, config}) => { | ||
const {data, type} = serializedObject || {} | ||
const ser = (type || '') == '' ? fields.data : structs[type] | ||
result.data = ser.toObject(data, config) | ||
} | ||
} | ||
const {structs, errors} = create(definitions, Types(config)) | ||
const {structs, errors} = create(definitions, Types({override, debug: true})) | ||
assert.equal(errors.length, 0) | ||
@@ -270,2 +298,39 @@ assertSerializer(structs.Message, { | ||
describe('Custom Type', function () { | ||
it('Implied Decimal', function () { | ||
const customTypes = { | ||
ImpliedDecimal: ()=> [ImpliedDecimal, {decimals: 4}] | ||
} | ||
const definitions = { | ||
Asset: { | ||
fields: { | ||
amount: 'ImpliedDecimal', | ||
symbol: 'String' | ||
} | ||
} | ||
} | ||
const ImpliedDecimal = ({decimals}) => { | ||
return { | ||
fromByteBuffer: (b) => b.readVString(), | ||
appendByteBuffer: (b, value) => {b.writeVString(value.toString())}, | ||
fromObject (value) { | ||
let [num = '', dec = ''] = value.split('.') | ||
// if(dec.length > decimals) { throw TypeError(`Adjust precision to only ${decimals} decimal places.`) } | ||
dec += '0'.repeat(decimals - dec.length) | ||
return `${num}.${dec}` | ||
}, | ||
toObject: (value) => value | ||
} | ||
} | ||
const {structs, errors} = create(definitions, Types({customTypes})) | ||
assert.equal(errors.length, 0) | ||
const asset = structs.Asset.fromObject({amount: '1', symbol: 'EOS'}) | ||
assert.deepEqual(asset, {amount: '1.0000', symbol: 'EOS'}) | ||
}) | ||
}) | ||
function assertCompile (definitions, config) { | ||
@@ -289,3 +354,2 @@ config = Object.assign({defaults: true, debug: false}, config) | ||
const obj3 = type.toObject(obj) // tests toObject | ||
deepEqual(value, obj3, 'serialize object') | ||
@@ -292,0 +356,0 @@ deepEqual(obj3, obj2, 'serialize buffer') |
{ | ||
"name": "fcbuffer", | ||
"description": "Serialization library geared towards immutable data storage such as blockchains.", | ||
"version": "1.0.8", | ||
"version": "1.0.9", | ||
"main": "index.js", | ||
@@ -6,0 +6,0 @@ "license": "MIT", |
[![Build Status](https://travis-ci.org/EOSIO/eosjs-fcbuffer.svg?branch=master)](https://travis-ci.org/EOSIO/eosjs-fcbuffer) | ||
[![Coverage Status](https://coveralls.io/repos/github/EOSIO/eosjs-fcbuffer/badge.svg?branch=master)](https://coveralls.io/github/EOSIO/eosjs-fcbuffer?branch=master) | ||
[![NPM](https://img.shields.io/npm/v/fcbuffer.svg)](https://www.npmjs.org/package/fcbuffer) | ||
@@ -4,0 +5,0 @@ # FC Buffer |
@@ -142,3 +142,3 @@ const ByteBuffer = require('bytebuffer') | ||
try { | ||
if (!fields) { return result } | ||
// if (!fields) { return result } | ||
@@ -168,3 +168,3 @@ for (field in fields) { | ||
const appendByteBuffer = config.override[`${name}.${field}.appendByteBuffer`] | ||
if(toObject && appendByteBuffer) { // FIXME | ||
if(toObject && appendByteBuffer) { | ||
appendByteBuffer({fields, serializedObject, b}) | ||
@@ -188,36 +188,4 @@ } else { | ||
return result | ||
}, | ||
/** | ||
Sort by the first element in a definition. Deterministic ordering is very important. | ||
*/ | ||
compare (a, b) { | ||
const firstKey = Object.keys(fields)[0] | ||
const firstType = fields[firstKey] | ||
const valA = a[firstKey] | ||
const valB = b[firstKey] | ||
if (firstType.compare) { return firstType.compare(valA, valB) } | ||
if (typeof valA === 'number' && typeof valB === 'number') { return valA - valB } | ||
let encoding | ||
if (Buffer.isBuffer(valA) && Buffer.isBuffer(valB)) { | ||
// A binary string compare does not work. If localeCompare is well | ||
// supported that could replace HEX. Performanance is very good so | ||
// comparing HEX is used for now. | ||
encoding = 'hex' | ||
} | ||
const strA = toString(valA, encoding) | ||
const strB = toString(valB, encoding) | ||
return strA > strB ? 1 : strA < strB ? -1 : 0 | ||
} | ||
} | ||
} | ||
const toString = (value, encoding) => | ||
value == null ? null | ||
: value.toString ? value.toString(encoding) | ||
: value |
@@ -7,3 +7,3 @@ const BN = require('bn.js') | ||
String: () => [string], | ||
Vector: type => [vector, {type}], | ||
Vector: (type, sorted) => [vector, {type, sorted}], | ||
Optional: type => [optional, {type}], | ||
@@ -78,21 +78,15 @@ Time: () => [time], | ||
const isSerializer = type => | ||
typeof type === 'object' && | ||
typeof type.fromByteBuffer === 'function' && | ||
typeof type.appendByteBuffer === 'function' && | ||
typeof type.fromObject === 'function' && | ||
typeof type.toObject === 'function' | ||
const vector = validation => { | ||
if (!isSerializer(validation.type)) { throw new TypeError('Vector type should be a serializer') } | ||
const {type, sorted} = validation | ||
if (!isSerializer(type)) { throw new TypeError('Vector type should be a serializer') } | ||
return { | ||
fromByteBuffer (b) { | ||
const size = b.readVarint32() | ||
// if (validation.debug) { | ||
// console.log("constint32 size = " + size.toString(16)) | ||
// } | ||
// if (validation.debug) { | ||
// console.log("constint32 size = " + size.toString(16)) | ||
// } | ||
const result = [] | ||
for (let i = 0; i < size; i++) { | ||
result.push(validation.type.fromByteBuffer(b)) | ||
result.push(type.fromByteBuffer(b)) | ||
} | ||
@@ -104,4 +98,7 @@ return result | ||
b.writeVarint32(value.length) | ||
if(sorted) { | ||
value = sort(type, Object.assign([], value)) | ||
} | ||
for (const o of value) { | ||
validation.type.appendByteBuffer(b, o) | ||
type.appendByteBuffer(b, o) | ||
} | ||
@@ -112,4 +109,7 @@ }, | ||
const result = [] | ||
if(sorted) { | ||
value = sort(type, Object.assign([], value)) | ||
} | ||
for (const o of value) { | ||
result.push(validation.type.fromObject(o)) | ||
result.push(type.fromObject(o)) | ||
} | ||
@@ -120,9 +120,11 @@ return result | ||
if (validation.defaults && value == null) { | ||
return [validation.type.toObject(value)] | ||
return [type.toObject(value)] | ||
} | ||
validate(value, validation) | ||
const result = [] | ||
if(sorted) { | ||
value = sort(type, Object.assign([], value)) | ||
} | ||
for (const o of value) { | ||
result.push(validation.type.toObject(o)) | ||
result.push(type.toObject(o)) | ||
} | ||
@@ -358,2 +360,49 @@ return result | ||
/** | ||
Sort by the first element in a definition. Deterministic ordering is very important. | ||
*/ | ||
const compare = values => { | ||
const firstKey = Object.keys(values)[0] | ||
const firstType = values[firstKey] | ||
return (a, b) => { | ||
const valA = a[firstKey] | ||
const valB = b[firstKey] | ||
if (firstType.compare) { | ||
return firstType.compare(valA, valB) | ||
} | ||
if (typeof valA === 'number' && typeof valB === 'number') { | ||
return valA - valB | ||
} | ||
let encoding | ||
if (Buffer.isBuffer(valA) && Buffer.isBuffer(valB)) { | ||
// A binary string compare does not work. If localeCompare is well | ||
// supported that could replace HEX. Performanance is very good so | ||
// comparing HEX is used for now. | ||
encoding = 'hex' | ||
} | ||
const strA = toString(valA, encoding) | ||
const strB = toString(valB, encoding) | ||
return strA > strB ? 1 : strA < strB ? -1 : 0 | ||
} | ||
} | ||
const isSerializer = type => | ||
typeof type === 'object' && | ||
typeof type.fromByteBuffer === 'function' && | ||
typeof type.appendByteBuffer === 'function' && | ||
typeof type.fromObject === 'function' && | ||
typeof type.toObject === 'function' | ||
const toString = (value, encoding) => | ||
value == null ? value : | ||
value.toString ? value.toString(encoding) : | ||
value | ||
const sort = (type, values) => | ||
type.compare ? values.sort(type.compare(values)) : | ||
values.sort(compare(values)) | ||
const spread = (...args) => Object.assign(...args) | ||
@@ -360,0 +409,0 @@ const isEmpty = value => value == null |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
70333
1090
103