@silverwind/ioredis-mock
Version:
This library emulates ioredis by performing all operations in-memory.
217 lines (170 loc) • 5.09 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.init = exports.dispose = void 0;
var _fengari = _interopRequireDefault(require("fengari"));
var _fengariInterop = _interopRequireDefault(require("fengari-interop"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const {
lua,
lualib,
lauxlib,
to_luastring: toLuaString,
to_jsstring: toJsString
} = _fengari.default;
const luaExecString = L => str => {
const retCode = lauxlib.luaL_dostring(L, toLuaString(str));
if (retCode !== 0) {
const errorMsg = lua.lua_tojsstring(L, -1);
const message = `Error trying to loading or executing lua code string in VM: ${errorMsg}`;
throw new Error(message);
}
}; // DEBUGGING PRINT TOOL
// const printStack = L => msg => {
// const output = []
// output.push(`===== PRINTING STACK: ${msg} =====`)
// const newTop = lua.lua_gettop(L);
// output.push(`| newTop ${newTop} |`)
// let i = newTop * -1;
// output.push(`STACK ${i}`)
// while (i < 0) {
// output.push('-----')
// output.push(interop.tojs(L, i))
// output.push('-----')
// i++;
// }
// console.log(output.join('\n'))
// };
const getTopLength = L => {
// get length of array in top of the stack
lua.lua_len(L, -1);
const length = lua.lua_tointeger(L, -1);
lua.lua_pop(L, 1);
return length; // ~get length of array in top of the stack
};
const typeOf = L => pos => toJsString(lua.lua_typename(L, lua.lua_type(L, pos)));
const getTopKeys = L => {
if (lua.lua_isnil(L, -1)) throw new Error('cannot get keys on nil');
if (!lua.lua_istable(L, -1)) throw new Error(`non-tables don't have keys! type is "${typeOf(L)(-1)}"`);
lua.lua_pushnil(L);
const keys = [];
while (lua.lua_next(L, -2) !== 0) {
keys.push(_fengariInterop.default.tojs(L, -2));
lua.lua_pop(L, 1);
}
return keys;
};
const isTopArray = L => () => {
try {
const keys = getTopKeys(L); // reversing as putting and getting things from the stack ends with everything upside down.
return keys.reverse().every((v, i) => v === i + 1);
} catch (e) {
return false;
}
};
const makeReturnValue = L => {
const isArray = isTopArray(L)();
if (!isArray) {
const retVal = _fengariInterop.default.tojs(L, -1);
if (Array.isArray(retVal)) {
// we push 'null' into position 0 in Arrays because in lua Arrays are one-based
// see src/commands/defineCommand:callToRedisCommand
// this removes the null element before returning
return retVal.slice(1);
}
return retVal;
}
const arrayLength = getTopLength(L);
const table = _fengariInterop.default.tojs(L, -1);
const retVal = [];
if (arrayLength === 0) {
lua.lua_pop(L, 1);
return retVal;
}
for (let i = 1; i <= arrayLength; i++) {
_fengariInterop.default.push(L, table.get(i));
retVal.push(makeReturnValue(L));
}
lua.lua_pop(L, 1);
return retVal;
};
const popReturnValue = L => topBeforeCall => {
const numReturn = lua.lua_gettop(L) - topBeforeCall + 1;
let ret;
if (numReturn > 0) {
ret = makeReturnValue(L);
}
lua.lua_settop(L, topBeforeCall);
return ret;
};
const pushTable = L => obj => {
lua.lua_newtable(L);
const index = lua.lua_gettop(L);
Object.keys(obj).forEach(fieldName => {
_fengariInterop.default.push(L, fieldName); // eslint-disable-next-line no-use-before-define
push(L)(obj[fieldName]);
lua.lua_settable(L, index);
});
};
const pushArray = L => array => {
lua.lua_newtable(L);
const subTableIndex = lua.lua_gettop(L);
array.forEach((e, i) => {
_fengariInterop.default.push(L, i + 1);
_fengariInterop.default.push(L, e);
lua.lua_settable(L, subTableIndex);
});
};
const push = L => value => {
if (Array.isArray(value)) {
pushArray(L)(value);
} else if (value && typeof value === 'object' && !Array.isArray(value)) {
pushTable(L)(value);
} else {
_fengariInterop.default.push(L, value);
}
};
const defineGlobalArray = L => (array, name) => {
push(L)(array);
lua.lua_setglobal(L, toLuaString(name));
};
const defineGlobalFunction = L => (fn, name) => {
// define global fn call
lua.lua_pushjsfunction(L, fn);
lua.lua_setglobal(L, toLuaString(name));
};
const extractArgs = L => () => {
const top = lua.lua_gettop(L);
const args = [];
let a = -top;
while (a < 0) {
args.push(a);
a += 1;
}
return args.map(i => _fengariInterop.default.tojs(L, i));
};
const init = () => {
// init fengari
const L = lauxlib.luaL_newstate();
lualib.luaL_openlibs(L);
_fengariInterop.default.luaopen_js(L);
return {
L,
defineGlobalFunction: defineGlobalFunction(L),
defineGlobalArray: defineGlobalArray(L),
luaExecString: luaExecString(L),
extractArgs: extractArgs(L),
popReturnValue: popReturnValue(L),
utils: {
isTopArray: isTopArray(L),
push: push(L)
}
};
};
exports.init = init;
const dispose = vm => {
const L = vm.L || vm;
lua.lua_close(L);
};
exports.dispose = dispose;