runtypes
Version:
Runtime validation for static types
144 lines (143 loc) • 7.19 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
globalThis.Object.defineProperty(exports, "__esModule", { value: true });
const Never_js_1 = __importDefault(require("./Never.js"));
const Optional_js_1 = __importDefault(require("./Optional.js"));
const Runtype_js_1 = __importDefault(require("./Runtype.js"));
const FAILURE_js_1 = __importDefault(require("./utils-internal/FAILURE.js"));
const SUCCESS_js_1 = __importDefault(require("./utils-internal/SUCCESS.js"));
const copyProperties_js_1 = __importDefault(require("./utils-internal/copyProperties.js"));
const defineIntrinsics_js_1 = __importDefault(require("./utils-internal/defineIntrinsics.js"));
const defineProperty_js_1 = __importDefault(require("./utils-internal/defineProperty.js"));
const enumerableKeysOf_js_1 = __importDefault(require("./utils-internal/enumerableKeysOf.js"));
const hasEnumerableOwn_js_1 = __importDefault(require("./utils-internal/hasEnumerableOwn.js"));
const isObject_js_1 = __importDefault(require("./utils-internal/isObject.js"));
const Object = (fields) => {
return Runtype_js_1.default.create(({ received: x, innerValidate, expected, parsing, memoParsed: memoParsedInherited }) => {
if (x === null || x === undefined)
return FAILURE_js_1.default.TYPE_INCORRECT({ expected, received: x });
const keysOfFields = (0, enumerableKeysOf_js_1.default)(expected.fields);
if (keysOfFields.length !== 0 && typeof x !== "object")
return FAILURE_js_1.default.TYPE_INCORRECT({ expected, received: x });
const keys = [...new Set([...keysOfFields, ...(0, enumerableKeysOf_js_1.default)(x)])];
const results = {};
const memoParsed = memoParsedInherited ?? new WeakMap();
const parsed = (() => {
if ((0, isObject_js_1.default)(x)) {
const parsed = memoParsed.get(x) ?? {};
memoParsed.set(x, parsed);
return parsed;
}
else {
return {};
}
})();
for (const key of keys) {
const fieldsHasKey = (0, hasEnumerableOwn_js_1.default)(key, expected.fields);
const xHasKey = (0, hasEnumerableOwn_js_1.default)(key, x);
if (fieldsHasKey) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const runtype = expected.fields[key];
if (xHasKey) {
const received = x[key];
if (Optional_js_1.default.isOptional(runtype)) {
(0, defineProperty_js_1.default)(results, key, innerValidate({ expected: runtype.underlying, received, parsing, memoParsed }));
}
else {
(0, defineProperty_js_1.default)(results, key, innerValidate({ expected: runtype, received, parsing, memoParsed }));
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
if (results[key].success)
(0, defineProperty_js_1.default)(parsed, key, results[key].value);
}
else {
if (Optional_js_1.default.isOptional(runtype)) {
if ("default" in runtype) {
(0, defineProperty_js_1.default)(results, key, (0, SUCCESS_js_1.default)(runtype.default));
(0, defineProperty_js_1.default)(parsed, key, runtype.default);
}
else {
(0, defineProperty_js_1.default)(results, key, (0, SUCCESS_js_1.default)(undefined));
}
}
else {
(0, defineProperty_js_1.default)(results, key, FAILURE_js_1.default.PROPERTY_MISSING({ expected: runtype }));
}
}
}
else if (xHasKey) {
const received = x[key];
if (expected.isExact) {
(0, defineProperty_js_1.default)(results, key, FAILURE_js_1.default.PROPERTY_PRESENT({ expected: Never_js_1.default, received }));
}
else {
(0, defineProperty_js_1.default)(results, key, (0, SUCCESS_js_1.default)(received));
}
}
else {
throw new Error("impossible");
}
}
const details = {};
for (const key of keys) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const result = results[key];
if (!result.success)
(0, defineProperty_js_1.default)(details, key, result);
}
if ((0, enumerableKeysOf_js_1.default)(details).length !== 0)
return FAILURE_js_1.default.CONTENT_INCORRECT({ expected, received: x, details });
else
return (0, SUCCESS_js_1.default)(parsing ? parsed : x);
}, { tag: "object", fields, isExact: false }).with(self => (0, defineIntrinsics_js_1.default)({}, {
asPartial: () => {
const cloned = self.clone();
const existingKeys = (0, enumerableKeysOf_js_1.default)(self.fields);
const fields = {};
for (const key of existingKeys) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const value = self.fields[key];
(0, defineProperty_js_1.default)(fields, key, Optional_js_1.default.isOptional(value) ? value : (0, Optional_js_1.default)(value));
}
cloned.fields = fields;
return cloned;
},
asReadonly: () => self.clone(),
pick: (...keys) => {
const cloned = self.clone();
const existingKeys = (0, enumerableKeysOf_js_1.default)(self.fields);
const fields = {};
for (const key of existingKeys)
if (keys.includes(key))
(0, defineProperty_js_1.default)(fields, key, self.fields[key]);
cloned.fields = fields;
return cloned;
},
omit: (...keys) => {
const cloned = self.clone();
const existingKeys = (0, enumerableKeysOf_js_1.default)(self.fields);
const fields = {};
for (const key of existingKeys)
if (!keys.includes(key))
(0, defineProperty_js_1.default)(fields, key, self.fields[key]);
cloned.fields = fields;
return cloned;
},
extend: (extension) => {
const cloned = self.clone();
const fields = {};
(0, copyProperties_js_1.default)(fields, self.fields);
(0, copyProperties_js_1.default)(fields, extension);
cloned.fields = fields;
return cloned;
},
exact: () => {
const cloned = self.clone();
cloned.isExact = true;
return cloned;
},
}));
};
exports.default = Object;