@jsonjoy.com/json-type
Version:
High-performance JSON Pointer implementation
230 lines • 12.2 kB
JavaScript
;
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