UNPKG

json-type-cli

Version:

High-performance JSON Pointer implementation

144 lines (143 loc) 5.83 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Cli = void 0; const node_util_1 = require("node:util"); const TypeSystem_1 = require("@jsonjoy.com/json-type/lib/system/TypeSystem"); const ObjectValueCaller_1 = require("@jsonjoy.com/reactive-rpc/lib/common/rpc/caller/ObjectValueCaller"); const bufferToUint8Array_1 = require("@jsonjoy.com/util/lib/buffers/bufferToUint8Array"); const util_1 = require("./util"); const methods_1 = require("./methods"); const defaultParams_1 = require("./defaultParams"); const ObjectValue_1 = require("@jsonjoy.com/json-type/lib/value/ObjectValue"); class Cli { constructor(options) { this.options = options; this.paramInstances = []; let router = options.router ?? ObjectValue_1.ObjectValue.create(new TypeSystem_1.TypeSystem()); router = (0, methods_1.defineBuiltinRoutes)(router); this.router = router; this.params = options.params ?? defaultParams_1.defaultParams; this.paramMap = new Map(); for (const param of this.params) { this.paramMap.set(param.param, param); if (param.short) this.paramMap.set(param.short, param); } this.caller = new ObjectValueCaller_1.ObjectValueCaller({ router, wrapInternalError: (err) => err }); this.types = router.system; this.t = this.types.t; this.codecs = options.codecs; this.requestCodec = this.codecs.get(this.codecs.defaultCodec); this.responseCodec = this.codecs.get(this.codecs.defaultCodec); this.argv = options.argv ?? process.argv.slice(2); this.stdin = options.stdin ?? process.stdin; this.stdout = options.stdout ?? process.stdout; this.stderr = options.stderr ?? process.stderr; this.exit = options.exit ?? process.exit; } run() { this.runAsync(); } param(param) { return this.paramMap.get(param); } async runAsync() { try { const system = this.router.system; for (const key of this.router.keys()) system.alias(key, this.router.get(key).type); const args = (0, node_util_1.parseArgs)({ args: this.argv, strict: false, allowPositionals: true, }); for (let argKey of Object.keys(args.values)) { let pointer = ''; const value = args.values[argKey]; const slashIndex = argKey.indexOf('/'); if (slashIndex !== -1) { pointer = argKey.slice(slashIndex); argKey = argKey.slice(0, slashIndex); } const param = this.param(argKey); if (!param) { throw new Error(`Unknown parameter "${argKey}"`); } const instance = param.createInstance(this, pointer, value); this.paramInstances.push(instance); if (instance.onParam) await instance.onParam(); } const method = args.positionals[0]; if (!method) { const param = this.param('help'); const instance = param?.createInstance(this, '', undefined); instance?.onParam?.(); throw new Error('No method specified'); } this.request = JSON.parse(args.positionals[1] || '{}'); await this.readStdin(); for (const instance of this.paramInstances) if (instance.onStdin) await instance.onStdin(); for (const instance of this.paramInstances) if (instance.onRequest) await instance.onRequest(); try { const ctx = { cli: this }; for (const instance of this.paramInstances) if (instance.onBeforeCall) await instance.onBeforeCall(method, ctx); const value = await this.caller.call(method, this.request, ctx); this.response = value.data; for (const instance of this.paramInstances) if (instance.onResponse) await instance.onResponse(); const buf = this.responseCodec.encode(this.response); this.stdout.write(buf); } catch (err) { const error = (0, util_1.formatError)(err); const buf = this.responseCodec.encode(error); this.stderr.write(buf); this.exit(1); } } catch (err) { const error = (0, util_1.formatError)(err); const buf = JSON.stringify(error, null, 4); this.stderr.write(buf); this.exit(1); } } cmd() { return this.options.cmd ?? '<cmd>'; } async getStdin() { const stdin = this.stdin; if (stdin.isTTY) return Buffer.alloc(0); const result = []; let length = 0; for await (const chunk of stdin) { result.push(chunk); length += chunk.length; } return Buffer.concat(result, length); } async readStdin() { const stdin = this.stdin; const codec = this.requestCodec; if (stdin.isTTY) return Object.create(null); const input = await this.getStdin(); if (codec.id === 'json') { const str = input.toString().trim(); if (!str) return Object.create(null); } this.rawStdinInput = (0, bufferToUint8Array_1.bufferToUint8Array)(input); this.stdinInput = codec.decode(this.rawStdinInput); } } exports.Cli = Cli;