UNPKG

8.96 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const types_1 = require("./types");
4const __1 = require("..");
5const codegen_1 = require("../codegen");
6const ref_error_1 = require("../ref_error");
7const names_1 = require("../names");
8const code_1 = require("../../vocabularies/code");
9const ref_1 = require("../../vocabularies/jtd/ref");
10const util_1 = require("../util");
11const quote_1 = require("../../runtime/quote");
12const 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};
22function 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, (0, 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}
67exports.default = compileSerializer;
68function 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}
78function serializeNullable(cxt, serializeForm) {
79 const { gen, schema, data } = cxt;
80 if (!schema.nullable)
81 return serializeForm(cxt);
82 gen.if((0, codegen_1._) `${data} === undefined || ${data} === null`, () => gen.add(names_1.default.json, (0, codegen_1._) `"null"`), () => serializeForm(cxt));
83}
84function serializeElements(cxt) {
85 const { gen, schema, data } = cxt;
86 gen.add(names_1.default.json, (0, 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, (0, codegen_1.str) `]`);
93}
94function serializeValues(cxt) {
95 const { gen, schema, data } = cxt;
96 gen.add(names_1.default.json, (0, 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, (0, codegen_1.str) `}`);
100}
101function 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, (0, codegen_1.str) `:`);
106 const value = gen.const("value", (0, codegen_1._) `${data}${(0, codegen_1.getProperty)(key)}`);
107 serializeCode({ ...cxt, schema, data: value });
108}
109function serializeDiscriminator(cxt) {
110 const { gen, schema, data } = cxt;
111 const { discriminator } = schema;
112 gen.add(names_1.default.json, (0, codegen_1.str) `{${JSON.stringify(discriminator)}:`);
113 const tag = gen.const("tag", (0, codegen_1._) `${data}${(0, codegen_1.getProperty)(discriminator)}`);
114 serializeString({ ...cxt, data: tag });
115 gen.if(false);
116 for (const tagValue in schema.mapping) {
117 gen.elseIf((0, 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, (0, codegen_1.str) `}`);
123}
124function serializeProperties(cxt) {
125 const { gen } = cxt;
126 gen.add(names_1.default.json, (0, codegen_1.str) `{`);
127 serializeSchemaProperties(cxt);
128 gen.add(names_1.default.json, (0, codegen_1.str) `}`);
129}
130function 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 let firstProp;
138 for (const key of props) {
139 if (first)
140 first = false;
141 else
142 gen.add(names_1.default.json, (0, codegen_1.str) `,`);
143 serializeProperty(key, properties[key], keyValue(key));
144 }
145 if (first)
146 firstProp = gen.let("first", true);
147 for (const key of optProps) {
148 const value = keyValue(key);
149 gen.if((0, codegen_1.and)((0, codegen_1._) `${value} !== undefined`, (0, code_1.isOwnProperty)(gen, data, key)), () => {
150 addComma(cxt, firstProp);
151 serializeProperty(key, optionalProperties[key], value);
152 });
153 }
154 if (schema.additionalProperties) {
155 gen.forIn("key", data, (key) => gen.if(isAdditional(key, allProps), () => serializeKeyValue(cxt, key, {}, firstProp)));
156 }
157 function keys(ps) {
158 return ps ? Object.keys(ps) : [];
159 }
160 function allProperties(ps) {
161 if (discriminator)
162 ps.push(discriminator);
163 if (new Set(ps).size !== ps.length) {
164 throw new Error("JTD: properties/optionalProperties/disciminator overlap");
165 }
166 return ps;
167 }
168 function keyValue(key) {
169 return gen.const("value", (0, codegen_1._) `${data}${(0, codegen_1.getProperty)(key)}`);
170 }
171 function serializeProperty(key, propSchema, value) {
172 gen.add(names_1.default.json, (0, codegen_1.str) `${JSON.stringify(key)}:`);
173 serializeCode({ ...cxt, schema: propSchema, data: value });
174 }
175 function isAdditional(key, ps) {
176 return ps.length ? (0, codegen_1.and)(...ps.map((p) => (0, codegen_1._) `${key} !== ${p}`)) : true;
177 }
178}
179function serializeType(cxt) {
180 const { gen, schema, data } = cxt;
181 switch (schema.type) {
182 case "boolean":
183 gen.add(names_1.default.json, (0, codegen_1._) `${data} ? "true" : "false"`);
184 break;
185 case "string":
186 serializeString(cxt);
187 break;
188 case "timestamp":
189 gen.if((0, codegen_1._) `${data} instanceof Date`, () => gen.add(names_1.default.json, (0, codegen_1._) `'"' + ${data}.toISOString() + '"'`), () => serializeString(cxt));
190 break;
191 default:
192 serializeNumber(cxt);
193 }
194}
195function serializeString({ gen, data }) {
196 gen.add(names_1.default.json, (0, codegen_1._) `${(0, util_1.useFunc)(gen, quote_1.default)}(${data})`);
197}
198function serializeNumber({ gen, data }) {
199 gen.add(names_1.default.json, (0, codegen_1._) `"" + ${data}`);
200}
201function serializeRef(cxt) {
202 const { gen, self, data, definitions, schema, schemaEnv } = cxt;
203 const { ref } = schema;
204 const refSchema = definitions[ref];
205 if (!refSchema)
206 throw new ref_error_1.default(self.opts.uriResolver, "", ref, `No definition ${ref}`);
207 if (!(0, ref_1.hasRef)(refSchema))
208 return serializeCode({ ...cxt, schema: refSchema });
209 const { root } = schemaEnv;
210 const sch = compileSerializer.call(self, new __1.SchemaEnv({ schema: refSchema, root }), definitions);
211 gen.add(names_1.default.json, (0, codegen_1._) `${getSerialize(gen, sch)}(${data})`);
212}
213function getSerialize(gen, sch) {
214 return sch.serialize
215 ? gen.scopeValue("serialize", { ref: sch.serialize })
216 : (0, codegen_1._) `${gen.scopeValue("wrapper", { ref: sch })}.serialize`;
217}
218function serializeEmpty({ gen, data }) {
219 gen.add(names_1.default.json, (0, codegen_1._) `JSON.stringify(${data})`);
220}
221function addComma({ gen }, first) {
222 if (first) {
223 gen.if(first, () => gen.assign(first, false), () => gen.add(names_1.default.json, (0, codegen_1.str) `,`));
224 }
225 else {
226 gen.add(names_1.default.json, (0, codegen_1.str) `,`);
227 }
228}
229//# sourceMappingURL=serialize.js.map
\No newline at end of file