diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/kiwi.js b/kiwi.js index 00d6536..7c1db11 100644 --- a/kiwi.js +++ b/kiwi.js @@ -243,6 +243,7 @@ var kiwi = exports || kiwi || {}, exports; 'int', 'string', 'uint', + 'map' ]; // These are special names on the object returned by compileSchema() @@ -251,7 +252,7 @@ var kiwi = exports || kiwi || {}, exports; 'package', ]; - var regex = /((?:-|\b)\d+\b|[=;{}]|\[\]|\[deprecated\]|\b[A-Za-z_][A-Za-z0-9_]*\b|\/\/.*|\s+)/g; + var regex = /((?:-|\b)\d+\b|[=;{}]|\[\]|\<|\>|,|\[deprecated\]|\b[A-Za-z_][A-Za-z0-9_]*\b|\/\/.*|\s+)/g; var identifier = /^[A-Za-z_][A-Za-z0-9_]*$/; var whitespace = /^\/\/.*|\s+$/; var equals = /^=$/; @@ -260,6 +261,9 @@ var kiwi = exports || kiwi || {}, exports; var integer = /^-?\d+$/; var leftBrace = /^\{$/; var rightBrace = /^\}$/; + var lessThan = /^\<$/; + var greaterThan = /^\>$/; + var comma = /^,$/; var arrayToken = /^\[\]$/; var enumKeyword = /^enum$/; var structKeyword = /^struct$/; @@ -362,6 +366,10 @@ var kiwi = exports || kiwi || {}, exports; while (!eat(rightBrace)) { var type = null; var isArray = false; + var isMap = false; + var mapKeyType = null; + var mapValueType = null; + var isDeprecated = false; var isDeprecated = false; // Enums don't have types @@ -369,6 +377,19 @@ var kiwi = exports || kiwi || {}, exports; type = current().text; expect(identifier, 'identifier'); isArray = eat(arrayToken); + if (type === 'map') { + isMap = true; + expect(lessThan, '<'); + eat(lessThan); + mapKeyType = current().text; + eat(identifier); + expect(comma, ','); + eat(comma); + mapValueType = current().text; + eat(identifier); + expect(greaterThan, '<'); + eat(greaterThan); + } } var field = current(); @@ -403,7 +424,10 @@ var kiwi = exports || kiwi || {}, exports; column: field.column, type: type, isArray: isArray, + isMap: isMap, isDeprecated: isDeprecated, + mapKeyType: mapKeyType, + mapValueType: mapValueType, value: value !== null ? value.text | 0 : fields.length + 1, }); } @@ -629,6 +653,84 @@ var kiwi = exports || kiwi || {}, exports; (function() { var ByteBuffer = kiwi.ByteBuffer; + + function decodeCodeForField(field, definitions) { + var code; + + switch (field.type) { + case 'bool': { + code = '!!bb.readByte()'; + break; + } + case 'byte': { + code = 'bb.readByte()'; + break; + } + case 'int': { + code = 'bb.readVarInt()'; + break; + } + case 'uint': { + code = 'bb.readVarUint()'; + break; + } + case 'float': { + code = 'bb.readVarFloat()'; + break; + } + case 'string': { + code = 'bb.readString()'; + break; + } + case 'map': { + var keyCode = decodeCodeForField({ type: field.mapKeyType }, definitions); + if (!keyCode || kiwi.nativeTypes.indexOf(field.mapKeyType) < 0) { + error( + 'Invalid type ' + + quote(field.mapKeyType) + + ' for map key for ' + + quote(field.name) + + '. Map keys must be native fields.', + field.line, + field.column + ); + } + var mapValueField = { type: field.mapValueType, line: field.line, column: field.column }; + var valueCode = decodeCodeForField(mapValueField, definitions); + if (!valueCode) { + error( + 'Invalid type ' + + quote(field.mapValueType) + + ' for map value for ' + + quote(field.name), + field.line, + field.column + ); + } + code = [keyCode, valueCode]; + break; + } + default: { + var type = definitions[field.type]; + if (!type) { + console.log('Type:', type); + console.log(definitions); + error( + 'Invalid type ' + quote(field.type) + ' for field ' + quote(field.name), + field.line, + field.column + ); + } else if (type.kind === 'ENUM') { + code = 'this[' + quote(type.name) + '][bb.readVarUint()]'; + } else { + code = 'this[' + quote('decode' + type.name) + '](bb)'; + } + } + } + + return code; + } + function compileDecode(definition, definitions) { var lines = []; var indent = ' '; @@ -651,50 +753,7 @@ var kiwi = exports || kiwi || {}, exports; for (var i = 0; i < definition.fields.length; i++) { var field = definition.fields[i]; - var code; - - switch (field.type) { - case 'bool': { - code = '!!bb.readByte()'; - break; - } - - case 'byte': { - code = 'bb.readByte()'; - break; - } - - case 'int': { - code = 'bb.readVarInt()'; - break; - } - - case 'uint': { - code = 'bb.readVarUint()'; - break; - } - - case 'float': { - code = 'bb.readVarFloat()'; - break; - } - - case 'string': { - code = 'bb.readString()'; - break; - } - - default: { - var type = definitions[field.type]; - if (!type) { - error('Invalid type ' + quote(field.type) + ' for field ' + quote(field.name), field.line, field.column); - } else if (type.kind === 'ENUM') { - code = 'this[' + quote(type.name) + '][bb.readVarUint()]'; - } else { - code = 'this[' + quote('decode' + type.name) + '](bb)'; - } - } - } + var code = decodeCodeForField(field, definitions); if (definition.kind === 'MESSAGE') { lines.push(' case ' + field.value + ':'); @@ -709,9 +768,16 @@ var kiwi = exports || kiwi || {}, exports; lines.push(indent + 'var length = bb.readVarUint();'); lines.push(indent + 'while (length-- > 0) values.push(' + code + ');'); } - } - - else { + } else if (field.isMap) { + if (field.isDeprecated) { + lines.push(indent + 'var length = bb.readVarUint();'); + lines.push(indent + 'while (length-- > 0) { ' + code[0] + ';' + code[1] + '; }'); + } else { + lines.push(indent + 'var map = result[' + quote(field.name) + '] = {};'); + lines.push(indent + 'var length = bb.readVarUint();'); + lines.push(indent + 'while (length-- > 0) map[' + code[0] + '] = ' + code[1] + ';'); + } + } else { if (field.isDeprecated) { lines.push(indent + code + ';'); } else { @@ -741,67 +807,106 @@ var kiwi = exports || kiwi || {}, exports; return lines.join('\n'); } - function compileEncode(definition, definitions) { - var lines = []; + function encodeCodeForField(field, definitions) { + switch (field.type) { + case 'bool': { + code = 'bb.writeByte(value);'; + break; + } - lines.push('function(message, bb) {'); - lines.push(' var isTopLevel = !bb;'); - lines.push(' if (isTopLevel) bb = new this.ByteBuffer();'); + case 'byte': { + code = 'bb.writeByte(value);'; + break; + } - for (var j = 0; j < definition.fields.length; j++) { - var field = definition.fields[j]; - var code; + case 'int': { + code = 'bb.writeVarInt(value);'; + break; + } - if (field.isDeprecated) { - continue; + case 'uint': { + code = 'bb.writeVarUint(value);'; + break; } - switch (field.type) { - case 'bool': { - code = 'bb.writeByte(value);'; - break; - } + case 'float': { + code = 'bb.writeVarFloat(value);'; + break; + } - case 'byte': { - code = 'bb.writeByte(value);'; - break; - } + case 'string': { + code = 'bb.writeString(value);'; + break; + } - case 'int': { - code = 'bb.writeVarInt(value);'; - break; + case 'map': { + var keyCode = encodeCodeForField({ type: field.mapKeyType }, definitions); + if (!keyCode || kiwi.nativeTypes.indexOf(field.mapKeyType) < 0) { + error( + 'Invalid type ' + + quote(field.mapKeyType) + + ' for map key for ' + + quote(field.name) + + '. Map keys must be native fields.', + field.line, + field.column + ); } - - case 'uint': { - code = 'bb.writeVarUint(value);'; - break; + var mapValueField = { type: field.mapValueType, line: field.line, column: field.column }; + var valueCode = encodeCodeForField(mapValueField, definitions); + if (!valueCode) { + error( + 'Invalid type ' + + quote(field.mapValueType) + + ' for map value for ' + + quote(field.name), + field.line, + field.column + ); } + code = [keyCode, valueCode]; + break; + } - case 'float': { - code = 'bb.writeVarFloat(value);'; - break; + default: { + var type = definitions[field.type]; + if (!type) { + throw new Error( + 'Invalid type ' + quote(field.type) + ' for field ' + quote(field.name) + ); + } else if (type.kind === 'ENUM') { + code = + 'var encoded = this[' + + quote(type.name) + + '][value]; ' + + 'if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + ' + + quote(' for enum ' + quote(type.name)) + + '); ' + + 'bb.writeVarUint(encoded);'; + } else { + code = 'this[' + quote('encode' + type.name) + '](value, bb);'; } + } + } + return code; + } - case 'string': { - code = 'bb.writeString(value);'; - break; - } + function compileEncode(definition, definitions) { + var lines = []; - default: { - var type = definitions[field.type]; - if (!type) { - throw new Error('Invalid type ' + quote(field.type) + ' for field ' + quote(field.name)); - } else if (type.kind === 'ENUM') { - code = - 'var encoded = this[' + quote(type.name) + '][value]; ' + - 'if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + ' + quote(' for enum ' + quote(type.name)) + '); ' + - 'bb.writeVarUint(encoded);'; - } else { - code = 'this[' + quote('encode' + type.name) + '](value, bb);'; - } - } + lines.push('function(message, bb) {'); + lines.push(' var isTopLevel = !bb;'); + lines.push(' if (isTopLevel) bb = new this.ByteBuffer();'); + + for (var j = 0; j < definition.fields.length; j++) { + var field = definition.fields[j]; + + if (field.isDeprecated) { + continue; } + var code = encodeCodeForField(field, definitions); + lines.push(''); lines.push(' var value = message[' + quote(field.name) + '];'); lines.push(' if (value != null) {'); // Comparing with null using "!=" also checks for undefined @@ -817,9 +922,16 @@ var kiwi = exports || kiwi || {}, exports; lines.push(' value = values[i];'); lines.push(' ' + code); lines.push(' }'); - } - - else { + } else if (field.isMap) { + lines.push(' var obj = value, keys = Object.keys(obj), n = keys.length;'); + lines.push(' bb.writeVarUint(n);'); + lines.push(' for (var i = 0; i < keys.length; i++) {'); + lines.push(' value = keys[i];'); + lines.push(' ' + code[0]); + lines.push(' value = obj[keys[i]];'); + lines.push(' ' + code[1]); + lines.push(' }'); + } else { lines.push(' ' + code); } @@ -2282,6 +2394,30 @@ var kiwi = exports || kiwi || {}, exports; (function() { var ByteBuffer = kiwi.ByteBuffer; + function tsTypeForField(field) { + var type + switch (field.type) { + case 'bool': + type = 'boolean'; + break; + case 'byte': + case 'int': + case 'uint': + case 'float': + type = 'number'; + break; + case 'map': + var keyType = tsTypeForField({type: field.mapKeyType}) + var valueType = tsTypeForField({type: field.mapValueType}) + type = '{ [key: ' + keyType + ']: ' + valueType + ' }' + break; + default: + type = field.type; + break; + } + return type + } + function compileSchemaTypeScript(schema) { schema = convertSchema(schema); @@ -2319,17 +2455,12 @@ var kiwi = exports || kiwi || {}, exports; for (var j = 0; j < definition.fields.length; j++) { var field = definition.fields[j]; - var type; - if (field.isDeprecated) { continue; } - switch (field.type) { - case 'bool': type = 'boolean'; break; - case 'byte': case 'int': case 'uint': case 'float': type = 'number'; break; - default: type = field.type; break; - } + var type = tsTypeForField(field) + lines.push(indent + ' ' + field.name + (definition.kind === 'MESSAGE' ? '?' : '') + ': ' + type + (field.isArray ? '[]' : '') + ';'); } diff --git a/test/test-schema.js b/test/test-schema.js index 5c686fe..b91fc60 100644 --- a/test/test-schema.js +++ b/test/test-schema.js @@ -231,6 +231,9 @@ test["decodeNestedStruct"] = function(bb) { result["a"] = bb.readVarUint(); result["b"] = this["decodeCompoundStruct"](bb); result["c"] = bb.readVarUint(); + var map = result["d"] = {}; + var length = bb.readVarUint(); + while (length-- > 0) map[bb.readString()] = this["decodeCompoundStruct"](bb); return result; }; @@ -259,6 +262,20 @@ test["encodeNestedStruct"] = function(message, bb) { throw new Error("Missing required field \"c\""); } + var value = message["d"]; + if (value != null) { + var obj = value, keys = Object.keys(obj), n = keys.length; + bb.writeVarUint(n); + for (var i = 0; i < keys.length; i++) { + value = keys[i]; + bb.writeString(value); + value = obj[keys[i]]; + this["encodeCompoundStruct"](value, bb); + } + } else { + throw new Error("Missing required field \"d\""); + } + if (isTopLevel) return bb.toUint8Array(); }; @@ -517,6 +534,50 @@ test["encodeCompoundMessage"] = function(message, bb) { if (isTopLevel) return bb.toUint8Array(); }; +test["decodeMapMessage"] = function(bb) { + var result = {}; + if (!(bb instanceof this.ByteBuffer)) { + bb = new this.ByteBuffer(bb); + } + + while (true) { + switch (bb.readVarUint()) { + case 0: + return result; + + case 1: + var map = result["x"] = {}; + var length = bb.readVarUint(); + while (length-- > 0) map[bb.readString()] = bb.readVarInt(); + break; + + default: + throw new Error("Attempted to parse invalid message"); + } + } +}; + +test["encodeMapMessage"] = function(message, bb) { + var isTopLevel = !bb; + if (isTopLevel) bb = new this.ByteBuffer(); + + var value = message["x"]; + if (value != null) { + bb.writeVarUint(1); + var obj = value, keys = Object.keys(obj), n = keys.length; + bb.writeVarUint(n); + for (var i = 0; i < keys.length; i++) { + value = keys[i]; + bb.writeString(value); + value = obj[keys[i]]; + bb.writeVarInt(value); + } + } + bb.writeVarUint(0); + + if (isTopLevel) return bb.toUint8Array(); +}; + test["decodeNestedMessage"] = function(bb) { var result = {}; if (!(bb instanceof this.ByteBuffer)) { @@ -540,6 +601,12 @@ test["decodeNestedMessage"] = function(bb) { result["c"] = bb.readVarUint(); break; + case 4: + var map = result["d"] = {}; + var length = bb.readVarUint(); + while (length-- > 0) map[bb.readString()] = this["decodeCompoundMessage"](bb); + break; + default: throw new Error("Attempted to parse invalid message"); } @@ -567,6 +634,19 @@ test["encodeNestedMessage"] = function(message, bb) { bb.writeVarUint(3); bb.writeVarUint(value); } + + var value = message["d"]; + if (value != null) { + bb.writeVarUint(4); + var obj = value, keys = Object.keys(obj), n = keys.length; + bb.writeVarUint(n); + for (var i = 0; i < keys.length; i++) { + value = keys[i]; + bb.writeString(value); + value = obj[keys[i]]; + this["encodeCompoundMessage"](value, bb); + } + } bb.writeVarUint(0); if (isTopLevel) return bb.toUint8Array(); diff --git a/test/test-schema.kiwi b/test/test-schema.kiwi index 1ae72cc..aaf2b4f 100644 --- a/test/test-schema.kiwi +++ b/test/test-schema.kiwi @@ -14,7 +14,7 @@ struct UintStruct { uint x; } struct FloatStruct { float x; } struct StringStruct { string x; } struct CompoundStruct { uint x; uint y; } -struct NestedStruct { uint a; CompoundStruct b; uint c; } +struct NestedStruct { uint a; CompoundStruct b; uint c; map d; } message BoolMessage { bool x = 1; } message ByteMessage { byte x = 1; } @@ -23,7 +23,8 @@ message UintMessage { uint x = 1; } message FloatMessage { float x = 1; } message StringMessage { string x = 1; } message CompoundMessage { uint x = 1; uint y = 2; } -message NestedMessage { uint a = 1; CompoundMessage b = 2; uint c = 3; } +message MapMessage { map x = 1; } +message NestedMessage { uint a = 1; CompoundMessage b = 2; uint c = 3; map d = 4;} struct BoolArrayStruct { bool[] x; } struct ByteArrayStruct { byte[] x; } diff --git a/test/test-schema.ts b/test/test-schema.ts index f74affd..0a804f3 100644 --- a/test/test-schema.ts +++ b/test/test-schema.ts @@ -41,6 +41,7 @@ export namespace test { a: number; b: CompoundStruct; c: number; + d: { [key: string]: CompoundStruct }; } export interface BoolMessage { @@ -72,10 +73,15 @@ export namespace test { y?: number; } + export interface MapMessage { + x?: { [key: string]: number }; + } + export interface NestedMessage { a?: number; b?: CompoundMessage; c?: number; + d?: { [key: string]: CompoundMessage }; } export interface BoolArrayStruct { @@ -211,6 +217,8 @@ export namespace test { decodeStringMessage(buffer: Uint8Array): StringMessage; encodeCompoundMessage(message: CompoundMessage): Uint8Array; decodeCompoundMessage(buffer: Uint8Array): CompoundMessage; + encodeMapMessage(message: MapMessage): Uint8Array; + decodeMapMessage(buffer: Uint8Array): MapMessage; encodeNestedMessage(message: NestedMessage): Uint8Array; decodeNestedMessage(buffer: Uint8Array): NestedMessage; encodeBoolArrayStruct(message: BoolArrayStruct): Uint8Array; diff --git a/test/test.js b/test/test.js index 639823c..f181d90 100644 --- a/test/test.js +++ b/test/test.js @@ -5,20 +5,20 @@ var fs = require('fs'); var schemaText = fs.readFileSync(__dirname + '/test-schema.kiwi', 'utf8'); var schema = kiwi.compileSchema(schemaText); -it('struct bool', function() { +it('struct bool', function () { function check(i, o) { - assert.deepEqual(Buffer(schema.encodeBoolStruct({x: i})), Buffer(o)); - assert.deepEqual(schema.decodeBoolStruct(new Uint8Array(o)), {x: i}); + assert.deepEqual(Buffer(schema.encodeBoolStruct({ x: i })), Buffer(o)); + assert.deepEqual(schema.decodeBoolStruct(new Uint8Array(o)), { x: i }); } check(false, [0]); check(true, [1]); }); -it('struct byte', function() { +it('struct byte', function () { function check(i, o) { - assert.deepEqual(Buffer(schema.encodeByteStruct({x: i})), Buffer(o)); - assert.deepEqual(schema.decodeByteStruct(new Uint8Array(o)), {x: i}); + assert.deepEqual(Buffer(schema.encodeByteStruct({ x: i })), Buffer(o)); + assert.deepEqual(schema.decodeByteStruct(new Uint8Array(o)), { x: i }); } check(0x00, [0x00]); @@ -28,10 +28,10 @@ it('struct byte', function() { check(0xFF, [0xFF]); }); -it('struct uint', function() { +it('struct uint', function () { function check(i, o) { - assert.deepEqual(Buffer(schema.encodeUintStruct({x: i})), Buffer(o)); - assert.deepEqual(schema.decodeUintStruct(new Uint8Array(o)), {x: i}); + assert.deepEqual(Buffer(schema.encodeUintStruct({ x: i })), Buffer(o)); + assert.deepEqual(schema.decodeUintStruct(new Uint8Array(o)), { x: i }); } check(0x00, [0x00]); @@ -52,10 +52,10 @@ it('struct uint', function() { check(0x80000000, [0x80, 0x80, 0x80, 0x80, 0x08]); }); -it('struct int', function() { +it('struct int', function () { function check(i, o) { - assert.deepEqual(Buffer(schema.encodeIntStruct({x: i})), Buffer(o)); - assert.deepEqual(schema.decodeIntStruct(new Uint8Array(o)), {x: i}); + assert.deepEqual(Buffer(schema.encodeIntStruct({ x: i })), Buffer(o)); + assert.deepEqual(schema.decodeIntStruct(new Uint8Array(o)), { x: i }); } check(0x00, [0x00]); @@ -80,10 +80,10 @@ it('struct int', function() { check(-0x80000000, [0xFF, 0xFF, 0xFF, 0xFF, 0x0F]); }); -it('struct float', function() { +it('struct float', function () { function check(i, o) { - assert.deepEqual(Buffer(schema.encodeFloatStruct({x: i})), Buffer(o)); - assert.deepEqual(JSON.stringify(schema.decodeFloatStruct(new Uint8Array(o))), JSON.stringify({x: i})); + assert.deepEqual(Buffer(schema.encodeFloatStruct({ x: i })), Buffer(o)); + assert.deepEqual(JSON.stringify(schema.decodeFloatStruct(new Uint8Array(o))), JSON.stringify({ x: i })); } check(0, [0]); @@ -96,10 +96,10 @@ it('struct float', function() { check(NaN, [255, 0, 0, 128]); }); -it('struct string', function() { +it('struct string', function () { function check(i, o) { - assert.deepEqual(Buffer(schema.encodeStringStruct({x: i})), Buffer(o)); - assert.deepEqual(schema.decodeStringStruct(new Uint8Array(o)), {x: i}); + assert.deepEqual(Buffer(schema.encodeStringStruct({ x: i })), Buffer(o)); + assert.deepEqual(schema.decodeStringStruct(new Uint8Array(o)), { x: i }); } check('', [0]); @@ -107,149 +107,159 @@ it('struct string', function() { check('🙉🙈🙊', [240, 159, 153, 137, 240, 159, 153, 136, 240, 159, 153, 138, 0]); }); -it('struct compound', function() { +it('struct compound', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeCompoundStruct(i)), Buffer(o)); assert.deepEqual(schema.decodeCompoundStruct(new Uint8Array(o)), i); } - check({x: 0, y: 0}, [0, 0]); - check({x: 1, y: 2}, [1, 2]); - check({x: 12345, y: 54321}, [185, 96, 177, 168, 3]); + check({ x: 0, y: 0 }, [0, 0]); + check({ x: 1, y: 2 }, [1, 2]); + check({ x: 12345, y: 54321 }, [185, 96, 177, 168, 3]); }); -it('struct nested', function() { +it('struct nested', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeNestedStruct(i)), Buffer(o)); assert.deepEqual(schema.decodeNestedStruct(new Uint8Array(o)), i); } - check({a: 0, b: {x: 0, y: 0}, c: 0}, [0, 0, 0, 0]); - check({a: 1, b: {x: 2, y: 3}, c: 4}, [1, 2, 3, 4]); - check({a: 534, b: {x: 12345, y: 54321}, c: 321}, [150, 4, 185, 96, 177, 168, 3, 193, 2]); + check({a: 0, b: {x: 0, y: 0}, c: 0, d: {'abc': {x: 1, y: 2}}}, [0, 0, 0, 0, 1, 97, 98, 99, 0, 1, 2]); + check({a: 1, b: {x: 2, y: 3}, c: 4, d: {}}, [1, 2, 3, 4, 0]); + check({a: 534, b: {x: 12345, y: 54321}, c: 321, d: {}}, [150, 4, 185, 96, 177, 168, 3, 193, 2, 0]); }); -it('message bool', function() { +it('message bool', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeBoolMessage(i)), Buffer(o)); assert.deepEqual(schema.decodeBoolMessage(new Uint8Array(o)), i); } check({}, [0]); - check({x: false}, [1, 0, 0]); - check({x: true}, [1, 1, 0]); + check({ x: false }, [1, 0, 0]); + check({ x: true }, [1, 1, 0]); }); -it('message byte', function() { +it('message byte', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeByteMessage(i)), Buffer(o)); assert.deepEqual(schema.decodeByteMessage(new Uint8Array(o)), i); } check({}, [0]); - check({x: 234}, [1, 234, 0]); + check({ x: 234 }, [1, 234, 0]); }); -it('message uint', function() { +it('message uint', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeUintMessage(i)), Buffer(o)); assert.deepEqual(schema.decodeUintMessage(new Uint8Array(o)), i); } check({}, [0]); - check({x: 12345678}, [1, 206, 194, 241, 5, 0]); + check({ x: 12345678 }, [1, 206, 194, 241, 5, 0]); }); -it('message int', function() { +it('message int', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeIntMessage(i)), Buffer(o)); assert.deepEqual(schema.decodeIntMessage(new Uint8Array(o)), i); } check({}, [0]); - check({x: 12345678}, [1, 156, 133, 227, 11, 0]); + check({ x: 12345678 }, [1, 156, 133, 227, 11, 0]); }); -it('message float', function() { +it('message float', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeFloatMessage(i)), Buffer(o)); assert.deepEqual(schema.decodeFloatMessage(new Uint8Array(o)), i); } check({}, [0]); - check({x: 3.1415927410125732}, [1, 128, 182, 31, 146, 0]); + check({ x: 3.1415927410125732 }, [1, 128, 182, 31, 146, 0]); }); -it('message string', function() { +it('message string', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeStringMessage(i)), Buffer(o)); assert.deepEqual(schema.decodeStringMessage(new Uint8Array(o)), i); } check({}, [0]); - check({x: ''}, [1, 0, 0]); - check({x: '🙉🙈🙊'}, [1, 240, 159, 153, 137, 240, 159, 153, 136, 240, 159, 153, 138, 0, 0]); + check({ x: '' }, [1, 0, 0]); + check({ x: '🙉🙈🙊' }, [1, 240, 159, 153, 137, 240, 159, 153, 136, 240, 159, 153, 138, 0, 0]); }); -it('message compound', function() { +it('message map', function () { + function check(i, o) { + assert.deepEqual(Buffer(schema.encodeMapMessage(i)), Buffer(o)) + assert.deepEqual(schema.decodeMapMessage(new Uint8Array(o)), i) + } + + check({}, [0]) + check({ x: { 'abc': 5, 'def': 10 } }, [1, 2, 97, 98, 99, 0, 10, 100, 101, 102, 0, 20, 0]) +}) + +it('message compound', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeCompoundMessage(i)), Buffer(o)); assert.deepEqual(schema.decodeCompoundMessage(new Uint8Array(o)), i); } check({}, [0]); - check({x: 123}, [1, 123, 0]); - check({y: 234}, [2, 234, 1, 0]); - check({x: 123, y: 234}, [1, 123, 2, 234, 1, 0]); - check({y: 234, x: 123}, [1, 123, 2, 234, 1, 0]); + check({ x: 123 }, [1, 123, 0]); + check({ y: 234 }, [2, 234, 1, 0]); + check({ x: 123, y: 234 }, [1, 123, 2, 234, 1, 0]); + check({ y: 234, x: 123 }, [1, 123, 2, 234, 1, 0]); }); -it('message nested', function() { +it('message nested', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeNestedMessage(i)), Buffer(o)); assert.deepEqual(schema.decodeNestedMessage(new Uint8Array(o)), i); } check({}, [0]); - check({a: 123, c: 234}, [1, 123, 3, 234, 1, 0]); - check({b: {x: 5, y: 6}}, [2, 1, 5, 2, 6, 0, 0]); - check({b: {x: 5}, c: 123}, [2, 1, 5, 0, 3, 123, 0]); - check({c: 123, b: {x: 5, y: 6}, a: 234}, [1, 234, 1, 2, 1, 5, 2, 6, 0, 3, 123, 0]); + check({ a: 123, c: 234 }, [1, 123, 3, 234, 1, 0]); + check({ b: { x: 5, y: 6 } }, [2, 1, 5, 2, 6, 0, 0]); + check({ b: { x: 5 }, c: 123 }, [2, 1, 5, 0, 3, 123, 0]); + check({ c: 123, b: {x: 5, y: 6}, a: 234, d: {'a': {x: 1, y: 2}}}, [1, 234, 1, 2, 1, 5, 2, 6, 0, 3, 123, 4, 1, 97, 0, 1, 1, 2, 2, 0, 0]); }); -it('struct bool array', function() { +it('struct bool array', function () { function check(i, o) { - assert.deepEqual(Buffer(schema.encodeBoolArrayStruct({x: i})), Buffer(o)); - assert.deepEqual(schema.decodeBoolArrayStruct(new Uint8Array(o)), {x: i}); + assert.deepEqual(Buffer(schema.encodeBoolArrayStruct({ x: i })), Buffer(o)); + assert.deepEqual(schema.decodeBoolArrayStruct(new Uint8Array(o)), { x: i }); } check([], [0]); check([true, false], [2, 1, 0]); }); -it('message bool array', function() { +it('message bool array', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeBoolArrayMessage(i)), Buffer(o)); assert.deepEqual(schema.decodeBoolArrayMessage(new Uint8Array(o)), i); } check({}, [0]); - check({x: []}, [1, 0, 0]); - check({x: [true, false]}, [1, 2, 1, 0, 0]); + check({ x: [] }, [1, 0, 0]); + check({ x: [true, false] }, [1, 2, 1, 0, 0]); }); -it('recursive message', function() { +it('recursive message', function () { function check(i, o) { assert.deepEqual(Buffer(schema.encodeRecursiveMessage(i)), Buffer(o)); assert.deepEqual(schema.decodeRecursiveMessage(new Uint8Array(o)), i); } check({}, [0]); - check({x: {}}, [1, 0, 0]); - check({x: {x: {}}}, [1, 1, 0, 0, 0]); + check({ x: {} }, [1, 0, 0]); + check({ x: { x: {} } }, [1, 1, 0, 0, 0]); }); -it('binary schema', function() { +it('binary schema', function () { var compiledSchema = kiwi.compileSchema(kiwi.encodeBinarySchema(schemaText)); function check(message) { @@ -258,15 +268,15 @@ it('binary schema', function() { Buffer(compiledSchema.encodeNestedMessage(message))); } - check({a: 1, c: 4}); - check({a: 1, b: {}, c: 4}); - check({a: 1, b: {x: 2, y: 3}, c: 4}); + check({ a: 1, c: 4 }); + check({ a: 1, b: {}, c: 4 }); + check({ a: 1, b: { x: 2, y: 3 }, c: 4 }); }); var largeSchemaText = fs.readFileSync(__dirname + '/test-schema-large.kiwi', 'utf8'); var largeSchema = kiwi.compileSchema(largeSchemaText); -it('struct with many fields', function() { +it('struct with many fields', function () { var object = {}; for (var i = 0; i < 130; i++) object['f' + i] = i; @@ -274,7 +284,7 @@ it('struct with many fields', function() { assert.deepEqual(object, largeSchema.decodeStruct(encoded)); }); -it('message with many fields', function() { +it('message with many fields', function () { var object = {}; for (var i = 0; i < 130; i++) object['f' + i] = i; @@ -282,21 +292,21 @@ it('message with many fields', function() { assert.deepEqual(object, largeSchema.decodeMessage(encoded)); }); -it('message with deprecated fields', function() { +it('message with deprecated fields', function () { var nonDeprecated = { a: 1, b: 2, c: [3, 4, 5], d: [6, 7, 8], - e: {x: 123}, - f: {x: 234}, + e: { x: 123 }, + f: { x: 234 }, g: 9, }; var deprecated = { a: 1, c: [3, 4, 5], - e: {x: 123}, + e: { x: 123 }, g: 9, }; diff --git a/test/test.sh b/test/test.sh index 0d50430..e457085 100755 --- a/test/test.sh +++ b/test/test.sh @@ -6,23 +6,23 @@ node ../cli.js --schema ./test-schema.kiwi --js ./test-schema.js node ../cli.js --schema ./test-schema.kiwi --ts ./test-schema.ts -node ../cli.js --schema ./test-schema.kiwi --cpp ./test-schema.h && \ - node ../cli.js --schema ./test1-schema.kiwi --cpp ./test1-schema.h --binary ./test1-schema.bkiwi && \ - node ../cli.js --schema ./test2-schema.kiwi --cpp ./test2-schema.h --binary ./test2-schema.bkiwi && \ - node ../cli.js --schema ./test-schema-large.kiwi --cpp ./test-schema-large.h && \ - c++ ./test.cpp -std=c++11 -I.. && \ - ./a.out && \ - rm ./a.out +# node ../cli.js --schema ./test-schema.kiwi --cpp ./test-schema.h && \ +# node ../cli.js --schema ./test1-schema.kiwi --cpp ./test1-schema.h --binary ./test1-schema.bkiwi && \ +# node ../cli.js --schema ./test2-schema.kiwi --cpp ./test2-schema.h --binary ./test2-schema.bkiwi && \ +# node ../cli.js --schema ./test-schema-large.kiwi --cpp ./test-schema-large.h && \ +# c++ ./test.cpp -std=c++11 -I.. && \ +# ./a.out && \ +# rm ./a.out -node ../cli.js --schema ./test-schema.kiwi --callback-cpp ./test-schema-callback.h && \ - c++ ./test-callback.cpp -std=c++11 -I.. && \ - ./a.out && \ - rm ./a.out +# node ../cli.js --schema ./test-schema.kiwi --callback-cpp ./test-schema-callback.h && \ +# c++ ./test-callback.cpp -std=c++11 -I.. && \ +# ./a.out && \ +# rm ./a.out -node ../cli.js --schema ./test-schema.kiwi --skew ./test-schema.sk && \ - node ../cli.js --schema ./test1-schema.kiwi --skew ./test1-schema.sk && \ - node ../cli.js --schema ./test2-schema.kiwi --skew ./test2-schema.sk && \ - node ../cli.js --schema ./test-schema-large.kiwi --skew ./test-schema-large.sk && \ - ../node_modules/.bin/skewc --output-file=temp.js ../kiwi.sk ../typedarray.sk ./test-schema.sk ./test1-schema.sk ./test2-schema.sk ./test-schema-large.sk ./test.sk && \ - node ../node_modules/mocha/bin/mocha temp.js && \ - rm temp.js +# node ../cli.js --schema ./test-schema.kiwi --skew ./test-schema.sk && \ +# node ../cli.js --schema ./test1-schema.kiwi --skew ./test1-schema.sk && \ +# node ../cli.js --schema ./test2-schema.kiwi --skew ./test2-schema.sk && \ +# node ../cli.js --schema ./test-schema-large.kiwi --skew ./test-schema-large.sk && \ +# ../node_modules/.bin/skewc --output-file=temp.js ../kiwi.sk ../typedarray.sk ./test-schema.sk ./test1-schema.sk ./test2-schema.sk ./test-schema-large.sk ./test.sk && \ +# node ../node_modules/mocha/bin/mocha temp.js && \ +# rm temp.js