[6a3a178] | 1 | "use strict";
|
---|
| 2 | Object.defineProperty(exports, "__esModule", { value: true });
|
---|
| 3 | const types_1 = require("./types");
|
---|
| 4 | const __1 = require("..");
|
---|
| 5 | const codegen_1 = require("../codegen");
|
---|
| 6 | const ref_error_1 = require("../ref_error");
|
---|
| 7 | const names_1 = require("../names");
|
---|
| 8 | const code_1 = require("../../vocabularies/code");
|
---|
| 9 | const ref_1 = require("../../vocabularies/jtd/ref");
|
---|
| 10 | const util_1 = require("../util");
|
---|
| 11 | const quote_1 = require("../../runtime/quote");
|
---|
| 12 | const genSerialize = {
|
---|
| 13 | elements: serializeElements,
|
---|
| 14 | values: serializeValues,
|
---|
| 15 | discriminator: serializeDiscriminator,
|
---|
| 16 | properties: serializeProperties,
|
---|
| 17 | optionalProperties: serializeProperties,
|
---|
| 18 | enum: serializeString,
|
---|
| 19 | type: serializeType,
|
---|
| 20 | ref: serializeRef,
|
---|
| 21 | };
|
---|
| 22 | function compileSerializer(sch, definitions) {
|
---|
| 23 | const _sch = __1.getCompilingSchema.call(this, sch);
|
---|
| 24 | if (_sch)
|
---|
| 25 | return _sch;
|
---|
| 26 | const { es5, lines } = this.opts.code;
|
---|
| 27 | const { ownProperties } = this.opts;
|
---|
| 28 | const gen = new codegen_1.CodeGen(this.scope, { es5, lines, ownProperties });
|
---|
| 29 | const serializeName = gen.scopeName("serialize");
|
---|
| 30 | const cxt = {
|
---|
| 31 | self: this,
|
---|
| 32 | gen,
|
---|
| 33 | schema: sch.schema,
|
---|
| 34 | schemaEnv: sch,
|
---|
| 35 | definitions,
|
---|
| 36 | data: names_1.default.data,
|
---|
| 37 | };
|
---|
| 38 | let sourceCode;
|
---|
| 39 | try {
|
---|
| 40 | this._compilations.add(sch);
|
---|
| 41 | sch.serializeName = serializeName;
|
---|
| 42 | gen.func(serializeName, names_1.default.data, false, () => {
|
---|
| 43 | gen.let(names_1.default.json, codegen_1.str ``);
|
---|
| 44 | serializeCode(cxt);
|
---|
| 45 | gen.return(names_1.default.json);
|
---|
| 46 | });
|
---|
| 47 | gen.optimize(this.opts.code.optimize);
|
---|
| 48 | const serializeFuncCode = gen.toString();
|
---|
| 49 | sourceCode = `${gen.scopeRefs(names_1.default.scope)}return ${serializeFuncCode}`;
|
---|
| 50 | const makeSerialize = new Function(`${names_1.default.scope}`, sourceCode);
|
---|
| 51 | const serialize = makeSerialize(this.scope.get());
|
---|
| 52 | this.scope.value(serializeName, { ref: serialize });
|
---|
| 53 | sch.serialize = serialize;
|
---|
| 54 | }
|
---|
| 55 | catch (e) {
|
---|
| 56 | if (sourceCode)
|
---|
| 57 | this.logger.error("Error compiling serializer, function code:", sourceCode);
|
---|
| 58 | delete sch.serialize;
|
---|
| 59 | delete sch.serializeName;
|
---|
| 60 | throw e;
|
---|
| 61 | }
|
---|
| 62 | finally {
|
---|
| 63 | this._compilations.delete(sch);
|
---|
| 64 | }
|
---|
| 65 | return sch;
|
---|
| 66 | }
|
---|
| 67 | exports.default = compileSerializer;
|
---|
| 68 | function serializeCode(cxt) {
|
---|
| 69 | let form;
|
---|
| 70 | for (const key of types_1.jtdForms) {
|
---|
| 71 | if (key in cxt.schema) {
|
---|
| 72 | form = key;
|
---|
| 73 | break;
|
---|
| 74 | }
|
---|
| 75 | }
|
---|
| 76 | serializeNullable(cxt, form ? genSerialize[form] : serializeEmpty);
|
---|
| 77 | }
|
---|
| 78 | function serializeNullable(cxt, serializeForm) {
|
---|
| 79 | const { gen, schema, data } = cxt;
|
---|
| 80 | if (!schema.nullable)
|
---|
| 81 | return serializeForm(cxt);
|
---|
| 82 | gen.if(codegen_1._ `${data} === undefined || ${data} === null`, () => gen.add(names_1.default.json, codegen_1._ `"null"`), () => serializeForm(cxt));
|
---|
| 83 | }
|
---|
| 84 | function serializeElements(cxt) {
|
---|
| 85 | const { gen, schema, data } = cxt;
|
---|
| 86 | gen.add(names_1.default.json, codegen_1.str `[`);
|
---|
| 87 | const first = gen.let("first", true);
|
---|
| 88 | gen.forOf("el", data, (el) => {
|
---|
| 89 | addComma(cxt, first);
|
---|
| 90 | serializeCode({ ...cxt, schema: schema.elements, data: el });
|
---|
| 91 | });
|
---|
| 92 | gen.add(names_1.default.json, codegen_1.str `]`);
|
---|
| 93 | }
|
---|
| 94 | function serializeValues(cxt) {
|
---|
| 95 | const { gen, schema, data } = cxt;
|
---|
| 96 | gen.add(names_1.default.json, codegen_1.str `{`);
|
---|
| 97 | const first = gen.let("first", true);
|
---|
| 98 | gen.forIn("key", data, (key) => serializeKeyValue(cxt, key, schema.values, first));
|
---|
| 99 | gen.add(names_1.default.json, codegen_1.str `}`);
|
---|
| 100 | }
|
---|
| 101 | function serializeKeyValue(cxt, key, schema, first) {
|
---|
| 102 | const { gen, data } = cxt;
|
---|
| 103 | addComma(cxt, first);
|
---|
| 104 | serializeString({ ...cxt, data: key });
|
---|
| 105 | gen.add(names_1.default.json, codegen_1.str `:`);
|
---|
| 106 | const value = gen.const("value", codegen_1._ `${data}${codegen_1.getProperty(key)}`);
|
---|
| 107 | serializeCode({ ...cxt, schema, data: value });
|
---|
| 108 | }
|
---|
| 109 | function serializeDiscriminator(cxt) {
|
---|
| 110 | const { gen, schema, data } = cxt;
|
---|
| 111 | const { discriminator } = schema;
|
---|
| 112 | gen.add(names_1.default.json, codegen_1.str `{${JSON.stringify(discriminator)}:`);
|
---|
| 113 | const tag = gen.const("tag", codegen_1._ `${data}${codegen_1.getProperty(discriminator)}`);
|
---|
| 114 | serializeString({ ...cxt, data: tag });
|
---|
| 115 | gen.if(false);
|
---|
| 116 | for (const tagValue in schema.mapping) {
|
---|
| 117 | gen.elseIf(codegen_1._ `${tag} === ${tagValue}`);
|
---|
| 118 | const sch = schema.mapping[tagValue];
|
---|
| 119 | serializeSchemaProperties({ ...cxt, schema: sch }, discriminator);
|
---|
| 120 | }
|
---|
| 121 | gen.endIf();
|
---|
| 122 | gen.add(names_1.default.json, codegen_1.str `}`);
|
---|
| 123 | }
|
---|
| 124 | function serializeProperties(cxt) {
|
---|
| 125 | const { gen } = cxt;
|
---|
| 126 | gen.add(names_1.default.json, codegen_1.str `{`);
|
---|
| 127 | serializeSchemaProperties(cxt);
|
---|
| 128 | gen.add(names_1.default.json, codegen_1.str `}`);
|
---|
| 129 | }
|
---|
| 130 | function serializeSchemaProperties(cxt, discriminator) {
|
---|
| 131 | const { gen, schema, data } = cxt;
|
---|
| 132 | const { properties, optionalProperties } = schema;
|
---|
| 133 | const props = keys(properties);
|
---|
| 134 | const optProps = keys(optionalProperties);
|
---|
| 135 | const allProps = allProperties(props.concat(optProps));
|
---|
| 136 | let first = !discriminator;
|
---|
| 137 | for (const key of props) {
|
---|
| 138 | serializeProperty(key, properties[key], keyValue(key));
|
---|
| 139 | }
|
---|
| 140 | for (const key of optProps) {
|
---|
| 141 | const value = keyValue(key);
|
---|
| 142 | gen.if(codegen_1.and(codegen_1._ `${value} !== undefined`, code_1.isOwnProperty(gen, data, key)), () => serializeProperty(key, optionalProperties[key], value));
|
---|
| 143 | }
|
---|
| 144 | if (schema.additionalProperties) {
|
---|
| 145 | gen.forIn("key", data, (key) => gen.if(isAdditional(key, allProps), () => serializeKeyValue(cxt, key, {}, gen.let("first", first))));
|
---|
| 146 | }
|
---|
| 147 | function keys(ps) {
|
---|
| 148 | return ps ? Object.keys(ps) : [];
|
---|
| 149 | }
|
---|
| 150 | function allProperties(ps) {
|
---|
| 151 | if (discriminator)
|
---|
| 152 | ps.push(discriminator);
|
---|
| 153 | if (new Set(ps).size !== ps.length) {
|
---|
| 154 | throw new Error("JTD: properties/optionalProperties/disciminator overlap");
|
---|
| 155 | }
|
---|
| 156 | return ps;
|
---|
| 157 | }
|
---|
| 158 | function keyValue(key) {
|
---|
| 159 | return gen.const("value", codegen_1._ `${data}${codegen_1.getProperty(key)}`);
|
---|
| 160 | }
|
---|
| 161 | function serializeProperty(key, propSchema, value) {
|
---|
| 162 | if (first)
|
---|
| 163 | first = false;
|
---|
| 164 | else
|
---|
| 165 | gen.add(names_1.default.json, codegen_1.str `,`);
|
---|
| 166 | gen.add(names_1.default.json, codegen_1.str `${JSON.stringify(key)}:`);
|
---|
| 167 | serializeCode({ ...cxt, schema: propSchema, data: value });
|
---|
| 168 | }
|
---|
| 169 | function isAdditional(key, ps) {
|
---|
| 170 | return ps.length ? codegen_1.and(...ps.map((p) => codegen_1._ `${key} !== ${p}`)) : true;
|
---|
| 171 | }
|
---|
| 172 | }
|
---|
| 173 | function serializeType(cxt) {
|
---|
| 174 | const { gen, schema, data } = cxt;
|
---|
| 175 | switch (schema.type) {
|
---|
| 176 | case "boolean":
|
---|
| 177 | gen.add(names_1.default.json, codegen_1._ `${data} ? "true" : "false"`);
|
---|
| 178 | break;
|
---|
| 179 | case "string":
|
---|
| 180 | serializeString(cxt);
|
---|
| 181 | break;
|
---|
| 182 | case "timestamp":
|
---|
| 183 | gen.if(codegen_1._ `${data} instanceof Date`, () => gen.add(names_1.default.json, codegen_1._ `'"' + ${data}.toISOString() + '"'`), () => serializeString(cxt));
|
---|
| 184 | break;
|
---|
| 185 | default:
|
---|
| 186 | serializeNumber(cxt);
|
---|
| 187 | }
|
---|
| 188 | }
|
---|
| 189 | function serializeString({ gen, data }) {
|
---|
| 190 | gen.add(names_1.default.json, codegen_1._ `${util_1.useFunc(gen, quote_1.default)}(${data})`);
|
---|
| 191 | }
|
---|
| 192 | function serializeNumber({ gen, data }) {
|
---|
| 193 | gen.add(names_1.default.json, codegen_1._ `"" + ${data}`);
|
---|
| 194 | }
|
---|
| 195 | function serializeRef(cxt) {
|
---|
| 196 | const { gen, self, data, definitions, schema, schemaEnv } = cxt;
|
---|
| 197 | const { ref } = schema;
|
---|
| 198 | const refSchema = definitions[ref];
|
---|
| 199 | if (!refSchema)
|
---|
| 200 | throw new ref_error_1.default("", ref, `No definition ${ref}`);
|
---|
| 201 | if (!ref_1.hasRef(refSchema))
|
---|
| 202 | return serializeCode({ ...cxt, schema: refSchema });
|
---|
| 203 | const { root } = schemaEnv;
|
---|
| 204 | const sch = compileSerializer.call(self, new __1.SchemaEnv({ schema: refSchema, root }), definitions);
|
---|
| 205 | gen.add(names_1.default.json, codegen_1._ `${getSerialize(gen, sch)}(${data})`);
|
---|
| 206 | }
|
---|
| 207 | function getSerialize(gen, sch) {
|
---|
| 208 | return sch.serialize
|
---|
| 209 | ? gen.scopeValue("serialize", { ref: sch.serialize })
|
---|
| 210 | : codegen_1._ `${gen.scopeValue("wrapper", { ref: sch })}.serialize`;
|
---|
| 211 | }
|
---|
| 212 | function serializeEmpty({ gen, data }) {
|
---|
| 213 | gen.add(names_1.default.json, codegen_1._ `JSON.stringify(${data})`);
|
---|
| 214 | }
|
---|
| 215 | function addComma({ gen }, first) {
|
---|
| 216 | gen.if(first, () => gen.assign(first, false), () => gen.add(names_1.default.json, codegen_1.str `,`));
|
---|
| 217 | }
|
---|
| 218 | //# sourceMappingURL=serialize.js.map |
---|