UNPKG

express-cargo

Version:

express middleware for class-based request parsing

146 lines (145 loc) 5.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: Object.getOwnPropertyDescriptor(all, name).get }); } _export(exports, { get bindingCargo () { return bindingCargo; }, get getCargo () { return getCargo; } }); const _types = require("./types"); const _metadata = require("./metadata"); function getErrorKey(sourceKey, currentKey) { return sourceKey ? `${sourceKey}.${currentKey}` : currentKey; } function bindObject(objectClass, sources, errors, sourceKey = '') { const metaClass = new _metadata.CargoClassMetadata(objectClass.prototype); const targetObject = new objectClass(); const fields = metaClass.getFieldList(); const virtualFields = []; for (const property of fields){ const meta = metaClass.getFieldMetadata(property); if (!meta) continue; let value; const metaKey = meta.getKey(); const key = typeof metaKey === 'string' ? metaKey : metaKey.description; if (!key) { errors.push(new _types.CargoFieldError(getErrorKey(sourceKey, key), 'empty string or symbol is not allowed')); continue; } const requestTransformer = meta.getRequestTransformer(); if (requestTransformer) { try { value = requestTransformer(sources.req); } catch (error) { errors.push(new _types.CargoTransformFieldError(property, `Error while computing request transform field: ${error instanceof Error ? error.message : String(error)}`)); continue; } if (value === undefined || value === null) { if (meta.getOptional()) { targetObject[property] = null; } else { errors.push(new _types.CargoFieldError(getErrorKey(sourceKey, key), `${key} is required`)); } } else { targetObject[property] = value; } continue; } if (meta.getVirtualTransformer()) { virtualFields.push(property); continue; } const currentSource = meta.getSource(); const currentSourceData = sources[currentSource]; if (currentSourceData) { value = currentSourceData[key]; } if (value === undefined || value === null) { if (meta.getOptional()) { targetObject[property] = null; continue; } else { errors.push(new _types.CargoFieldError(getErrorKey(sourceKey, key), `${key} is required`)); continue; } } switch(meta.type){ case String: targetObject[property] = String(value); break; case Number: targetObject[property] = isNaN(Number(value)) ? value : Number(value); break; case Boolean: targetObject[property] = value === true || value === 'true'; break; case Date: targetObject[property] = new Date(value); break; default: { const nextSources = { ...sources, [currentSource]: value }; targetObject[property] = bindObject(meta.type, nextSources, errors, getErrorKey(sourceKey, key)); break; } } const transformer = meta.getTransformer(); if (transformer) { targetObject[property] = transformer(targetObject[property]); } for (const rule of meta.getValidators()){ if (!rule.validate(value)) { errors.push(new _types.CargoFieldError(key, rule.message)); } } } for (const property of virtualFields){ const meta = metaClass.getFieldMetadata(property); const transformer = meta.getVirtualTransformer(); try { targetObject[property] = transformer(targetObject); } catch (error) { errors.push(new _types.CargoTransformFieldError(property, `Error while computing virtual field: ${error instanceof Error ? error.message : String(error)}`)); } } return targetObject; } function bindingCargo(cargoClass) { return (req, res, next)=>{ try { const errors = []; const sources = { req: req, body: req.body, query: req.query, uri: req.params, header: req.headers, session: req.session }; const cargo = bindObject(cargoClass, sources, errors); if (errors.length > 0) { throw new _types.CargoValidationError(errors); } req._cargo = cargo; next(); } catch (err) { next(err); } }; } function getCargo(req) { return req._cargo; }