"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.excess = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var t = _interopRequireWildcard(require("io-ts")); var _Either = require("fp-ts/lib/Either"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ // Extra IO-TS type to not allow more keys than the defined ones. // Extracted from https://github.com/gcanti/io-ts/issues/322 const getIsCodec = tag => codec => codec._tag === tag; const isInterfaceCodec = getIsCodec('InterfaceType'); const isPartialCodec = getIsCodec('PartialType'); const isIntersectionType = getIsCodec('IntersectionType'); const getProps = codec => { switch (codec._tag) { case 'RefinementType': case 'ReadonlyType': return getProps(codec.type); case 'InterfaceType': case 'StrictType': case 'PartialType': return codec.props; case 'IntersectionType': return codec.types.reduce((props, type) => Object.assign(props, getProps(type)), {}); } }; const getNameFromProps = (props, isPartial) => Object.keys(props).map(k => `${k}${isPartial ? '?' : ''}: ${props[k].name}`).join(', '); /** * Provides a human-readable definition of the io-ts validator. * @param codec The io-ts declaration passed as an argument to the Excess method. * @remarks Since we currently use it only with objects, we'll cover the IntersectionType and PartialType */ const getExcessTypeName = codec => { if (isIntersectionType(codec)) { return `{ ${codec.types.map(subCodec => { if (isInterfaceCodec(subCodec)) { return getNameFromProps(subCodec.props, false); } if (isPartialCodec(subCodec)) { return getNameFromProps(subCodec.props, true); } return subCodec.name; }).filter(Boolean).join(', ')} }`; } return `Excess<${codec.name}>`; }; const stripKeys = (o, props) => { const keys = Object.getOwnPropertyNames(o); const propsKeys = Object.getOwnPropertyNames(props); propsKeys.forEach(pk => { const index = keys.indexOf(pk); if (index !== -1) { keys.splice(index, 1); } }); return keys.length ? (0, _Either.left)(keys) : (0, _Either.right)(o); }; /** * Validate if there are any keys that exist in the validated object, but they don't in the validation object. * @param codec The io-ts schema to wrap with this validation * @param name (optional) Replace the custom logic to name the validation error by providing a static name. */ const excess = (codec, name = getExcessTypeName(codec)) => { const props = getProps(codec); return new ExcessType(name, u => (0, _Either.isRight)(stripKeys(u, props)) && codec.is(u), (u, c) => _Either.either.chain(t.UnknownRecord.validate(u, c), () => _Either.either.chain(codec.validate(u, c), a => _Either.either.mapLeft(stripKeys(a, props), keys => keys.map(k => ({ value: a[k], context: c, message: `excess key '${k}' found` }))))), a => codec.encode(stripKeys(a, props).right), codec); }; exports.excess = excess; class ExcessType extends t.Type { constructor(name, is, validate, encode, type) { super(name, is, validate, encode); (0, _defineProperty2.default)(this, "_tag", 'ExcessType'); this.type = type; } }