From 9aee64b03b157168cdc5d0bd11e899b87ced0b4c Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Sun, 29 Oct 2017 17:09:10 +0800 Subject: [PATCH 01/20] added support to data type `undefined`; added typescript typing; added contributors in package.json; increased npm version; --- .gitignore | 2 ++ api.d.ts | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ decode.js | 2 ++ encode.js | 4 +++ package.json | 52 +++++++++++++++++++----------- 5 files changed, 130 insertions(+), 19 deletions(-) create mode 100644 api.d.ts diff --git a/.gitignore b/.gitignore index df3b8ef..9d5cfed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .*.swp /node_modules +.idea/ +yarn.lock diff --git a/api.d.ts b/api.d.ts new file mode 100644 index 0000000..f210b68 --- /dev/null +++ b/api.d.ts @@ -0,0 +1,89 @@ +type Buffer = Uint8Array | ArrayBuffer; +type ByteArray = any[] + +class Encoder { + encode(term): ByteArray; + + undefined(x): ByteArray; + + null(x): ByteArray; + + number(x): ByteArray; + + int(x): ByteArray; + + array(x): ByteArray; + + object(x): ByteArray; + + atom(x): ByteArray; + + tuple(x): ByteArray; + + buffer(x): ByteArray; + + string(x): ByteArray; + + boolean(x): ByteArray; +} + +interface encode { + (term): Buffer; + + Encoder: Encoder; + + optlist_to_term(opts): any[]; + + optlist_to_binary(opts): Buffer; +} + +class Decoder { + constructor(bin: ArrayBuffer) + + decode(): any; + + SMALL_INTEGER(): any; + + INTEGER(): any; + + STRING(): any; + + ATOM(): any; + + LIST(): any; + + LARGE_TUPLE(): any; + + SMALL_TUPLE(): any; + + BINARY(): any; +} + +interface decode { + (term): any; + + Decoder: Decoder +} + +interface iolist { + to_buffer(list): Buffer + + size(list): number; +} + +declare let encode: encode; +declare let decode: decode; +declare let iolist: iolist; + +export default { + term_to_binary: encode + , optlist_to_term: encode.optlist_to_term + , optlist_to_binary: encode.optlist_to_binary + + , binary_to_term: decode + + , iolist_to_binary: iolist.to_buffer + , iolist_to_buffer: iolist.to_buffer + , iolist_size: iolist.size +} + diff --git a/decode.js b/decode.js index d7ea4cf..2028074 100644 --- a/decode.js +++ b/decode.js @@ -95,6 +95,8 @@ Decoder.prototype.ATOM = function() { term = true else if (term == 'nil') term = null + else if (term == 'undefined') + term = undefined else term = {a:term} diff --git a/encode.js b/encode.js index c3f83a0..3c67fe9 100644 --- a/encode.js +++ b/encode.js @@ -33,6 +33,10 @@ Encoder.prototype.encode = function(term) { return encoder.apply(this, [term]) } +Encoder.prototype.undefined = function(x) { + return this.atom('undefined') +} + Encoder.prototype.null = function(x) { return this.atom('nil') } diff --git a/package.json b/package.json index e6a32ba..05d0f98 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,34 @@ -{ "name": "erlang" -, "version": "1.0.1" -, "author": { "name": "Jason Smith", "email": "jason.h.smith@gmail.com" } -, "description": "Erlang interoperability with Javascript" -, "homepage": "http://github.com/iriscouch/erlang.js" -, "repository": { "type": "git" - , "url": "git://github.com/iriscouch/erlang.js" } -, "engines": [ "node" ] -, "main": "./api.js" -, "scripts": { "test" : "tap test/" - } - -, "dependencies": { "debug": "~1.0.4" - } - -, "devDependencies": { "tap": "~0.4.8" - , "async": "~0.2.10" - , "traceback": "~0.3.1" - } +{ + "name": "erlang", + "version": "1.1.0", + "author": "Jason Smith ", + "contributors": [ + "Beeno Tung " + ], + "description": "Erlang interoperability with Javascript", + "homepage": "http://github.com/beenotung/erlang.js", + "repository": { + "type": "git", + "url": "git://github.com/beenotung/erlang.js.git" + }, + "bugs": { + "url": "https://github.com/beenotung/erlang.js/issues" + }, + "main": "./api.js", + "types": "./api.d.ts", + "scripts": { + "test": "tap test/" + }, + "dependencies": { + "debug": "~1.0.4" + }, + "devDependencies": { + "tap": "~0.4.8", + "async": "~0.2.10", + "traceback": "~0.3.1" + }, + "directories": { + "test": "test" + }, + "license": "ISC" } From c799167a3b0267c5ea28f100c2c040072c073906 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Sun, 29 Oct 2017 17:12:00 +0800 Subject: [PATCH 02/20] renamed on npm from erlang to @beenotung/erlang --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 05d0f98..b1515ae 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "erlang", + "name": "@beenotung/erlang", "version": "1.1.0", "author": "Jason Smith ", "contributors": [ From 0278974e198cd7be96e74f6b48d52e4146a10030 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Sun, 29 Oct 2017 17:22:37 +0800 Subject: [PATCH 03/20] added tslint and fixed for tslint; --- api.d.ts | 4 +- package.json | 9 ++-- tsconfig.json | 30 +++++++++++ tslint.json | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 tsconfig.json create mode 100644 tslint.json diff --git a/api.d.ts b/api.d.ts index f210b68..7594fc8 100644 --- a/api.d.ts +++ b/api.d.ts @@ -1,7 +1,7 @@ type Buffer = Uint8Array | ArrayBuffer; type ByteArray = any[] -class Encoder { +declare class Encoder { encode(term): ByteArray; undefined(x): ByteArray; @@ -37,7 +37,7 @@ interface encode { optlist_to_binary(opts): Buffer; } -class Decoder { +declare class Decoder { constructor(bin: ArrayBuffer) decode(): any; diff --git a/package.json b/package.json index b1515ae..8cbe8c8 100644 --- a/package.json +++ b/package.json @@ -17,15 +17,18 @@ "main": "./api.js", "types": "./api.d.ts", "scripts": { - "test": "tap test/" + "lint": "tslint -p .", + "test": "npm run lint && tap test/" }, "dependencies": { "debug": "~1.0.4" }, "devDependencies": { - "tap": "~0.4.8", "async": "~0.2.10", - "traceback": "~0.3.1" + "tap": "~0.4.8", + "traceback": "~0.3.1", + "tslint": "^5.8.0", + "typescript": "^2.5.3" }, "directories": { "test": "test" diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..90d7186 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "declaration": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "noImplicitThis": true, + "skipLibCheck": true, + "lib": [ + "dom", + "es2015" + ], + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "target": "es5", + "outDir": "build" + }, + "include": [ + "api.d.ts" + ], + "exclude": [ + "node_modules" + ], + "compileOnSave": false, + "atom": { + "rewriteTsconfig": false + } +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..cedb669 --- /dev/null +++ b/tslint.json @@ -0,0 +1,136 @@ +{ + "rules": { + "space-before-function-paren": false, + "callable-types": true, + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "eofline": true, + "forin": true, + "import-blacklist": [ + true, + "rxjs" + ], + "import-spacing": true, + "indent": [ + true, + "spaces" + ], + "interface-over-type-literal": false, + "label-position": true, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": "instance-sandwich" + }, + "static-before-instance", + "variables-before-functions" + ], + "no-arg": true, + "no-bitwise": false, + "no-console": [ + false, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-variable": true, + "no-unused-variable": [ + true + ], + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-inferrable-types": false, + "no-shadowed-variable": false, + "no-string-literal": false, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "prefer-const": true, + "quotemark": [ + true, + "double", + "avoid-escape" + ], + "radix": true, + "semicolon": [ + true, + "always", + "ignore-interfaces" + ], + "triple-equals": false, + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "typeof-compare": true, + "unified-signatures": true, + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + "directive-selector": [ + true, + "attribute", + "", + "camelCase" + ], + "component-selector": [ + true, + "element", + "", + "kebab-case" + ], + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": true, + "component-class-suffix": false, + "directive-class-suffix": true, + "no-access-missing-member": true, + "templates-use-public": true, + "invoke-injectable": true + }, + "rulesDirectory": [ + "node_modules/codelyzer", + "node_modules/tslint-eslint-rules/dist/rules" + ] +} From 15d6311d515ce165ea0975cd93cb93550d5df38b Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Sun, 29 Oct 2017 17:22:46 +0800 Subject: [PATCH 04/20] 1.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8cbe8c8..772fbfb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beenotung/erlang", - "version": "1.1.0", + "version": "1.1.1", "author": "Jason Smith ", "contributors": [ "Beeno Tung " From 10d8392a8f5f6425c394b497b4f3e9a9032a2050 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Sun, 29 Oct 2017 17:39:06 +0800 Subject: [PATCH 05/20] fixed export default setting --- api.d.ts | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/api.d.ts b/api.d.ts index 7594fc8..3bc1563 100644 --- a/api.d.ts +++ b/api.d.ts @@ -28,13 +28,13 @@ declare class Encoder { } interface encode { - (term): Buffer; + (term: any): Buffer; Encoder: Encoder; - optlist_to_term(opts): any[]; + optlist_to_term(opts: any[]): any[]; - optlist_to_binary(opts): Buffer; + optlist_to_binary(opts: any[]): Buffer; } declare class Decoder { @@ -60,7 +60,7 @@ declare class Decoder { } interface decode { - (term): any; + (term: Buffer): any; Decoder: Decoder } @@ -75,15 +75,19 @@ declare let encode: encode; declare let decode: decode; declare let iolist: iolist; -export default { - term_to_binary: encode - , optlist_to_term: encode.optlist_to_term - , optlist_to_binary: encode.optlist_to_binary +export function term_to_binary(term: any): Buffer; - , binary_to_term: decode +export function optlist_to_term(opts: any[]): any[]; - , iolist_to_binary: iolist.to_buffer - , iolist_to_buffer: iolist.to_buffer - , iolist_size: iolist.size -} +export function optlist_to_binary(opts: any[]): Buffer; + + +export function binary_to_term(term: Buffer): any; + + +export function iolist_to_binary(list): Buffer; + +export function iolist_to_buffer(list): Buffer; + +export function iolist_size(list): number; From b1cb6274dd0775b20fcb1b2b575ef910ae6b8420 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Sun, 29 Oct 2017 17:39:14 +0800 Subject: [PATCH 06/20] 1.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 772fbfb..4c9177e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beenotung/erlang", - "version": "1.1.1", + "version": "1.1.2", "author": "Jason Smith ", "contributors": [ "Beeno Tung " From d6a13e7b0ff801946c91ed661a5070f307006bb6 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 12:15:50 +0800 Subject: [PATCH 07/20] added support to javascript object (hashmap <--> optlist) --- .gitignore | 1 + .npmignore | 5 +++++ decode.js | 4 ++++ encode.js | 8 ++++++-- package.json | 3 +++ test/object.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ utils.ts | 37 +++++++++++++++++++++++++++++++++++++ 7 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 .npmignore create mode 100644 test/object.js create mode 100644 utils.ts diff --git a/.gitignore b/.gitignore index 9d5cfed..2e3f88f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /node_modules .idea/ yarn.lock +utils.js \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..f2880f9 --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +.*.swp +/node_modules +.idea/ +yarn.lock +utils.ts \ No newline at end of file diff --git a/decode.js b/decode.js index 2028074..7741425 100644 --- a/decode.js +++ b/decode.js @@ -20,6 +20,7 @@ var util = require('util') var debug = require('debug')('erlang:decode') var lib = require('./lib.js') +var utils = require('./utils.js') function binary_to_term(term) { if (!Buffer.isBuffer(term)) @@ -142,6 +143,9 @@ Decoder.prototype.SMALL_TUPLE = function() { this.bin = body.bin debug('Small tuple %j', this.bin) + if (term[0] === utils.map_optlist_tag) { + return utils.optlist_to_object(term); + } return {t:term} } diff --git a/encode.js b/encode.js index 3c67fe9..5588165 100644 --- a/encode.js +++ b/encode.js @@ -18,6 +18,7 @@ module.exports.optlist_to_binary = optlist_to_binary var util = require('util') var lib = require('./lib.js') +var utils = require('./utils.js') var typeOf = lib.typeOf function Encoder () { @@ -78,8 +79,11 @@ Encoder.prototype.array = function(x) { Encoder.prototype.object = function(x) { var keys = Object.keys(x) - if(keys.length !== 1) - throw new Error("Don't know how to process: " + util.inspect(x)) + if(keys.length !== 1){ + // throw new Error("Don't know how to process: " + util.inspect(x)) + var res = utils.object_to_optlist(x); + return this.encode(res); + } var tag = keys[0] var val = x[tag] diff --git a/package.json b/package.json index 4c9177e..1cf8d10 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,9 @@ "types": "./api.d.ts", "scripts": { "lint": "tslint -p .", + "build": "tsc utils.ts", + "pretest": "npm run build", + "prepublishOnly": "npm test", "test": "npm run lint && tap test/" }, "dependencies": { diff --git a/test/object.js b/test/object.js new file mode 100644 index 0000000..84bfd5e --- /dev/null +++ b/test/object.js @@ -0,0 +1,45 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var tap = require('tap') +var test = tap.test +var util = require('util') + +var package = require('../package.json') +var api = require('../' + package.main) +var lib = require('../lib.js') + +test('Simple object codec', function(t) { + var o = {username:'user',password:'123'}; + + var bin = api.term_to_binary(o) + t.equal(bin[0], lib.VERSION_MAGIC, 'Encoded tuple begins with the magic number') + t.equal(bin[1], lib.tags.SMALL_TUPLE, 'Object is encoded as a SMALL_TUPLE') + + var dec = api.binary_to_term(bin) + t.equal(JSON.stringify(o), JSON.stringify(dec), 'Decoded is same as original data') + + t.end() +}) + +test('Deep object codec', function(t) { + var o = {username:'user',password:'123', logs:[{time:123}, {time:234}]}; + + var bin = api.term_to_binary(o) + t.equal(bin[0], lib.VERSION_MAGIC, 'Encoded tuple begins with the magic number') + t.equal(bin[1], lib.tags.SMALL_TUPLE, 'Object is encoded as a SMALL_TUPLE') + + var dec = api.binary_to_term(bin) + t.equal(JSON.stringify(o), JSON.stringify(dec), 'Decoded is same as original data') + + t.end() +}) diff --git a/utils.ts b/utils.ts new file mode 100644 index 0000000..5b5706f --- /dev/null +++ b/utils.ts @@ -0,0 +1,37 @@ +export const map_optlist_tag = 'map_optlist'; + +const map_object = x => { + return typeof x === "object" && x !== null && !Array.isArray(x) + ? object_to_optlist(x) + : Array.isArray(x) + ? x.map(x => map_object(x)) + : x; +}; + +/** + * object -> optlist + * */ +export function object_to_optlist(o: any): any { + const vs = Object.keys(o) + .map(x => ({t: [x, map_object(o[x])]})); + return {t: [map_optlist_tag, vs]}; +} + +/** + * optlist -> object + * */ +export function optlist_to_object(term: [any, any]): any { + if (!term) { + throw new TypeError("argument should be a tuple"); + } + if (!Array.isArray(term) || term.length !== 2) { + throw new TypeError("argument should be a tuple"); + } + if (term[0] !== map_optlist_tag || !Array.isArray(term[1])) { + throw new TypeError("argument should be optlist"); + } + const vs = term[1]; + const o = {} as any; + vs.forEach(tuple => o[tuple.t[0]] = tuple.t[1]); + return o; +} From 491d420ec32e31297256f38cbd502fe9c3a2a298 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 12:15:58 +0800 Subject: [PATCH 08/20] 1.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1cf8d10..c4d16e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beenotung/erlang", - "version": "1.1.2", + "version": "1.2.0", "author": "Jason Smith ", "contributors": [ "Beeno Tung " From 1effaa84ff86f63d5896027d717fa5dadd0893d3 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 14:26:49 +0800 Subject: [PATCH 09/20] renamed utils to object --- .gitignore | 2 +- .npmignore | 2 +- decode.js | 7 +++---- encode.js | 4 ++-- utils.ts => object.ts | 0 5 files changed, 7 insertions(+), 8 deletions(-) rename utils.ts => object.ts (100%) diff --git a/.gitignore b/.gitignore index 2e3f88f..67cb699 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ /node_modules .idea/ yarn.lock -utils.js \ No newline at end of file +object.js \ No newline at end of file diff --git a/.npmignore b/.npmignore index f2880f9..2c1384d 100644 --- a/.npmignore +++ b/.npmignore @@ -2,4 +2,4 @@ /node_modules .idea/ yarn.lock -utils.ts \ No newline at end of file +object.ts \ No newline at end of file diff --git a/decode.js b/decode.js index 7741425..44eafed 100644 --- a/decode.js +++ b/decode.js @@ -16,11 +16,10 @@ module.exports.Decoder = Decoder //module.exports.term_to_optlist = term_to_optlist //module.exports.binary_to_optlist = binary_to_optlist -var util = require('util') var debug = require('debug')('erlang:decode') var lib = require('./lib.js') -var utils = require('./utils.js') +var object = require('./object.js') function binary_to_term(term) { if (!Buffer.isBuffer(term)) @@ -143,8 +142,8 @@ Decoder.prototype.SMALL_TUPLE = function() { this.bin = body.bin debug('Small tuple %j', this.bin) - if (term[0] === utils.map_optlist_tag) { - return utils.optlist_to_object(term); + if (term[0] === object.map_optlist_tag) { + return object.optlist_to_object(term); } return {t:term} } diff --git a/encode.js b/encode.js index 5588165..04c7f03 100644 --- a/encode.js +++ b/encode.js @@ -18,7 +18,7 @@ module.exports.optlist_to_binary = optlist_to_binary var util = require('util') var lib = require('./lib.js') -var utils = require('./utils.js') +var object = require('./object.js') var typeOf = lib.typeOf function Encoder () { @@ -81,7 +81,7 @@ Encoder.prototype.object = function(x) { var keys = Object.keys(x) if(keys.length !== 1){ // throw new Error("Don't know how to process: " + util.inspect(x)) - var res = utils.object_to_optlist(x); + var res = object.object_to_optlist(x); return this.encode(res); } diff --git a/utils.ts b/object.ts similarity index 100% rename from utils.ts rename to object.ts From 790adbd4e808e43578e3713e173b9888083fd680 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 17:09:13 +0800 Subject: [PATCH 10/20] support three style of object encoding: - tagged_optlist (default, the previous one) - optlist - list --- .editorconfig | 25 +++++++++++++++ .gitignore | 2 +- object.ts | 85 ++++++++++++++++++++++++++++++++++++++++---------- package.json | 13 ++++++-- test/object.js | 24 ++++++++------ 5 files changed, 120 insertions(+), 29 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8f500ad --- /dev/null +++ b/.editorconfig @@ -0,0 +1,25 @@ +# EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs +# http://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 2 + +# We recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.xml] +indent_style = space +indent_size = 4 + +[*.json] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore index 67cb699..b6e9bad 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ /node_modules .idea/ yarn.lock -object.js \ No newline at end of file +object.js diff --git a/object.ts b/object.ts index 5b5706f..93712e3 100644 --- a/object.ts +++ b/object.ts @@ -1,4 +1,9 @@ -export const map_optlist_tag = 'map_optlist'; +export const map_optlist_tag = "map_optlist"; +export const map_list_tag = "map_list"; +import * as util from "util"; + +export type format = "tagged_optlist" | "optlist" | "list" ; +const default_format: format = "tagged_optlist"; const map_object = x => { return typeof x === "object" && x !== null && !Array.isArray(x) @@ -8,30 +13,78 @@ const map_object = x => { : x; }; +export function getTupleArray(term): any[] { + if (!term) { + throw new TypeError("argument is not tuple: " + util.inspect(term)); + } + const xs = term.t || term.tuple; + if (Array.isArray(xs)) { + return xs; + } + throw new TypeError("argument is not tuple: " + util.inspect(term)); +} + /** * object -> optlist * */ -export function object_to_optlist(o: any): any { - const vs = Object.keys(o) - .map(x => ({t: [x, map_object(o[x])]})); - return {t: [map_optlist_tag, vs]}; +export function object_to_optlist(o: any, format: format = default_format): any { + switch (format) { + case "tagged_optlist": + case "optlist": { + const vs = Object.keys(o) + .map(x => ({t: [x, map_object(o[x])]})); + return format === "tagged_optlist" + ? {t: [map_optlist_tag, vs]} + : vs; + } + case "list": { + const vs = []; + Object.keys(o) + .forEach(x => vs.push(x, o[x])); + return {t: [map_list_tag, vs]}; + } + default: + throw new TypeError("unsupported format: " + util.inspect(format)); + } } /** * optlist -> object * */ -export function optlist_to_object(term: [any, any]): any { +export function optlist_to_object(term: [any, any], format: format = default_format): any { if (!term) { - throw new TypeError("argument should be a tuple"); - } - if (!Array.isArray(term) || term.length !== 2) { - throw new TypeError("argument should be a tuple"); + throw new TypeError("unsupported term: " + util.inspect(term)); } - if (term[0] !== map_optlist_tag || !Array.isArray(term[1])) { - throw new TypeError("argument should be optlist"); + switch (format) { + case "tagged_optlist": + case "optlist": { + if (format === "tagged_optlist") { + if (term.length !== 2) { + throw new Error("term should be tuple of 2 elements: " + util.inspect(term)); + } + term = term[1]; + } + const o = {}; + term.forEach(tuple => { + const xs = getTupleArray(tuple); + if (xs.length !== 2) { + throw new Error("tuple should be size of 2: " + util.inspect(tuple)); + } + o[xs[0]] = xs[1]; + }); + return o; + } + case "list": { + const o = {}; + if (term.length % 2 !== 0) { + throw new Error("invalid list, should be even number of element: " + util.inspect(term)); + } + for (let i = 0; i < term.length; i += 2) { + o[term[i]] = term[i + 1]; + } + return o; + } + default: + throw new TypeError("unsupported format: " + util.inspect(format)); } - const vs = term[1]; - const o = {} as any; - vs.forEach(tuple => o[tuple.t[0]] = tuple.t[1]); - return o; } diff --git a/package.json b/package.json index c4d16e8..42ad038 100644 --- a/package.json +++ b/package.json @@ -18,20 +18,27 @@ "types": "./api.d.ts", "scripts": { "lint": "tslint -p .", - "build": "tsc utils.ts", + "build": "tsc object.ts", "pretest": "npm run build", "prepublishOnly": "npm test", "test": "npm run lint && tap test/" }, "dependencies": { - "debug": "~1.0.4" + "debug": "~1.0.4", + "util": "^0.10.3" }, "devDependencies": { + "@angular/compiler": ">=4.0.0-beta", + "@angular/core": ">=4.0.0-beta", "async": "~0.2.10", + "codelyzer": "^3.2.2", + "rxjs": "^5.0.1", "tap": "~0.4.8", "traceback": "~0.3.1", "tslint": "^5.8.0", - "typescript": "^2.5.3" + "tslint-eslint-rules": "^4.1.1", + "typescript": "^2.5.3", + "zone.js": "^0.8.4" }, "directories": { "test": "test" diff --git a/test/object.js b/test/object.js index 84bfd5e..65d3e50 100644 --- a/test/object.js +++ b/test/object.js @@ -31,15 +31,21 @@ test('Simple object codec', function(t) { t.end() }) -test('Deep object codec', function(t) { - var o = {username:'user',password:'123', logs:[{time:123}, {time:234}]}; +var o = {username:'user',password:'123', logs:[{time:123}, {time:234}]}; - var bin = api.term_to_binary(o) - t.equal(bin[0], lib.VERSION_MAGIC, 'Encoded tuple begins with the magic number') - t.equal(bin[1], lib.tags.SMALL_TUPLE, 'Object is encoded as a SMALL_TUPLE') +function test_deep_object(format){ + test(`Deep object codec (${format})`, function(t){ + var bin = api.term_to_binary(o, format) + t.equal(bin[0], lib.VERSION_MAGIC, 'Encoded tuple begins with the magic number') + t.equal(bin[1], lib.tags.SMALL_TUPLE, 'Object is encoded as a SMALL_TUPLE') - var dec = api.binary_to_term(bin) - t.equal(JSON.stringify(o), JSON.stringify(dec), 'Decoded is same as original data') + var dec = api.binary_to_term(bin, format) + t.equal(JSON.stringify(o), JSON.stringify(dec), 'Decoded is same as original data') - t.end() -}) + t.end() + }) +} + +test_deep_object("map_optlist"); +test_deep_object("map_list"); +test_deep_object("util"); From a13471d32134a69a0a2c71634d64023457d0b1dd Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 17:09:23 +0800 Subject: [PATCH 11/20] 1.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 42ad038..ecf32da 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beenotung/erlang", - "version": "1.2.0", + "version": "1.3.0", "author": "Jason Smith ", "contributors": [ "Beeno Tung " From aa6d25fe73f7c574fe7d10d89c5b6c600875aa4d Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 17:28:26 +0800 Subject: [PATCH 12/20] tidy up api.d.ts for tslint --- api.d.ts | 74 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/api.d.ts b/api.d.ts index 3bc1563..7863ffb 100644 --- a/api.d.ts +++ b/api.d.ts @@ -1,79 +1,79 @@ type Buffer = Uint8Array | ArrayBuffer; -type ByteArray = any[] +type ByteArray = any[]; declare class Encoder { - encode(term): ByteArray; + encode(term): ByteArray; - undefined(x): ByteArray; + undefined(x): ByteArray; - null(x): ByteArray; + null(x): ByteArray; - number(x): ByteArray; + number(x): ByteArray; - int(x): ByteArray; + int(x): ByteArray; - array(x): ByteArray; + array(x): ByteArray; - object(x): ByteArray; + object(x): ByteArray; - atom(x): ByteArray; + atom(x): ByteArray; - tuple(x): ByteArray; + tuple(x): ByteArray; - buffer(x): ByteArray; + buffer(x): ByteArray; - string(x): ByteArray; + string(x): ByteArray; - boolean(x): ByteArray; + boolean(x): ByteArray; } -interface encode { - (term: any): Buffer; +interface Encode { + (term: any): Buffer; - Encoder: Encoder; + Encoder: Encoder; - optlist_to_term(opts: any[]): any[]; + optlist_to_term(opts: any[]): any[]; - optlist_to_binary(opts: any[]): Buffer; + optlist_to_binary(opts: any[]): Buffer; } declare class Decoder { - constructor(bin: ArrayBuffer) + constructor(bin: ArrayBuffer) - decode(): any; + decode(): any; - SMALL_INTEGER(): any; + SMALL_INTEGER(): any; - INTEGER(): any; + INTEGER(): any; - STRING(): any; + STRING(): any; - ATOM(): any; + ATOM(): any; - LIST(): any; + LIST(): any; - LARGE_TUPLE(): any; + LARGE_TUPLE(): any; - SMALL_TUPLE(): any; + SMALL_TUPLE(): any; - BINARY(): any; + BINARY(): any; } -interface decode { - (term: Buffer): any; +interface Decode { + (term: Buffer): any; - Decoder: Decoder + Decoder: Decoder } -interface iolist { - to_buffer(list): Buffer +interface IOList { + to_buffer(list): Buffer - size(list): number; + size(list): number; } -declare let encode: encode; -declare let decode: decode; -declare let iolist: iolist; +declare let encode: Encode; +declare let decode: Decode; +declare let iolist: IOList; export function term_to_binary(term: any): Buffer; From f2abecd2d8e1d2c1edaf5ee336408895abe712aa Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 17:28:50 +0800 Subject: [PATCH 13/20] added blob_to_term() --- .gitignore | 7 +++++++ .npmignore | 4 +++- api.d.ts | 1 + api.js | 3 +++ async.ts | 15 +++++++++++++++ package.json | 3 ++- tsconfig.json | 12 +++++------- 7 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 async.ts diff --git a/.gitignore b/.gitignore index b6e9bad..96e2e2b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,11 @@ /node_modules .idea/ yarn.lock + +object.d.ts object.js +object.js.map + +async.d.ts +async.js +async.js.map diff --git a/.npmignore b/.npmignore index 2c1384d..7deaa21 100644 --- a/.npmignore +++ b/.npmignore @@ -2,4 +2,6 @@ /node_modules .idea/ yarn.lock -object.ts \ No newline at end of file + +object.ts +async.ts diff --git a/api.d.ts b/api.d.ts index 7863ffb..7a10e4a 100644 --- a/api.d.ts +++ b/api.d.ts @@ -91,3 +91,4 @@ export function iolist_to_buffer(list): Buffer; export function iolist_size(list): number; +export function blob_to_term(blob: Blob): Promise; diff --git a/api.js b/api.js index e5a18da..80b0171 100644 --- a/api.js +++ b/api.js @@ -13,6 +13,7 @@ var encode = require('./encode.js') var decode = require('./decode.js') var iolist = require('./iolist.js') +var async = require('./async.js') module.exports = { term_to_binary : encode @@ -24,4 +25,6 @@ module.exports = , iolist_to_binary : iolist.to_buffer , iolist_to_buffer : iolist.to_buffer , iolist_size : iolist.size + + , blob_to_term : async.blob_to_term } diff --git a/async.ts b/async.ts new file mode 100644 index 0000000..6b068ab --- /dev/null +++ b/async.ts @@ -0,0 +1,15 @@ +import * as arraybufferToBuffer from "arraybuffer-to-buffer"; +import {binary_to_term} from "./api"; + +export async function blob_to_term(blob: Blob) { + return new Promise(((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + const buf = reader.result as ArrayBuffer; + const bs = arraybufferToBuffer(buf); + resolve(binary_to_term(bs)); + }; + reader.onerror = reject; + reader.readAsArrayBuffer(blob); + })); +} diff --git a/package.json b/package.json index ecf32da..9e04ba9 100644 --- a/package.json +++ b/package.json @@ -18,12 +18,13 @@ "types": "./api.d.ts", "scripts": { "lint": "tslint -p .", - "build": "tsc object.ts", + "build": "tsc", "pretest": "npm run build", "prepublishOnly": "npm test", "test": "npm run lint && tap test/" }, "dependencies": { + "arraybuffer-to-buffer": "^0.0.4", "debug": "~1.0.4", "util": "^0.10.3" }, diff --git a/tsconfig.json b/tsconfig.json index 90d7186..e0a78f6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,7 @@ { "compilerOptions": { - "allowJs": true, "allowSyntheticDefaultImports": true, - "declaration": false, + "declaration": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "noImplicitThis": true, @@ -11,14 +10,13 @@ "dom", "es2015" ], - "module": "es2015", "moduleResolution": "node", - "sourceMap": true, - "target": "es5", - "outDir": "build" + "sourceMap": true }, "include": [ - "api.d.ts" + "api.d.ts", + "object.ts", + "async.ts" ], "exclude": [ "node_modules" From 7226bbdbca8fc488e686521f1173b128e5471001 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 17:31:58 +0800 Subject: [PATCH 14/20] 1.4.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9e04ba9..7ecff02 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beenotung/erlang", - "version": "1.3.0", + "version": "1.4.0", "author": "Jason Smith ", "contributors": [ "Beeno Tung " From c97d4a4a87cc479d280b9c8ab31b987145abb743 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 18:30:54 +0800 Subject: [PATCH 15/20] fixed cyclic dependency bug in between api.js and async.js --- .gitignore | 2 -- api.d.ts | 1 + api.js | 6 +++++- async.ts | 5 ++--- tsconfig.json | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 96e2e2b..97a6931 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,8 @@ .idea/ yarn.lock -object.d.ts object.js object.js.map -async.d.ts async.js async.js.map diff --git a/api.d.ts b/api.d.ts index 7a10e4a..55da799 100644 --- a/api.d.ts +++ b/api.d.ts @@ -91,4 +91,5 @@ export function iolist_to_buffer(list): Buffer; export function iolist_size(list): number; + export function blob_to_term(blob: Blob): Promise; diff --git a/api.js b/api.js index 80b0171..389fcc5 100644 --- a/api.js +++ b/api.js @@ -15,6 +15,10 @@ var decode = require('./decode.js') var iolist = require('./iolist.js') var async = require('./async.js') +function blob_to_term(blob){ + return async.blob_to_buffer().then(decode); +} + module.exports = { term_to_binary : encode , optlist_to_term : encode.optlist_to_term @@ -26,5 +30,5 @@ module.exports = , iolist_to_buffer : iolist.to_buffer , iolist_size : iolist.size - , blob_to_term : async.blob_to_term + , blob_to_term : blob_to_term } diff --git a/async.ts b/async.ts index 6b068ab..54645e8 100644 --- a/async.ts +++ b/async.ts @@ -1,13 +1,12 @@ import * as arraybufferToBuffer from "arraybuffer-to-buffer"; -import {binary_to_term} from "./api"; -export async function blob_to_term(blob: Blob) { +export function blob_to_buffer(blob: Blob) { return new Promise(((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { const buf = reader.result as ArrayBuffer; const bs = arraybufferToBuffer(buf); - resolve(binary_to_term(bs)); + resolve(bs); }; reader.onerror = reject; reader.readAsArrayBuffer(blob); diff --git a/tsconfig.json b/tsconfig.json index e0a78f6..2c6a3fb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { + "allowJs": true, "allowSyntheticDefaultImports": true, - "declaration": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "noImplicitThis": true, From 9ddae74ff8c1712410b31e0a705148e8982bd41a Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 18:31:21 +0800 Subject: [PATCH 16/20] 1.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7ecff02..10b5b14 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beenotung/erlang", - "version": "1.4.0", + "version": "1.4.1", "author": "Jason Smith ", "contributors": [ "Beeno Tung " From d0a926b4bc6dfc5d9b728d72b4f0f975009d89cf Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 18:35:43 +0800 Subject: [PATCH 17/20] fixed bug in blob_to_term: missing argument passing --- api.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api.js b/api.js index 389fcc5..a7a249a 100644 --- a/api.js +++ b/api.js @@ -16,7 +16,8 @@ var iolist = require('./iolist.js') var async = require('./async.js') function blob_to_term(blob){ - return async.blob_to_buffer().then(decode); + return async.blob_to_buffer(blob) + .then(decode) } module.exports = From 4c32b353105a8312d2811517be6ec48f6887a6be Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 18:35:52 +0800 Subject: [PATCH 18/20] 1.4.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 10b5b14..3f78354 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beenotung/erlang", - "version": "1.4.1", + "version": "1.4.2", "author": "Jason Smith ", "contributors": [ "Beeno Tung " From 609b3500be1f92cde6d16f89d21abcfa4773a046 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 21:03:30 +0800 Subject: [PATCH 19/20] fixed deep object bug in object.js: object_to_optlist() and optlist_to_object() --- .gitignore | 2 ++ object.ts | 46 +++++++++++++++++++++++++++++++++++----------- package.json | 5 ++++- tsconfig.json | 2 ++ 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 97a6931..96e2e2b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,10 @@ .idea/ yarn.lock +object.d.ts object.js object.js.map +async.d.ts async.js async.js.map diff --git a/object.ts b/object.ts index 93712e3..86e9c6f 100644 --- a/object.ts +++ b/object.ts @@ -5,13 +5,7 @@ import * as util from "util"; export type format = "tagged_optlist" | "optlist" | "list" ; const default_format: format = "tagged_optlist"; -const map_object = x => { - return typeof x === "object" && x !== null && !Array.isArray(x) - ? object_to_optlist(x) - : Array.isArray(x) - ? x.map(x => map_object(x)) - : x; -}; +const isTuple = t => !!t && (Array.isArray(t.t) || Array.isArray(t.tuple)); export function getTupleArray(term): any[] { if (!term) { @@ -24,6 +18,36 @@ export function getTupleArray(term): any[] { throw new TypeError("argument is not tuple: " + util.inspect(term)); } +/** + * @param x: Javascript term + * @param format: type format + * */ +const map_object = (x, format) => { + return typeof x === "object" && x !== null && !Array.isArray(x) + ? object_to_optlist(x) + : Array.isArray(x) + ? x.map(x => map_object(x, format)) + : x; +}; + +/** + * @param x: Erlang term + * @param format: type format + * */ +const map_list = (x, format) => { + if (isTuple(x)) { + const t = x.t || x.tuple; + if (t.length === 2 && t[0] === map_list_tag) { + return optlist_to_object(t[1], format); + } + return {t: map_list(t, format)}; + } + if (Array.isArray(x)) { + return x.map(x => map_list(x, format)); + } + return x; +}; + /** * object -> optlist * */ @@ -32,7 +56,7 @@ export function object_to_optlist(o: any, format: format = default_format): any case "tagged_optlist": case "optlist": { const vs = Object.keys(o) - .map(x => ({t: [x, map_object(o[x])]})); + .map(x => ({t: [x, map_object(o[x], format)]})); return format === "tagged_optlist" ? {t: [map_optlist_tag, vs]} : vs; @@ -40,7 +64,7 @@ export function object_to_optlist(o: any, format: format = default_format): any case "list": { const vs = []; Object.keys(o) - .forEach(x => vs.push(x, o[x])); + .forEach(x => vs.push(x, map_object(o[x], format))); return {t: [map_list_tag, vs]}; } default: @@ -70,7 +94,7 @@ export function optlist_to_object(term: [any, any], format: format = default_for if (xs.length !== 2) { throw new Error("tuple should be size of 2: " + util.inspect(tuple)); } - o[xs[0]] = xs[1]; + o[xs[0]] = map_list(xs[1], format); }); return o; } @@ -80,7 +104,7 @@ export function optlist_to_object(term: [any, any], format: format = default_for throw new Error("invalid list, should be even number of element: " + util.inspect(term)); } for (let i = 0; i < term.length; i += 2) { - o[term[i]] = term[i + 1]; + o[term[i]] = map_list(term[i + 1], format); } return o; } diff --git a/package.json b/package.json index 3f78354..a337f33 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,9 @@ "types": "./api.d.ts", "scripts": { "lint": "tslint -p .", - "build": "tsc", + "build": "tsc && run-p buildType:*", + "buildType:async": "tsc -d async.ts || true", + "buildType:object": "tsc -d object.ts || true", "pretest": "npm run build", "prepublishOnly": "npm test", "test": "npm run lint && tap test/" @@ -33,6 +35,7 @@ "@angular/core": ">=4.0.0-beta", "async": "~0.2.10", "codelyzer": "^3.2.2", + "npm-run-all": "^4.1.1", "rxjs": "^5.0.1", "tap": "~0.4.8", "traceback": "~0.3.1", diff --git a/tsconfig.json b/tsconfig.json index 2c6a3fb..d06afe0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,8 @@ "dom", "es2015" ], + "target": "es5", + "module": "commonjs", "moduleResolution": "node", "sourceMap": true }, From 04714893c354f62c6226749ff9b6ceaadd1373c0 Mon Sep 17 00:00:00 2001 From: Beeno Tung Date: Mon, 30 Oct 2017 21:05:16 +0800 Subject: [PATCH 20/20] 1.4.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a337f33..4187fbb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@beenotung/erlang", - "version": "1.4.2", + "version": "1.4.3", "author": "Jason Smith ", "contributors": [ "Beeno Tung "