UNPKG

@jsonjoy.com/json-type

Version:

High-performance JSON Pointer implementation

147 lines (146 loc) 6.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MapType = void 0; const tslib_1 = require("tslib"); const JsExpression_1 = require("@jsonjoy.com/util/lib/codegen/util/JsExpression"); const asString_1 = require("@jsonjoy.com/util/lib/strings/asString"); const printTree_1 = require("tree-dump/lib/printTree"); const schema = tslib_1.__importStar(require("../../schema")); const constants_1 = require("../../constants"); const CborEncoderCodegenContext_1 = require("../../codegen/binary/CborEncoderCodegenContext"); const MessagePackEncoderCodegenContext_1 = require("../../codegen/binary/MessagePackEncoderCodegenContext"); const AbsType_1 = require("./AbsType"); class MapType extends AbsType_1.AbsType { constructor(valueType, keyType, options) { super(); this.valueType = valueType; this.keyType = keyType; this.schema = { kind: 'map', value: schema.s.any, ...(keyType && { key: schema.s.any }), ...options }; } getSchema(ctx) { return { ...this.schema, value: this.valueType.getSchema(ctx), ...(this.keyType && { key: this.keyType.getSchema(ctx) }), }; } getOptions() { const { kind, value, key, ...options } = this.schema; return options; } codegenValidator(ctx, path, r) { const err = ctx.err(constants_1.ValidationError.MAP, path); ctx.js(`if (!${r} || (typeof ${r} !== 'object') || (${r}.constructor !== Object)) return ${err};`); const rKeys = ctx.codegen.var(`Object.keys(${r});`); const rLength = ctx.codegen.var(`${rKeys}.length`); const rKey = ctx.codegen.r(); const rValue = ctx.codegen.r(); ctx.js(`for (var ${rKey}, ${rValue}, i = 0; i < ${rLength}; i++) {`); ctx.js(`${rKey} = ${rKeys}[i];`); ctx.js(`${rValue} = ${r}[${rKey}];`); this.valueType.codegenValidator(ctx, [...path, { r: rKey }], rValue); ctx.js(`}`); ctx.emitCustomValidators(this, path, r); } codegenJsonTextEncoder(ctx, value) { ctx.writeText('{'); const r = ctx.codegen.var(value.use()); const rKeys = ctx.codegen.var(`Object.keys(${r})`); const rLength = ctx.codegen.var(`${rKeys}.length`); const rKey = ctx.codegen.var(); ctx.codegen.if(`${rLength}`, () => { ctx.js(`${rKey} = ${rKeys}[0];`); ctx.js(`s += asString(${rKey}) + ':';`); this.valueType.codegenJsonTextEncoder(ctx, new JsExpression_1.JsExpression(() => `${r}[${rKey}]`)); }); ctx.js(`for (var i = 1; i < ${rLength}; i++) {`); ctx.js(`${rKey} = ${rKeys}[i];`); ctx.js(`s += ',' + asString(${rKey}) + ':';`); this.valueType.codegenJsonTextEncoder(ctx, new JsExpression_1.JsExpression(() => `${r}[${rKey}]`)); ctx.js(`}`); ctx.writeText('}'); } codegenBinaryEncoder(ctx, value) { const type = this.valueType; const codegen = ctx.codegen; const r = codegen.var(value.use()); const rKeys = codegen.var(`Object.keys(${r})`); const rKey = codegen.var(); const rLength = codegen.var(`${rKeys}.length`); const ri = codegen.var('0'); ctx.js(`encoder.writeObjHdr(${rLength});`); ctx.js(`for(; ${ri} < ${rLength}; ${ri}++){`); ctx.js(`${rKey} = ${rKeys}[${ri}];`); ctx.js(`encoder.writeStr(${rKey});`); const expr = new JsExpression_1.JsExpression(() => `${r}[${rKey}]`); if (ctx instanceof CborEncoderCodegenContext_1.CborEncoderCodegenContext) type.codegenCborEncoder(ctx, expr); else if (ctx instanceof MessagePackEncoderCodegenContext_1.MessagePackEncoderCodegenContext) type.codegenMessagePackEncoder(ctx, expr); else throw new Error('Unknown encoder'); ctx.js(`}`); } codegenCborEncoder(ctx, value) { this.codegenBinaryEncoder(ctx, value); } codegenMessagePackEncoder(ctx, value) { this.codegenBinaryEncoder(ctx, value); } codegenJsonEncoder(ctx, value) { const type = this.valueType; const objStartBlob = ctx.gen((encoder) => encoder.writeStartObj()); const objEndBlob = ctx.gen((encoder) => encoder.writeEndObj()); const separatorBlob = ctx.gen((encoder) => encoder.writeObjSeparator()); const keySeparatorBlob = ctx.gen((encoder) => encoder.writeObjKeySeparator()); const codegen = ctx.codegen; const r = codegen.var(value.use()); const rKeys = codegen.var(`Object.keys(${r})`); const rKey = codegen.var(); const rLength = codegen.var(`${rKeys}.length`); ctx.blob(objStartBlob); ctx.codegen.if(`${rLength}`, () => { ctx.js(`${rKey} = ${rKeys}[0];`); codegen.js(`encoder.writeStr(${rKey});`); ctx.blob(keySeparatorBlob); type.codegenJsonEncoder(ctx, new JsExpression_1.JsExpression(() => `${r}[${rKey}]`)); }); ctx.js(`for (var i = 1; i < ${rLength}; i++) {`); ctx.js(`${rKey} = ${rKeys}[i];`); ctx.blob(separatorBlob); codegen.js(`encoder.writeStr(${rKey});`); ctx.blob(keySeparatorBlob); type.codegenJsonEncoder(ctx, new JsExpression_1.JsExpression(() => `${r}[${rKey}]`)); ctx.js(`}`); ctx.blob(objEndBlob); } toJson(value, system = this.system) { const map = value; const keys = Object.keys(map); const length = keys.length; if (!length) return '{}'; const last = length - 1; const type = this.valueType; let str = '{'; for (let i = 0; i < last; i++) { const key = keys[i]; const val = value[key]; if (val === undefined) continue; str += (0, asString_1.asString)(key) + ':' + type.toJson(val, system) + ','; } const key = keys[last]; const val = value[key]; if (val !== undefined) { str += (0, asString_1.asString)(key) + ':' + type.toJson(val, system); } else if (str.length > 1) str = str.slice(0, -1); return (str + '}'); } toString(tab = '') { return super.toString(tab) + (0, printTree_1.printTree)(tab, [(tab) => this.valueType.toString(tab)]); } } exports.MapType = MapType;