UNPKG

nestjs-protobuf-es

Version:

Protobuf-ES integration for NestJS

99 lines (98 loc) 3.46 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isFieldRequired = isFieldRequired; const protobuf_1 = require("@bufbuild/protobuf"); const wire_1 = require("@bufbuild/protobuf/wire"); const wkt_1 = require("@bufbuild/protobuf/wkt"); const PV_EXT_NUMBER = 1159; const PV_FIELD_RULES_MAP = new Map([ [25, { name: 'required', type: protobuf_1.ScalarType.BOOL }], [27, { name: 'ignore', type: protobuf_1.ScalarType.INT32 }], ]); const PV_MESSAGE_RULES_MAP = new Map([[1, { name: 'disabled', type: protobuf_1.ScalarType.BOOL }]]); const IS_FIELD_REQUIRED_CACHE = new WeakMap(); /** * Returns true if the field is required by protovalidate or has the proto2 `required` label, or the Edition * feature field_presence = LEGACY_REQUIRED. * * Results for each field are cached for performance reasons. */ function isFieldRequired(field) { let required = IS_FIELD_REQUIRED_CACHE.get(field); if (required == null) { required = isProtoValidateRequired(field) || isLegacyRequired(field); IS_FIELD_REQUIRED_CACHE.set(field, required); } return required; } /** * Returns true if the field is required by protovalidate. * * Note that this function only applies to message fields (singular, repeated, map), * and always returns false for other field types. */ function isProtoValidateRequired(field) { if (!field.proto.options?.$unknown) { return false; } let fieldRules = {}; for (const uf of field.proto.options.$unknown) { if (uf.no !== PV_EXT_NUMBER) continue; fieldRules = { ...extractFields(uf.data, PV_FIELD_RULES_MAP) }; } if (!fieldRules.required || fieldRules.ignore === 3) { return false; } if (field.parent.proto.options?.$unknown) { let messageRules = {}; for (const uf of field.parent.proto.options.$unknown) { if (uf.no !== PV_EXT_NUMBER) continue; messageRules = { ...extractFields(uf.data, PV_MESSAGE_RULES_MAP) }; } if (messageRules.disabled) { return false; } } return true; } /** * Returns true if the field has the proto2 `required` label, or the Edition * feature field_presence = LEGACY_REQUIRED. * * Note that this function only applies to singular message fields, and always * returns false for other fields. */ function isLegacyRequired(field) { return (field.fieldKind === 'message' && field.presence === wkt_1.FeatureSet_FieldPresence.LEGACY_REQUIRED); } function extractFields(bytes, fieldMap) { const reader = new wire_1.BinaryReader(bytes); const end = reader.pos + reader.uint32(); const results = {}; let resultSize = 0; while (reader.pos < end) { const [fieldNo, wireType] = reader.tag(); const fieldDesc = fieldMap.get(fieldNo); if (!fieldDesc) { reader.skip(wireType); continue; } results[fieldDesc.name] = readValue(reader, fieldDesc.type); // Check if all fields were extracted and leave early. if (++resultSize === fieldMap.size) break; } return results; } function readValue(reader, type) { switch (type) { case protobuf_1.ScalarType.INT32: return reader.int32(); case protobuf_1.ScalarType.BOOL: return reader.bool(); default: throw new Error(`Unknown scalar type: ${type}`); } }