UNPKG

scilla-data-parser

Version:

Scilla data types can be very verbose, making it hard for developers to use the state directly. The parser will help developers can make references and manipulation to state more easily.

622 lines (621 loc) 21.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var bn_js_1 = require("bn.js"); var customTypeMap = {}; function isObject(a) { return !!a && a.constructor === Object; } // Check a object is in scilla data format function isScillaData(node) { if (!isObject(node)) return false; if ('vname' in node && 'type' in node && 'value' in node) { return true; } return false; } //With the type field in scilla object, parse it to a tree. function parseTypeTree(strType) { var typeStack = []; var typeCtx = { type: '', childTypes: [] }; typeStack.push(typeCtx); var subType = ''; var i = 0; while (i < strType.length) { switch (strType[i]) { case '(': typeStack.push({ type: '', childTypes: [] }); if (typeCtx != null) { if (typeCtx.type == '') { typeCtx.type = subType; } typeCtx.childTypes.push(typeStack[typeStack.length - 1]); } subType = ''; typeCtx = typeStack[typeStack.length - 1]; break; case ')': if (typeStack.length == 0) throw new TypeError('JSON Parse: Too many closing brackets'); typeStack.pop(); if (subType.length > 0) { typeCtx.type = subType; } subType = ''; if (typeStack.length > 0) { typeCtx = typeStack[typeStack.length - 1]; } break; case ' ': case ' ': case '\n': break; default: subType += strType[i]; break; } ++i; } //In case root node has no child the node type is the input string. if (typeStack[0].childTypes.length == 0) { typeStack[0].type = strType; } return typeStack[0]; } //Convert INodeType to string type. function getTypeString(typeCtx) { var ret = typeCtx.type; if (typeCtx.childTypes.length == 0) { return ret; } ret += ' '; for (var i = 0; i < typeCtx.childTypes.length; i++) { ret += '('; ret += getTypeString(typeCtx.childTypes[i]); ret += ')'; if (i < typeCtx.childTypes.length - 1) { ret += ' '; } } return ret; } function toSimpleData(node) { var vname = node.vname; var type = node.type; var value = node.value; var ret = {}; var typeTree = parseTypeTree(type); switch (typeTree.type) { case 'Bool': ret[vname] = value['constructor'].toLowerCase() == 'true'; break; case 'String': case 'ByStr20': ret[vname] = value; break; case 'Option': if (typeTree.childTypes.length == 1) { if (value['constructor'] == 'Some') { var op = toSimpleData({ vname: 'op', type: getTypeString(typeTree.childTypes[0]), value: value.arguments[0], }); ret[vname] = op.op; } else { ret[vname] = ''; } } else { throw new TypeError('Invalid Option node'); } break; case 'Map': { ret[vname] = {}; var childs = value; if (Array.isArray(childs) && typeTree.childTypes.length == 2) { for (var _i = 0, childs_1 = childs; _i < childs_1.length; _i++) { var c = childs_1[_i]; var key = toSimpleData({ vname: 'key', type: getTypeString(typeTree.childTypes[0]), value: c.key, }); var val = toSimpleData({ vname: 'val', type: getTypeString(typeTree.childTypes[1]), value: c.val, }); ret[vname][key.key] = val.val; } } else { throw new TypeError('Invalid Map node'); } break; } case 'List': ret[vname] = []; var childs = value; if (Array.isArray(childs) && typeTree.childTypes.length == 1) { for (var _a = 0, childs_2 = childs; _a < childs_2.length; _a++) { var c = childs_2[_a]; var l = toSimpleData({ vname: 'l', type: getTypeString(typeTree.childTypes[0]), value: c, }); ret[vname].push(l.l); } } else { throw new TypeError('Invalid List node'); } break; case 'Pair': { ret[vname] = {}; var childs = value.arguments; if (Array.isArray(childs) && childs.length == 2 && typeTree.childTypes.length == 2) { var x = toSimpleData({ vname: 'x', type: getTypeString(typeTree.childTypes[0]), value: childs[0], }); var y = toSimpleData({ vname: 'y', type: getTypeString(typeTree.childTypes[1]), value: childs[1], }); ret[vname].x = x.x; ret[vname].y = y.y; } else { throw new TypeError('Invalid Pair node'); } break; } case 'Uint32': case 'Int32': ret[vname] = parseInt(value); break; case 'Uint64': case 'Uint128': case 'Uint256': case 'Int64': case 'Int128': case 'Uint256': case 'BNum': ret[vname] = new bn_js_1.BN(value); break; default: if (customTypeMap[typeTree.type] != null) { ret[vname] = {}; var rule = customTypeMap[typeTree.type]; var childs = value.arguments; if (Array.isArray(childs) && childs.length == rule.argtypes.length) { for (var k = 0; k < rule.argtypes.length; k++) { var rname = rule.argtypes[k]['vname']; var rtype = rule.argtypes[k]['type']; ret[vname][rname] = toSimpleData({ vname: rname, type: rtype, value: childs[k], })[rname]; } } else { throw new TypeError('Invalid Custom node'); } } else { throw new TypeError('Unhandle type ' + typeTree.type); } break; } return ret; } function toStraightData(node) { var vname = node.vname; var type = node.type; var value = node.value; var ret = { vname: node.vname, type: node.type, value: null, }; var typeTree = parseTypeTree(type); switch (typeTree.type) { case 'Bool': ret.value = value['constructor'].toLowerCase() == 'true'; break; case 'String': case 'ByStr20': ret.value = value; break; case 'Option': if (typeTree.childTypes.length == 1) { if (value['constructor'] == 'Some') { var op = toStraightData({ vname: 'op', type: getTypeString(typeTree.childTypes[0]), value: value.arguments[0], }); ret.value = op.value; } else { ret.value = ''; } } else { throw new TypeError('Invalid Option node'); } break; case 'Map': { ret.value = {}; var childs = value; if (Array.isArray(childs) && typeTree.childTypes.length == 2) { for (var _i = 0, childs_3 = childs; _i < childs_3.length; _i++) { var c = childs_3[_i]; var key = toStraightData({ vname: 'key', type: getTypeString(typeTree.childTypes[0]), value: c.key, }); var val = toStraightData({ vname: 'val', type: getTypeString(typeTree.childTypes[1]), value: c.val, }); ret.value[key.value] = val.value; } } else { throw new TypeError('Invalid Map node'); } break; } case 'List': ret.value = []; var childs = value; if (Array.isArray(childs) && typeTree.childTypes.length == 1) { for (var _a = 0, childs_4 = childs; _a < childs_4.length; _a++) { var c = childs_4[_a]; var l = toStraightData({ vname: 'l', type: getTypeString(typeTree.childTypes[0]), value: c, }); ret.value.push(l.value); } } else { throw new TypeError('Invalid List node'); } break; case 'Pair': { ret.value = {}; var childs = value.arguments; if (Array.isArray(childs) && childs.length == 2 && typeTree.childTypes.length == 2) { var x = toStraightData({ vname: 'x', type: getTypeString(typeTree.childTypes[0]), value: childs[0], }); var y = toStraightData({ vname: 'y', type: getTypeString(typeTree.childTypes[1]), value: childs[1], }); ret.value.x = x.value; ret.value.y = y.value; } else { throw new TypeError('Invalid Pair node'); } break; } case 'Uint32': case 'Int32': ret.value = parseInt(value); break; case 'Uint64': case 'Uint128': case 'Uint256': case 'Int64': case 'Int128': case 'Uint256': case 'BNum': ret.value = new bn_js_1.BN(value); break; default: if (customTypeMap[typeTree.type] != null) { ret.value = {}; var rule = customTypeMap[typeTree.type]; var childs = value.arguments; if (Array.isArray(childs) && childs.length == rule.argtypes.length) { for (var k = 0; k < rule.argtypes.length; k++) { var rname = rule.argtypes[k]['vname']; var rtype = rule.argtypes[k]['type']; ret.value[rname] = toStraightData({ vname: rname, type: rtype, value: childs[k], }).value; } } else { throw new TypeError('Invalid Custom node'); } } else { throw new TypeError('Unhandle type ' + typeTree.type); } break; } return ret; } //New node with same type. function getEmptyData(node) { if (isObject(node)) { return {}; } else if (Array.isArray(node)) { return []; } return ''; } //With each node is in scilla format, convert it to simple format. //The bStraight flag mean keep the sciila format in root node. It still have enough info to convert back to scilla format. function convertToSimpleJson(input, bStraight) { if (bStraight === void 0) { bStraight = false; } var stackIns = []; var stackParents = []; var stackOuts = []; stackIns.push(input); stackParents.push(-1); stackOuts.push(getEmptyData(input)); var k = 0; while (k < stackIns.length) { var curIn = stackIns[k]; if (isScillaData(curIn)) { stackOuts[k] = bStraight ? toStraightData(curIn) : toSimpleData(curIn); } else if (isObject(curIn)) { for (var _i = 0, _a = Object.keys(curIn); _i < _a.length; _i++) { var p = _a[_i]; var c = curIn[p]; stackIns.push(c); stackOuts[k][p] = stackOuts.length; //index to out node. var emptyData = getEmptyData(c); stackOuts.push(emptyData); stackParents.push(k); } } else if (Array.isArray(curIn)) { for (var _b = 0, curIn_1 = curIn; _b < curIn_1.length; _b++) { var p = curIn_1[_b]; stackIns.push(p); var emptyData = getEmptyData(p); stackOuts.push(emptyData); stackParents.push(k); } } else { stackOuts[k] = JSON.parse(JSON.stringify(curIn)); } k++; } k = stackIns.length - 1; while (k >= 0) { var curIn = stackIns[k]; if (isScillaData(curIn)) { } else if (isObject(curIn)) { for (var _c = 0, _d = Object.keys(curIn); _c < _d.length; _c++) { var p = _d[_c]; stackOuts[k][p] = stackOuts[stackOuts[k][p]]; } } else if (Array.isArray(curIn)) { var mappable = {}; for (var i = 0; i < stackIns.length; i++) { if (stackParents[i] == k) { stackOuts[k].push(stackOuts[i]); if (mappable != null) { var size = 0, vname; for (vname in stackOuts[i]) { mappable[vname] = stackOuts[i][vname]; size++; } if (size != 1) { mappable = null; } } } } if (mappable != null) { stackOuts[k] = mappable; } } else { } k--; } return stackOuts[0]; } function isFloat(n) { return n === +n && n !== (n | 0); } function isInteger(n) { return n === +n && n === (n | 0); } function toScillaBool(value) { var ret = false; if (typeof value === 'boolean') { ret = value; } else if (typeof value === 'string') { ret = value.toLowerCase() == 'true'; } else if (isInteger(value)) { ret = parseInt(value) != 0; } else { ret = false; } return ret ? 'True' : 'False'; } function convertToScillaData(node) { var vname = node.vname; var type = node.type; var value = node.value; var ret = { vname: vname, type: type, value: null, }; var typeTree = parseTypeTree(type); switch (typeTree.type) { case 'Bool': ret.value = { constructor: toScillaBool(value), argtypes: [], arguments: [] }; break; case 'String': case 'ByStr20': ret.value = value; break; case 'Option': ret.value = {}; if (typeTree.childTypes.length == 1) { if (value != null && value != '') { var op = convertToScillaData({ vname: 'op', type: getTypeString(typeTree.childTypes[0]), value: value, }); ret.value['constructor'] = 'Some'; ret.value['argtypes'] = [op.type]; ret.value['arguments'] = [op.value]; } else { ret.value['constructor'] = 'None'; ret.value['argtypes'] = [getTypeString(typeTree.childTypes[0])]; ret.value['arguments'] = []; } } else { throw new TypeError('Invalid Option node'); } break; case 'Map': { ret.value = []; var childs = value; if (isObject(childs) && typeTree.childTypes.length == 2) { for (var _i = 0, _a = Object.keys(childs); _i < _a.length; _i++) { var c = _a[_i]; var key = convertToScillaData({ vname: 'key', type: getTypeString(typeTree.childTypes[0]), value: c, }); var val = convertToScillaData({ vname: 'val', type: getTypeString(typeTree.childTypes[1]), value: childs[c], }); ret.value.push({ key: key.value, val: val.value, }); } } else { throw new TypeError('Invalid Map node'); } break; } case 'List': { ret.value = []; var childs = value; if (Array.isArray(childs) && typeTree.childTypes.length == 1) { for (var _b = 0, childs_5 = childs; _b < childs_5.length; _b++) { var c = childs_5[_b]; var l = convertToScillaData({ vname: 'l', type: getTypeString(typeTree.childTypes[0]), value: c, }); ret.value.push(l.value); } } else { throw new TypeError('Invalid List node'); } break; } case 'Pair': { ret.value = {}; var childs = value; if (isObject(childs) && typeTree.childTypes.length == 2) { var x = convertToScillaData({ vname: 'x', type: getTypeString(typeTree.childTypes[0]), value: childs.x, }); var y = convertToScillaData({ vname: 'y', type: getTypeString(typeTree.childTypes[1]), value: childs.y, }); ret.value['constructor'] = 'Pair'; ret.value['argtypes'] = [x.type, y.type]; ret.value['arguments'] = [x.value, y.value]; } else { throw new TypeError('Invalid Pair node'); } break; } case 'Uint32': case 'Int32': ret.value = value.toString(); break; case 'Uint64': case 'Uint128': case 'Uint256': case 'Int64': case 'Int128': case 'Uint256': case 'BNum': ret.value = value.toString(); break; default: throw new TypeError('Unhandle type ' + typeTree.type); break; } return ret; } function convertToScillaDataList(input) { var ret = []; if (Array.isArray(input)) { for (var _i = 0, input_1 = input; _i < input_1.length; _i++) { var p = input_1[_i]; if (isScillaData(p)) { ret.push(convertToScillaData(p)); } else { throw new TypeError('Invalid scilla node'); } } } return ret; } function fetchCustomData(name, rule) { customTypeMap[name] = rule; } exports.ScillaDataParser = { convertToSimpleJson: convertToSimpleJson, convertToScillaData: convertToScillaData, convertToScillaDataList: convertToScillaDataList, fetchCustomData: fetchCustomData, };