You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					218 lines
				
				8.5 KiB
			
		
		
			
		
	
	
					218 lines
				
				8.5 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"use strict";
							 | 
						||
| 
								 | 
							
								Object.defineProperty(exports, "__esModule", { value: true });
							 | 
						||
| 
								 | 
							
								const types_1 = require("./types");
							 | 
						||
| 
								 | 
							
								const __1 = require("..");
							 | 
						||
| 
								 | 
							
								const codegen_1 = require("../codegen");
							 | 
						||
| 
								 | 
							
								const ref_error_1 = require("../ref_error");
							 | 
						||
| 
								 | 
							
								const names_1 = require("../names");
							 | 
						||
| 
								 | 
							
								const code_1 = require("../../vocabularies/code");
							 | 
						||
| 
								 | 
							
								const ref_1 = require("../../vocabularies/jtd/ref");
							 | 
						||
| 
								 | 
							
								const util_1 = require("../util");
							 | 
						||
| 
								 | 
							
								const quote_1 = require("../../runtime/quote");
							 | 
						||
| 
								 | 
							
								const genSerialize = {
							 | 
						||
| 
								 | 
							
								    elements: serializeElements,
							 | 
						||
| 
								 | 
							
								    values: serializeValues,
							 | 
						||
| 
								 | 
							
								    discriminator: serializeDiscriminator,
							 | 
						||
| 
								 | 
							
								    properties: serializeProperties,
							 | 
						||
| 
								 | 
							
								    optionalProperties: serializeProperties,
							 | 
						||
| 
								 | 
							
								    enum: serializeString,
							 | 
						||
| 
								 | 
							
								    type: serializeType,
							 | 
						||
| 
								 | 
							
								    ref: serializeRef,
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								function compileSerializer(sch, definitions) {
							 | 
						||
| 
								 | 
							
								    const _sch = __1.getCompilingSchema.call(this, sch);
							 | 
						||
| 
								 | 
							
								    if (_sch)
							 | 
						||
| 
								 | 
							
								        return _sch;
							 | 
						||
| 
								 | 
							
								    const { es5, lines } = this.opts.code;
							 | 
						||
| 
								 | 
							
								    const { ownProperties } = this.opts;
							 | 
						||
| 
								 | 
							
								    const gen = new codegen_1.CodeGen(this.scope, { es5, lines, ownProperties });
							 | 
						||
| 
								 | 
							
								    const serializeName = gen.scopeName("serialize");
							 | 
						||
| 
								 | 
							
								    const cxt = {
							 | 
						||
| 
								 | 
							
								        self: this,
							 | 
						||
| 
								 | 
							
								        gen,
							 | 
						||
| 
								 | 
							
								        schema: sch.schema,
							 | 
						||
| 
								 | 
							
								        schemaEnv: sch,
							 | 
						||
| 
								 | 
							
								        definitions,
							 | 
						||
| 
								 | 
							
								        data: names_1.default.data,
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    let sourceCode;
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								        this._compilations.add(sch);
							 | 
						||
| 
								 | 
							
								        sch.serializeName = serializeName;
							 | 
						||
| 
								 | 
							
								        gen.func(serializeName, names_1.default.data, false, () => {
							 | 
						||
| 
								 | 
							
								            gen.let(names_1.default.json, (0, codegen_1.str) ``);
							 | 
						||
| 
								 | 
							
								            serializeCode(cxt);
							 | 
						||
| 
								 | 
							
								            gen.return(names_1.default.json);
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								        gen.optimize(this.opts.code.optimize);
							 | 
						||
| 
								 | 
							
								        const serializeFuncCode = gen.toString();
							 | 
						||
| 
								 | 
							
								        sourceCode = `${gen.scopeRefs(names_1.default.scope)}return ${serializeFuncCode}`;
							 | 
						||
| 
								 | 
							
								        const makeSerialize = new Function(`${names_1.default.scope}`, sourceCode);
							 | 
						||
| 
								 | 
							
								        const serialize = makeSerialize(this.scope.get());
							 | 
						||
| 
								 | 
							
								        this.scope.value(serializeName, { ref: serialize });
							 | 
						||
| 
								 | 
							
								        sch.serialize = serialize;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    catch (e) {
							 | 
						||
| 
								 | 
							
								        if (sourceCode)
							 | 
						||
| 
								 | 
							
								            this.logger.error("Error compiling serializer, function code:", sourceCode);
							 | 
						||
| 
								 | 
							
								        delete sch.serialize;
							 | 
						||
| 
								 | 
							
								        delete sch.serializeName;
							 | 
						||
| 
								 | 
							
								        throw e;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    finally {
							 | 
						||
| 
								 | 
							
								        this._compilations.delete(sch);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return sch;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								exports.default = compileSerializer;
							 | 
						||
| 
								 | 
							
								function serializeCode(cxt) {
							 | 
						||
| 
								 | 
							
								    let form;
							 | 
						||
| 
								 | 
							
								    for (const key of types_1.jtdForms) {
							 | 
						||
| 
								 | 
							
								        if (key in cxt.schema) {
							 | 
						||
| 
								 | 
							
								            form = key;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    serializeNullable(cxt, form ? genSerialize[form] : serializeEmpty);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeNullable(cxt, serializeForm) {
							 | 
						||
| 
								 | 
							
								    const { gen, schema, data } = cxt;
							 | 
						||
| 
								 | 
							
								    if (!schema.nullable)
							 | 
						||
| 
								 | 
							
								        return serializeForm(cxt);
							 | 
						||
| 
								 | 
							
								    gen.if((0, codegen_1._) `${data} === undefined || ${data} === null`, () => gen.add(names_1.default.json, (0, codegen_1._) `"null"`), () => serializeForm(cxt));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeElements(cxt) {
							 | 
						||
| 
								 | 
							
								    const { gen, schema, data } = cxt;
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1.str) `[`);
							 | 
						||
| 
								 | 
							
								    const first = gen.let("first", true);
							 | 
						||
| 
								 | 
							
								    gen.forOf("el", data, (el) => {
							 | 
						||
| 
								 | 
							
								        addComma(cxt, first);
							 | 
						||
| 
								 | 
							
								        serializeCode({ ...cxt, schema: schema.elements, data: el });
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1.str) `]`);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeValues(cxt) {
							 | 
						||
| 
								 | 
							
								    const { gen, schema, data } = cxt;
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1.str) `{`);
							 | 
						||
| 
								 | 
							
								    const first = gen.let("first", true);
							 | 
						||
| 
								 | 
							
								    gen.forIn("key", data, (key) => serializeKeyValue(cxt, key, schema.values, first));
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1.str) `}`);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeKeyValue(cxt, key, schema, first) {
							 | 
						||
| 
								 | 
							
								    const { gen, data } = cxt;
							 | 
						||
| 
								 | 
							
								    addComma(cxt, first);
							 | 
						||
| 
								 | 
							
								    serializeString({ ...cxt, data: key });
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1.str) `:`);
							 | 
						||
| 
								 | 
							
								    const value = gen.const("value", (0, codegen_1._) `${data}${(0, codegen_1.getProperty)(key)}`);
							 | 
						||
| 
								 | 
							
								    serializeCode({ ...cxt, schema, data: value });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeDiscriminator(cxt) {
							 | 
						||
| 
								 | 
							
								    const { gen, schema, data } = cxt;
							 | 
						||
| 
								 | 
							
								    const { discriminator } = schema;
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1.str) `{${JSON.stringify(discriminator)}:`);
							 | 
						||
| 
								 | 
							
								    const tag = gen.const("tag", (0, codegen_1._) `${data}${(0, codegen_1.getProperty)(discriminator)}`);
							 | 
						||
| 
								 | 
							
								    serializeString({ ...cxt, data: tag });
							 | 
						||
| 
								 | 
							
								    gen.if(false);
							 | 
						||
| 
								 | 
							
								    for (const tagValue in schema.mapping) {
							 | 
						||
| 
								 | 
							
								        gen.elseIf((0, codegen_1._) `${tag} === ${tagValue}`);
							 | 
						||
| 
								 | 
							
								        const sch = schema.mapping[tagValue];
							 | 
						||
| 
								 | 
							
								        serializeSchemaProperties({ ...cxt, schema: sch }, discriminator);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    gen.endIf();
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1.str) `}`);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeProperties(cxt) {
							 | 
						||
| 
								 | 
							
								    const { gen } = cxt;
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1.str) `{`);
							 | 
						||
| 
								 | 
							
								    serializeSchemaProperties(cxt);
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1.str) `}`);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeSchemaProperties(cxt, discriminator) {
							 | 
						||
| 
								 | 
							
								    const { gen, schema, data } = cxt;
							 | 
						||
| 
								 | 
							
								    const { properties, optionalProperties } = schema;
							 | 
						||
| 
								 | 
							
								    const props = keys(properties);
							 | 
						||
| 
								 | 
							
								    const optProps = keys(optionalProperties);
							 | 
						||
| 
								 | 
							
								    const allProps = allProperties(props.concat(optProps));
							 | 
						||
| 
								 | 
							
								    let first = !discriminator;
							 | 
						||
| 
								 | 
							
								    for (const key of props) {
							 | 
						||
| 
								 | 
							
								        serializeProperty(key, properties[key], keyValue(key));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    for (const key of optProps) {
							 | 
						||
| 
								 | 
							
								        const value = keyValue(key);
							 | 
						||
| 
								 | 
							
								        gen.if((0, codegen_1.and)((0, codegen_1._) `${value} !== undefined`, (0, code_1.isOwnProperty)(gen, data, key)), () => serializeProperty(key, optionalProperties[key], value));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (schema.additionalProperties) {
							 | 
						||
| 
								 | 
							
								        gen.forIn("key", data, (key) => gen.if(isAdditional(key, allProps), () => serializeKeyValue(cxt, key, {}, gen.let("first", first))));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    function keys(ps) {
							 | 
						||
| 
								 | 
							
								        return ps ? Object.keys(ps) : [];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    function allProperties(ps) {
							 | 
						||
| 
								 | 
							
								        if (discriminator)
							 | 
						||
| 
								 | 
							
								            ps.push(discriminator);
							 | 
						||
| 
								 | 
							
								        if (new Set(ps).size !== ps.length) {
							 | 
						||
| 
								 | 
							
								            throw new Error("JTD: properties/optionalProperties/disciminator overlap");
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return ps;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    function keyValue(key) {
							 | 
						||
| 
								 | 
							
								        return gen.const("value", (0, codegen_1._) `${data}${(0, codegen_1.getProperty)(key)}`);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    function serializeProperty(key, propSchema, value) {
							 | 
						||
| 
								 | 
							
								        if (first)
							 | 
						||
| 
								 | 
							
								            first = false;
							 | 
						||
| 
								 | 
							
								        else
							 | 
						||
| 
								 | 
							
								            gen.add(names_1.default.json, (0, codegen_1.str) `,`);
							 | 
						||
| 
								 | 
							
								        gen.add(names_1.default.json, (0, codegen_1.str) `${JSON.stringify(key)}:`);
							 | 
						||
| 
								 | 
							
								        serializeCode({ ...cxt, schema: propSchema, data: value });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    function isAdditional(key, ps) {
							 | 
						||
| 
								 | 
							
								        return ps.length ? (0, codegen_1.and)(...ps.map((p) => (0, codegen_1._) `${key} !== ${p}`)) : true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeType(cxt) {
							 | 
						||
| 
								 | 
							
								    const { gen, schema, data } = cxt;
							 | 
						||
| 
								 | 
							
								    switch (schema.type) {
							 | 
						||
| 
								 | 
							
								        case "boolean":
							 | 
						||
| 
								 | 
							
								            gen.add(names_1.default.json, (0, codegen_1._) `${data} ? "true" : "false"`);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case "string":
							 | 
						||
| 
								 | 
							
								            serializeString(cxt);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        case "timestamp":
							 | 
						||
| 
								 | 
							
								            gen.if((0, codegen_1._) `${data} instanceof Date`, () => gen.add(names_1.default.json, (0, codegen_1._) `'"' + ${data}.toISOString() + '"'`), () => serializeString(cxt));
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        default:
							 | 
						||
| 
								 | 
							
								            serializeNumber(cxt);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeString({ gen, data }) {
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1._) `${(0, util_1.useFunc)(gen, quote_1.default)}(${data})`);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeNumber({ gen, data }) {
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1._) `"" + ${data}`);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeRef(cxt) {
							 | 
						||
| 
								 | 
							
								    const { gen, self, data, definitions, schema, schemaEnv } = cxt;
							 | 
						||
| 
								 | 
							
								    const { ref } = schema;
							 | 
						||
| 
								 | 
							
								    const refSchema = definitions[ref];
							 | 
						||
| 
								 | 
							
								    if (!refSchema)
							 | 
						||
| 
								 | 
							
								        throw new ref_error_1.default(self.opts.uriResolver, "", ref, `No definition ${ref}`);
							 | 
						||
| 
								 | 
							
								    if (!(0, ref_1.hasRef)(refSchema))
							 | 
						||
| 
								 | 
							
								        return serializeCode({ ...cxt, schema: refSchema });
							 | 
						||
| 
								 | 
							
								    const { root } = schemaEnv;
							 | 
						||
| 
								 | 
							
								    const sch = compileSerializer.call(self, new __1.SchemaEnv({ schema: refSchema, root }), definitions);
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1._) `${getSerialize(gen, sch)}(${data})`);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function getSerialize(gen, sch) {
							 | 
						||
| 
								 | 
							
								    return sch.serialize
							 | 
						||
| 
								 | 
							
								        ? gen.scopeValue("serialize", { ref: sch.serialize })
							 | 
						||
| 
								 | 
							
								        : (0, codegen_1._) `${gen.scopeValue("wrapper", { ref: sch })}.serialize`;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function serializeEmpty({ gen, data }) {
							 | 
						||
| 
								 | 
							
								    gen.add(names_1.default.json, (0, codegen_1._) `JSON.stringify(${data})`);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								function addComma({ gen }, first) {
							 | 
						||
| 
								 | 
							
								    gen.if(first, () => gen.assign(first, false), () => gen.add(names_1.default.json, (0, codegen_1.str) `,`));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								//# sourceMappingURL=serialize.js.map
							 |