Skip to content

fixed for undefined and added Typescript support #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
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
25 changes: 25 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
.*.swp
/node_modules
.idea/
yarn.lock

object.d.ts
object.js
object.js.map

async.d.ts
async.js
async.js.map
7 changes: 7 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.*.swp
/node_modules
.idea/
yarn.lock

object.ts
async.ts
95 changes: 95 additions & 0 deletions api.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
type Buffer = Uint8Array | ArrayBuffer;
type ByteArray = any[];

declare 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: any): Buffer;

Encoder: Encoder;

optlist_to_term(opts: any[]): any[];

optlist_to_binary(opts: any[]): Buffer;
}

declare 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: Buffer): 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 function term_to_binary(term: any): Buffer;

export function optlist_to_term(opts: any[]): any[];

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;


export function blob_to_term(blob: Blob): Promise<any>;
8 changes: 8 additions & 0 deletions api.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
var encode = require('./encode.js')
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(blob)
.then(decode)
}

module.exports =
{ term_to_binary : encode
Expand All @@ -24,4 +30,6 @@ module.exports =
, iolist_to_binary : iolist.to_buffer
, iolist_to_buffer : iolist.to_buffer
, iolist_size : iolist.size

, blob_to_term : blob_to_term
}
14 changes: 14 additions & 0 deletions async.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as arraybufferToBuffer from "arraybuffer-to-buffer";

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(bs);
};
reader.onerror = reject;
reader.readAsArrayBuffer(blob);
}));
}
7 changes: 6 additions & 1 deletion decode.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +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 object = require('./object.js')

function binary_to_term(term) {
if (!Buffer.isBuffer(term))
Expand Down Expand Up @@ -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}

Expand Down Expand Up @@ -140,6 +142,9 @@ Decoder.prototype.SMALL_TUPLE = function() {
this.bin = body.bin

debug('Small tuple %j', this.bin)
if (term[0] === object.map_optlist_tag) {
return object.optlist_to_object(term);
}
return {t:term}
}

Expand Down
12 changes: 10 additions & 2 deletions encode.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module.exports.optlist_to_binary = optlist_to_binary

var util = require('util')
var lib = require('./lib.js')
var object = require('./object.js')
var typeOf = lib.typeOf

function Encoder () {
Expand All @@ -33,6 +34,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')
}
Expand Down Expand Up @@ -74,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 = object.object_to_optlist(x);
return this.encode(res);
}

var tag = keys[0]
var val = x[tag]
Expand Down
114 changes: 114 additions & 0 deletions object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
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 isTuple = t => !!t && (Array.isArray(t.t) || Array.isArray(t.tuple));

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));
}

/**
* @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
* */
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], format)]}));
return format === "tagged_optlist"
? {t: [map_optlist_tag, vs]}
: vs;
}
case "list": {
const vs = [];
Object.keys(o)
.forEach(x => vs.push(x, map_object(o[x], format)));
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], format: format = default_format): any {
if (!term) {
throw new TypeError("unsupported term: " + util.inspect(term));
}
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]] = map_list(xs[1], format);
});
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]] = map_list(term[i + 1], format);
}
return o;
}
default:
throw new TypeError("unsupported format: " + util.inspect(format));
}
}
Loading