UNPKG

@jsonjoy.com/json-type

Version:

High-performance JSON Pointer implementation

230 lines 12.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JsonCodegen = void 0; const tslib_1 = require("tslib"); const JsExpression_1 = require("@jsonjoy.com/codegen/lib/util/JsExpression"); const normalizeAccessor_1 = require("@jsonjoy.com/codegen/lib/util/normalizeAccessor"); const JsonEncoder_1 = require("@jsonjoy.com/json-pack/lib/json/JsonEncoder"); const type_1 = require("../../../type"); const util_1 = require("../../util"); const AbstractBinaryCodegen_1 = require("../AbstractBinaryCodegen"); const writer_1 = require("../writer"); const once_1 = require("thingies/lib/once"); let JsonCodegen = (() => { var _a; let _classSuper = AbstractBinaryCodegen_1.AbstractBinaryCodegen; let _instanceExtraInitializers = []; let _linkGet_decorators; return _a = class JsonCodegen extends _classSuper { constructor() { super(...arguments); this.encoder = (tslib_1.__runInitializers(this, _instanceExtraInitializers), new JsonEncoder_1.JsonEncoder(writer_1.writer)); } linkGet() { this.codegen.linkDependency(_a.get, 'get'); } onArr(path, r, type) { const codegen = this.codegen; const rLen = codegen.var(/* js */ `${r.use()}.length`); const { _head = [], _type, _tail = [] } = type; const headLen = _head.length; const tailLen = _tail.length; const constLen = headLen + tailLen; if (constLen) { codegen.if(/* js */ `${rLen} < ${constLen}`, () => { codegen.js(`throw new Error('ARR_LEN');`); }); } codegen.if( /* js */ `${rLen} === 0`, () => { this.blob(this.gen((encoder) => { encoder.writeStartArr(); encoder.writeEndArr(); })); }, () => { const ri = codegen.var('0'); const separatorBlob = this.gen((encoder) => encoder.writeObjSeparator()); this.blob(this.gen((encoder) => { encoder.writeStartArr(); })); if (headLen) { for (let i = 0; i < headLen; i++) { const isLast = i === headLen - 1; this.onNode([...path, { r: i + '' }], new JsExpression_1.JsExpression(() => /* js */ `${r.use()}[${i}]`), _head[i]); if (!isLast) this.blob(separatorBlob); } codegen.js(/* js */ `${ri} += ${headLen}`); } if (_type) { if (!_head.length) { codegen.if(`${rLen} > ${_tail.length}`, () => { this.onNode([...path, { r: '0' }], new JsExpression_1.JsExpression(() => /* js */ `${r.use()}[0]`), type._type); codegen.js(/* js */ `${ri}++`); }); } codegen.js(/* js */ `for(; ${ri} < ${rLen} - ${_tail.length}; ${ri}++) {`); this.blob(separatorBlob); this.onNode([...path, { r: ri }], new JsExpression_1.JsExpression(() => /* js */ `${r.use()}[${ri}]`), type._type); codegen.js(/* js */ `}`); } if (tailLen) { for (let i = 0; i < tailLen; i++) { const isFirst = i === 0; if (isFirst) { codegen.if(`${ri} + ${i} > 0`, () => { this.blob(separatorBlob); }); } else { this.blob(separatorBlob); } this.onNode([...path, { r: `${ri} + ${i}` }], new JsExpression_1.JsExpression(() => /* js */ `${r.use()}[${ri}+${i}]`), _tail[i]); } } this.blob(this.gen((encoder) => { encoder.writeEndArr(); })); }); } onObj(path, value, type) { const codegen = this.codegen; const r = codegen.var(value.use()); const fields = type.keys; const requiredFields = fields.filter((field) => !(field instanceof type_1.KeyOptType)); const optionalFields = fields.filter((field) => field instanceof type_1.KeyOptType); const requiredLength = requiredFields.length; const optionalLength = optionalFields.length; const encodeUnknownFields = !!type.schema.encodeUnknownKeys; const separatorBlob = this.gen((encoder) => encoder.writeObjSeparator()); const keySeparatorBlob = this.gen((encoder) => encoder.writeObjKeySeparator()); const endBlob = this.gen((encoder) => encoder.writeEndObj()); const emitRequiredFields = () => { for (let i = 0; i < requiredLength; i++) { const field = requiredFields[i]; this.blob(this.gen((encoder) => { encoder.writeStr(field.key); encoder.writeObjKeySeparator(); })); const accessor = (0, normalizeAccessor_1.normalizeAccessor)(field.key); this.onNode([...path, field.key], new JsExpression_1.JsExpression(() => `(${r}${accessor})`), field.val); this.blob(separatorBlob); } }; const emitOptionalFields = () => { for (let i = 0; i < optionalLength; i++) { const field = optionalFields[i]; const accessor = (0, normalizeAccessor_1.normalizeAccessor)(field.key); codegen.if(`${r}${accessor} !== undefined`, () => { this.blob(this.gen((encoder) => { encoder.writeStr(field.key); })); this.blob(keySeparatorBlob); this.onNode([...path, field.key], new JsExpression_1.JsExpression(() => `${r}${accessor}`), field.val); this.blob(separatorBlob); }); } }; const emitUnknownFields = () => { const rKeys = codegen.r(); const rKey = codegen.r(); const ri = codegen.r(); const rLength = codegen.r(); const keys = fields.map((field) => JSON.stringify(field.key)); const rKnownFields = codegen.addConstant(/* js */ `new Set([${keys.join(',')}])`); codegen.js(/* js */ `var ${rKeys} = Object.keys(${r}), ${rLength} = ${rKeys}.length, ${rKey};`); codegen.js(/* js */ `for (var ${ri} = 0; ${ri} < ${rLength}; ${ri}++) {`); codegen.js(/* js */ `${rKey} = ${rKeys}[${ri}];`); codegen.js(/* js */ `if (${rKnownFields}.has(${rKey})) continue;`); codegen.js(/* js */ `encoder.writeStr(${rKey});`); this.blob(keySeparatorBlob); codegen.js(/* js */ `encoder.writeAny(${r}[${rKey}]);`); this.blob(separatorBlob); codegen.js(/* js */ `}`); }; const emitEnding = () => { const rewriteLastSeparator = () => { for (let i = 0; i < endBlob.length; i++) codegen.js(/* js */ `uint8[writer.x - ${endBlob.length - i}] = ${endBlob[i]};`); }; if (requiredFields.length) { rewriteLastSeparator(); } else { codegen.if( /* js */ `uint8[writer.x - 1] === ${separatorBlob[separatorBlob.length - 1]}`, () => { rewriteLastSeparator(); }, () => { this.blob(endBlob); }); } }; this.blob(this.gen((encoder) => { encoder.writeStartObj(); })); if (!encodeUnknownFields && !optionalLength) { emitRequiredFields(); emitEnding(); } else if (!encodeUnknownFields) { emitRequiredFields(); emitOptionalFields(); emitEnding(); } else { emitRequiredFields(); emitOptionalFields(); emitUnknownFields(); emitEnding(); } } onMap(path, val, type) { const separatorBlob = this.gen((encoder) => encoder.writeObjSeparator()); const keySeparatorBlob = this.gen((encoder) => encoder.writeObjKeySeparator()); const codegen = this.codegen; const r = codegen.var(val.use()); const rKeys = codegen.var(`Object.keys(${r})`); const rKey = codegen.var(); const ri = codegen.var(); const rLength = codegen.var(`${rKeys}.length`); this.blob(this.gen((encoder) => encoder.writeStartObj())); codegen.if(`${rLength}`, () => { codegen.js(`${rKey} = ${rKeys}[0];`); codegen.js(`encoder.writeStr(${rKey});`); this.blob(keySeparatorBlob); this.onNode([...path, { r: rKey }], new JsExpression_1.JsExpression(() => `${r}[${rKey}]`), type._value); }); codegen.js(`for (var ${ri} = 1; ${ri} < ${rLength}; ${ri}++) {`); codegen.js(`${rKey} = ${rKeys}[${ri}];`); this.blob(separatorBlob); codegen.js(`encoder.writeStr(${rKey});`); this.blob(keySeparatorBlob); this.onNode([...path, { r: rKey }], new JsExpression_1.JsExpression(() => `${r}[${rKey}]`), type._value); codegen.js(`}`); this.blob(this.gen((encoder) => encoder.writeEndObj())); } onKey(path, r, type) { this.onNode([...path, type.key], r, type.val); } genEncoder(type) { return _a.get(type); } }, (() => { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; _linkGet_decorators = [once_1.once]; tslib_1.__esDecorate(_a, null, _linkGet_decorators, { kind: "method", name: "linkGet", static: false, private: false, access: { has: obj => "linkGet" in obj, get: obj => obj.linkGet }, metadata: _metadata }, null, _instanceExtraInitializers); if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); })(), _a.get = (0, util_1.lazyKeyedFactory)((type, name) => { const codegen = new _a(type, name); const r = codegen.codegen.options.args[0]; const expression = new JsExpression_1.JsExpression(() => r); codegen.onNode([], expression, type); // console.log(codegen.codegen.generate().js); return codegen.compile(); }), _a; })(); exports.JsonCodegen = JsonCodegen; //# sourceMappingURL=JsonCodegen.js.map