UNPKG

@matatbread/typia

Version:

Superfast runtime validators with only one line

335 lines 20.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProtobufDecodeProgrammer = void 0; const typescript_1 = __importDefault(require("typescript")); const ExpressionFactory_1 = require("../../factories/ExpressionFactory"); const IdentifierFactory_1 = require("../../factories/IdentifierFactory"); const MetadataCollection_1 = require("../../factories/MetadataCollection"); const MetadataFactory_1 = require("../../factories/MetadataFactory"); const ProtobufFactory_1 = require("../../factories/ProtobufFactory"); const StatementFactory_1 = require("../../factories/StatementFactory"); const TypeFactory_1 = require("../../factories/TypeFactory"); const MetadataObjectType_1 = require("../../schemas/metadata/MetadataObjectType"); const MetadataProperty_1 = require("../../schemas/metadata/MetadataProperty"); const FeatureProgrammer_1 = require("../FeatureProgrammer"); const FunctionProgrammer_1 = require("../helpers/FunctionProgrammer"); const ProtobufUtil_1 = require("../helpers/ProtobufUtil"); var ProtobufDecodeProgrammer; (function (ProtobufDecodeProgrammer) { ProtobufDecodeProgrammer.decompose = (props) => { var _a; const collection = new MetadataCollection_1.MetadataCollection(); const meta = ProtobufFactory_1.ProtobufFactory.metadata({ method: props.modulo.getText(), checker: props.context.checker, transformer: props.context.transformer, collection, type: props.type, }); return { functions: Object.fromEntries(collection .objects() .filter((object) => ProtobufUtil_1.ProtobufUtil.isStaticObject(object)) .map((object) => [ `${PREFIX}o${object.index}`, StatementFactory_1.StatementFactory.constant({ name: props.functor.useLocal(`${PREFIX}o${object.index}`), value: write_object_function({ context: props.context, functor: props.functor, object, }), }), ])), statements: [], arrow: typescript_1.default.factory.createArrowFunction(undefined, undefined, [ IdentifierFactory_1.IdentifierFactory.parameter("input", typescript_1.default.factory.createTypeReferenceNode("Uint8Array")), ], props.context.importer.type({ file: "typia", name: "Resolved", arguments: [ typescript_1.default.factory.createTypeReferenceNode((_a = props.name) !== null && _a !== void 0 ? _a : TypeFactory_1.TypeFactory.getFullName({ checker: props.context.checker, type: props.type, })), ], }), undefined, typescript_1.default.factory.createBlock([ StatementFactory_1.StatementFactory.constant({ name: "reader", value: typescript_1.default.factory.createNewExpression(props.context.importer.internal("ProtobufReader"), undefined, [typescript_1.default.factory.createIdentifier("input")]), }), typescript_1.default.factory.createReturnStatement(decode_regular_object({ top: true, object: meta.objects[0].type, })), ], true)), }; }; ProtobufDecodeProgrammer.write = (props) => { const functor = new FunctionProgrammer_1.FunctionProgrammer(props.modulo.getText()); const result = ProtobufDecodeProgrammer.decompose(Object.assign(Object.assign({}, props), { functor })); return FeatureProgrammer_1.FeatureProgrammer.writeDecomposed({ modulo: props.modulo, functor, result, }); }; const write_object_function = (props) => typescript_1.default.factory.createArrowFunction(undefined, undefined, [ IdentifierFactory_1.IdentifierFactory.parameter("reader"), IdentifierFactory_1.IdentifierFactory.parameter("length", TypeFactory_1.TypeFactory.keyword("number"), ExpressionFactory_1.ExpressionFactory.number(-1)), ], TypeFactory_1.TypeFactory.keyword("any"), undefined, typescript_1.default.factory.createBlock([ typescript_1.default.factory.createExpressionStatement(typescript_1.default.factory.createBinaryExpression(typescript_1.default.factory.createIdentifier("length"), typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.EqualsToken), typescript_1.default.factory.createConditionalExpression(typescript_1.default.factory.createLessThan(typescript_1.default.factory.createIdentifier("length"), ExpressionFactory_1.ExpressionFactory.number(0)), undefined, callReader("size"), undefined, typescript_1.default.factory.createAdd(callReader("index"), typescript_1.default.factory.createIdentifier("length"))))), ...write_object_function_body({ context: props.context, condition: typescript_1.default.factory.createLessThan(callReader("index"), typescript_1.default.factory.createIdentifier("length")), tag: "tag", output: "output", object: props.object, }), typescript_1.default.factory.createReturnStatement(typescript_1.default.factory.createIdentifier("output")), ], true)); const write_object_function_body = (props) => { if (props.object.properties.some((p) => p.of_protobuf_ === undefined)) ProtobufFactory_1.ProtobufFactory.emplaceObject(props.object); const clauses = props.object.properties .map((p) => decode_property({ context: props.context, accessor: IdentifierFactory_1.IdentifierFactory.access(typescript_1.default.factory.createIdentifier(props.output), p.key.getSoleLiteral()), protobuf: p.of_protobuf_, metadata: p.value, })) .flat(); return [ StatementFactory_1.StatementFactory.constant({ name: props.output, value: typescript_1.default.factory.createAsExpression(typescript_1.default.factory.createObjectLiteralExpression(props.object.properties .filter((p) => !(props.context.compilerOptions.exactOptionalPropertyTypes === true && p.value.optional === true)) .map((p) => typescript_1.default.factory.createPropertyAssignment(IdentifierFactory_1.IdentifierFactory.identifier(p.key.getSoleLiteral()), write_property_default_value(p.value))), true), TypeFactory_1.TypeFactory.keyword("any")), }), typescript_1.default.factory.createWhileStatement(props.condition, typescript_1.default.factory.createBlock([ StatementFactory_1.StatementFactory.constant({ name: props.tag, value: callReader("uint32"), }), typescript_1.default.factory.createSwitchStatement(typescript_1.default.factory.createUnsignedRightShift(typescript_1.default.factory.createIdentifier(props.tag), ExpressionFactory_1.ExpressionFactory.number(3)), typescript_1.default.factory.createCaseBlock([ ...clauses, typescript_1.default.factory.createDefaultClause([ typescript_1.default.factory.createExpressionStatement(callReader("skipType", [ typescript_1.default.factory.createBitwiseAnd(typescript_1.default.factory.createIdentifier(props.tag), ExpressionFactory_1.ExpressionFactory.number(7)), ])), typescript_1.default.factory.createBreakStatement(), ]), ])), ])), ]; }; const write_property_default_value = (value) => typescript_1.default.factory.createAsExpression(value.nullable ? typescript_1.default.factory.createNull() : value.isRequired() === false ? typescript_1.default.factory.createIdentifier("undefined") : value.arrays.length ? typescript_1.default.factory.createArrayLiteralExpression() : value.maps.length ? typescript_1.default.factory.createNewExpression(typescript_1.default.factory.createIdentifier("Map"), undefined, []) : value.natives.length ? typescript_1.default.factory.createNewExpression(typescript_1.default.factory.createIdentifier("Uint8Array"), undefined, [typescript_1.default.factory.createArrayLiteralExpression([])]) : value.atomics.some((a) => a.type === "string") || value.constants.some((c) => c.type === "string" && c.values.some((v) => v.value === "")) || value.templates.some((tpl) => tpl.row.length === 1 && tpl.row[0].getName() === "string") ? typescript_1.default.factory.createStringLiteral("") : value.objects.length && value.objects.some((obj) => !ProtobufUtil_1.ProtobufUtil.isStaticObject(obj.type)) ? typescript_1.default.factory.createObjectLiteralExpression() : typescript_1.default.factory.createIdentifier("undefined"), TypeFactory_1.TypeFactory.keyword("any")); /* ----------------------------------------------------------- DECODERS ----------------------------------------------------------- */ const decode_property = (props) => props.protobuf.union.map((schema) => decode_property_type({ context: props.context, accessor: props.accessor, schema, required: props.metadata.isRequired() && props.metadata.nullable === false, })); const decode_property_type = (props) => { const out = (title, value) => typescript_1.default.factory.createCaseClause(ExpressionFactory_1.ExpressionFactory.number(props.schema.index), [ typescript_1.default.factory.createExpressionStatement(typescript_1.default.factory.createIdentifier(`// ${title}`)), ...(Array.isArray(value) ? value : [ typescript_1.default.factory.createExpressionStatement(typescript_1.default.factory.createBinaryExpression(props.accessor, typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.EqualsToken), value)), ]), typescript_1.default.factory.createBreakStatement(), ]); // ATOMICS if (props.schema.type === "bytes") return out("bytes", callReader("bytes")); else if (props.schema.type === "bool") return out("bool", callReader("bool")); else if (props.schema.type === "bigint") return out(props.schema.name, callReader(props.schema.name)); else if (props.schema.type === "number") return out(props.schema.name, decode_number(props.schema)); else if (props.schema.type === "string") return out("string", callReader("string")); // INSTANCES else if (props.schema.type === "array") return out(`Array<${props.schema.array.value.getName()}>`, decode_array({ accessor: props.accessor, schema: props.schema, required: props.required, })); else if (props.schema.type === "object") return out(props.schema.object.name, decode_regular_object({ top: false, object: props.schema.object, })); else if (props.schema.type === "map") if (props.schema.map instanceof MetadataObjectType_1.MetadataObjectType) { const key = props.schema.map.properties[0].key; const value = props.schema.map.properties[0].value; return out(`Record<${key.getName()}, ${value.getName()}>`, decode_map({ context: props.context, accessor: props.accessor, schema: props.schema, required: props.required, key, value, initializer: typescript_1.default.factory.createObjectLiteralExpression([]), setter: () => typescript_1.default.factory.createBinaryExpression(typescript_1.default.factory.createElementAccessExpression(props.accessor, typescript_1.default.factory.createIdentifier("entry.key")), typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.EqualsToken), typescript_1.default.factory.createIdentifier("entry.value")), })); } else { const key = props.schema.map.key; const value = props.schema.map.value; return out(`Map<${key.getName()}, ${value.getName()}>`, decode_map({ context: props.context, accessor: props.accessor, schema: props.schema, required: props.required, key, value, initializer: typescript_1.default.factory.createNewExpression(typescript_1.default.factory.createIdentifier("Map"), [TypeFactory_1.TypeFactory.keyword("any"), TypeFactory_1.TypeFactory.keyword("any")], []), setter: () => typescript_1.default.factory.createCallExpression(IdentifierFactory_1.IdentifierFactory.access(props.accessor, "set"), undefined, [ typescript_1.default.factory.createIdentifier("entry.key"), typescript_1.default.factory.createIdentifier("entry.value"), ]), })); } throw new Error("Error on ProtobufDecodeProgrammer.write(): unknown property type"); }; const decode_number = (schema) => { const value = callReader(schema.name); return schema.name === "int64" || schema.name === "uint64" ? typescript_1.default.factory.createCallExpression(typescript_1.default.factory.createIdentifier("Number"), undefined, [value]) : value; }; const decode_array = (props) => { const statements = []; if (props.required === false) statements.push(typescript_1.default.factory.createBinaryExpression(props.accessor, typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.QuestionQuestionEqualsToken), typescript_1.default.factory.createAsExpression(typescript_1.default.factory.createArrayLiteralExpression(), typescript_1.default.factory.createTypeReferenceNode("any[]")))); const decoder = decode_array_value(props.schema.value); if (["bool", "bigint", "number"].includes(props.schema.value.type)) { statements.push(typescript_1.default.factory.createIfStatement(typescript_1.default.factory.createStrictEquality(ExpressionFactory_1.ExpressionFactory.number(2), typescript_1.default.factory.createBitwiseAnd(typescript_1.default.factory.createIdentifier("tag"), ExpressionFactory_1.ExpressionFactory.number(7))), typescript_1.default.factory.createBlock([ StatementFactory_1.StatementFactory.constant({ name: "piece", value: typescript_1.default.factory.createAdd(callReader("uint32"), callReader("index")), }), typescript_1.default.factory.createWhileStatement(typescript_1.default.factory.createLessThan(callReader("index"), typescript_1.default.factory.createIdentifier("piece")), typescript_1.default.factory.createExpressionStatement(typescript_1.default.factory.createCallExpression(IdentifierFactory_1.IdentifierFactory.access(props.accessor, "push"), undefined, [decoder]))), ], true), typescript_1.default.factory.createExpressionStatement(typescript_1.default.factory.createCallExpression(IdentifierFactory_1.IdentifierFactory.access(props.accessor, "push"), undefined, [decoder])))); } else statements.push(typescript_1.default.factory.createCallExpression(IdentifierFactory_1.IdentifierFactory.access(props.accessor, "push"), undefined, [decoder])); return statements.map((stmt) => typescript_1.default.isExpression(stmt) ? typescript_1.default.factory.createExpressionStatement(stmt) : stmt); }; const decode_regular_object = (props) => typescript_1.default.factory.createCallExpression(typescript_1.default.factory.createIdentifier(`${PREFIX}o${props.object.index}`), undefined, [ typescript_1.default.factory.createIdentifier("reader"), ...(props.top ? [] : [callReader("uint32")]), ]); const decode_map = (props) => { const statements = [ ...(props.required === true ? [ typescript_1.default.factory.createBinaryExpression(props.accessor, typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.QuestionQuestionEqualsToken), props.initializer), ] : []), StatementFactory_1.StatementFactory.constant({ name: "piece", value: typescript_1.default.factory.createAdd(callReader("uint32"), callReader("index")), }), ...write_object_function_body({ context: props.context, condition: typescript_1.default.factory.createLessThan(callReader("index"), typescript_1.default.factory.createIdentifier("piece")), tag: "kind", output: "entry", object: createObjectType([ { key: "key", value: props.key, }, { key: "value", value: props.value, }, ]), }), ...(props.required === false ? [ typescript_1.default.factory.createBinaryExpression(props.accessor, typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.QuestionQuestionEqualsToken), props.initializer), ] : []), props.setter(), ]; return [ typescript_1.default.factory.createExpressionStatement(ExpressionFactory_1.ExpressionFactory.selfCall(typescript_1.default.factory.createBlock(statements.map((stmt) => typescript_1.default.isExpression(stmt) ? typescript_1.default.factory.createExpressionStatement(stmt) : stmt), true))), ]; }; const decode_array_value = (schema) => { if (schema.type === "bytes") return callReader("bytes"); else if (schema.type === "bool") return callReader("bool"); else if (schema.type === "bigint") return callReader(schema.name); else if (schema.type === "number") return decode_number(schema); else if (schema.type === "string") return callReader("string"); else if (schema.type === "object") return decode_regular_object({ top: false, object: schema.object, }); throw new Error("unreachable condition"); }; })(ProtobufDecodeProgrammer || (exports.ProtobufDecodeProgrammer = ProtobufDecodeProgrammer = {})); const PREFIX = "_pd"; const callReader = (method, args) => typescript_1.default.factory.createCallExpression(IdentifierFactory_1.IdentifierFactory.access(typescript_1.default.factory.createIdentifier("reader"), method), undefined, args); const createObjectType = (definitions) => { const properties = definitions.map((def) => MetadataProperty_1.MetadataProperty.create({ key: MetadataFactory_1.MetadataFactory.soleLiteral(def.key), value: def.value, description: null, jsDocTags: [], })); const obj = MetadataObjectType_1.MetadataObjectType.create({ name: "object.o" + Math.random().toString().slice(2), properties, description: undefined, jsDocTags: [], index: -1, validated: true, recursive: false, nullables: [false], }); ProtobufFactory_1.ProtobufFactory.emplaceObject(obj); return obj; }; //# sourceMappingURL=ProtobufDecodeProgrammer.js.map