You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

funtypes

Package Overview
Dependencies
Maintainers
2
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

funtypes - npm Package Compare versions

Comparing version

to
5.0.0

lib/chunk-c374952a.mjs

54

.size-snapshot.json
{
"chunk-dd209c8b.js": {
"bundled": 31236,
"minified": 19651,
"gzipped": 6098
},
"readonly.js": {
"bundled": 1880,
"minified": 1532,
"gzipped": 529
},
"index.js": {
"bundled": 27341,
"minified": 17663,
"gzipped": 5534
"bundled": 1721,
"minified": 1391,
"gzipped": 482
},
"index.mjs": {
"bundled": 26898,
"minified": 17555,
"gzipped": 5501,
"bundled": 847,
"minified": 703,
"gzipped": 370,
"treeshaked": {
"rollup": {
"code": 0,
"code": 29,
"import_statements": 29
},
"webpack": {
"code": 1013
}
}
},
"chunk-c374952a.mjs": {
"bundled": 31026,
"minified": 19713,
"gzipped": 6139,
"treeshaked": {
"rollup": {
"code": 10493,
"import_statements": 0
},
"webpack": {
"code": 10513
"code": 11444
}
}
},
"readonly.mjs": {
"bundled": 991,
"minified": 827,
"gzipped": 432,
"treeshaked": {
"rollup": {
"code": 136,
"import_statements": 76
},
"webpack": {
"code": 1099
}
}
}
}

12

lib/index.d.ts

@@ -10,3 +10,8 @@ export { AsyncContract } from './asynccontract';

export { default as showValue } from './showValue';
export { Array, ReadonlyArray } from './types/array';
export { Readonly } from './types/Readonly';
export { Mutable } from './types/Mutable';
export { Array, Array as MutableArray, ReadonlyArray } from './types/array';
export { Object, Object as MutableObject, ReadonlyObject, Partial, Partial as MutablePartial, ReadonlyPartial, } from './types/Object';
export { Record, Record as MutableRecord, ReadonlyRecord } from './types/Record';
export { Tuple, Tuple as MutableTuple, ReadonlyTuple } from './types/tuple';
export type { ConstraintCheck } from './types/constraint';

@@ -23,7 +28,4 @@ export { Constraint, Guard } from './types/constraint';

export { Never } from './types/never';
export { Object, Partial } from './types/Object';
export { Boolean, Function, Number, String, Symbol } from './types/primative';
export { Readonly } from './types/Readonly';
export { Record } from './types/Record';
export { Tuple } from './types/tuple';
export { Sealed } from './types/Sealed';
export { Union } from './types/union';

@@ -30,0 +32,0 @@ export { Unknown } from './types/unknown';

"use strict";
function isParsedValueRuntype(e) {
return "tag" in e && "parsed" === e.tag;
}
function ParsedValue(e, t) {
return (
assertRuntype(e),
create(
"parsed",
{
p: (r, n, s) =>
((e, t, r) => {
if (!e.success) return e;
if (!e.cycle) {
const n = t(e.value);
return (n.success && r && innerGuard(r, n.value, createGuardVisitedState())) || n;
}
return innerMapValidationPlaceholder(
Array.isArray(e.placeholder) ? [...e.placeholder] : { ...e.placeholder },
() => e.unwrap(),
t,
r,
);
})(s(e, r), e => t.parse(e), t.test),
t(r, n) {
return t.test
? n(t.test, r)
: failure((t.name || `ParsedValue<${show(e)}>`) + " does not support Runtype.test");
},
s(r, n, s) {
if (!t.serialize)
return failure(
(t.name || `ParsedValue<${show(e)}>`) + " does not support Runtype.serialize",
);
const a = t.test ? innerGuard(t.test, r, createGuardVisitedState()) : void 0;
if (a) return a;
const o = t.serialize(r);
return o.success ? s(e, o.value) : o;
},
},
{
underlying: e,
config: t,
show() {
return t.name || `ParsedValue<${show(e, !1)}>`;
},
},
)
);
}
function assertRuntype(...e) {
for (const r of e) if (!r || !r[t]) throw new Error("Expected Runtype but got " + showValue(r));
}
function create(e, r, n) {
function safeParse(e) {
return innerValidate(s, e, createVisitedState());
}
function safeSerialize(e) {
return innerSerialize(s, e, createVisitedState());
}
const s = {
...n,
tag: e,
assert(e) {
const t = innerGuard(s, e, createGuardVisitedState());
if (t) throw new ValidationError(t);
},
parse(e) {
const t = safeParse(e);
if (!t.success) throw new ValidationError(t);
return t.value;
},
safeParse,
test: e => void 0 === innerGuard(s, e, createGuardVisitedState()),
serialize(e) {
const t = safeSerialize(e);
if (!t.success) throw new ValidationError(t);
return t.value;
},
safeSerialize,
Or: e => Union(s, e),
And: e => Intersect(s, e),
withConstraint: (e, t) => Constraint(s, e, t),
withGuard: (e, t) => Constraint(s, e, t),
withBrand: e => Brand(e, s),
withParser: e => ParsedValue(s, e),
toString: () => `Runtype<${show(s)}>`,
[t]: "function" == typeof r ? { p: r } : r,
};
return s;
}
function createValidationPlaceholder(e, t) {
return innerMapValidationPlaceholder(e, () => t(e) || success(e));
}
function innerMapValidationPlaceholder(e, t, r, n) {
let s,
a = !1;
const o = {
success: !0,
cycle: !0,
placeholder: e,
unwrap() {
if (s) return (a = !0), s;
s = success(e);
const i = t(),
l = i.success && r ? r(i.value) : i;
if (!l.success) return (s = l);
if (a) {
const e = ((e, t) =>
e === t
? success(t)
: Array.isArray(e) && Array.isArray(t)
? (e.splice(0, e.length, ...t), success(e))
: e &&
"object" == typeof e &&
!Array.isArray(e) &&
t &&
"object" == typeof t &&
!Array.isArray(t)
? (Object.assign(e, t), success(e))
: failure(
`Cannot convert a value of type "${
Array.isArray(e) ? "Array" : typeof e
}" into a value of type "${
null === t ? "null" : Array.isArray(t) ? "Array" : typeof t
}" when it contains cycles.`,
))(s.value, l.value),
t = e.success && n && innerGuard(n, e.value, createGuardVisitedState());
s = t || e;
} else {
const e = n && innerGuard(n, l.value, createGuardVisitedState());
s = e || l;
}
return s.success && (o.placeholder = s.value), s;
},
};
return o;
}
function createVisitedState() {
return new Map();
}
function createGuardVisitedState() {
return new Map();
}
function innerValidate(e, t, r) {
const n = innerValidateToPlaceholder(e, t, r);
return n.cycle ? n.unwrap() : n;
}
function innerValidateToPlaceholder(e, r, n) {
var s;
const a = n,
o = e[t],
i = null === (s = a.get(e)) || void 0 === s ? void 0 : s.get(r);
if (void 0 !== i) return i;
const l = o.p(
r,
(e, t) => innerValidate(e, t, n),
(e, t) => innerValidateToPlaceholder(e, t, n),
);
return l.cycle ? (a.set(e, (a.get(e) || new Map()).set(r, l)), l) : l;
}
function innerSerialize(e, t, r) {
const n = innerSerializeToPlaceholder(e, t, r);
return n.cycle ? n.unwrap() : n;
}
function innerSerializeToPlaceholder(e, r, n) {
var s;
const a = n,
o = e[t],
i = null === (s = a.get(e)) || void 0 === s ? void 0 : s.get(r);
if (void 0 !== i) return i;
let l = (o.s || o.p)(
r,
(e, t) => innerSerialize(e, t, n),
(e, t) => innerSerializeToPlaceholder(e, t, n),
);
return l.cycle ? (a.set(e, (a.get(e) || new Map()).set(r, l)), l) : l;
}
function innerGuard(e, r, n) {
var s;
const a = n,
o = e[t];
if (r && ("object" == typeof r || "function" == typeof r)) {
if (null === (s = a.get(e)) || void 0 === s ? void 0 : s.has(r)) return;
a.set(e, (a.get(e) || new Set()).add(r));
}
if (o.t) return o.t(r, (e, t) => innerGuard(e, t, n));
let i = o.p(
r,
(e, t) => innerGuard(e, t, n) || success(t),
(e, t) => innerGuard(e, t, n) || success(t),
);
return i.cycle && (i = i.unwrap()), i.success ? void 0 : i;
}
function showValue(e, r = 3, n = 30) {
switch (typeof e) {
case "bigint":
case "boolean":
case "number":
return "" + e;
case "string":
return JSON.stringify(e);
case "object":
if (null === e) return "null";
if (Array.isArray(e)) {
if (0 === r || 0 === n) return "[Array]";
{
let t = "[",
s = 0;
for (s = 0; s < e.length && n > t.length; s++)
0 !== s && (t += ", "), (t += showValue(e[s], r - 1, n - t.length));
return s < e.length && (t += " ... "), (t += "]"), t;
}
}
if ((e => "object" == typeof e && null != e && t in e)(e)) return e.toString();
if (0 === r) return "{Object}";
{
const t = Object.entries(e);
let s = "{",
a = 0;
for (a = 0; a < t.length && n > s.length; a++) {
0 !== a && (s += ", ");
const [e, o] = t[a];
s += `${/\s/.test(e) ? JSON.stringify(e) : e}: ${showValue(o, r - 1, n - s.length)}`;
}
return a < t.length && (s += " ... "), (s += "}"), s;
}
case "function":
case "symbol":
case "undefined":
default:
return typeof e;
}
}
function success(e) {
return { success: !0, value: e };
}
function failure(e, t = {}) {
return { success: !1, message: e, ...t };
}
function expected(e, t, r = {}) {
return failure(`Expected ${"string" == typeof e ? e : show(e)}, but was ${showValue(t)}`, r);
}
function unableToAssign(e, t, ...r) {
return [
`Unable to assign ${showValue(e)} to ${"string" == typeof t ? t : show(t)}`,
...r.map(toFullError),
];
}
function andError([e, ...t]) {
return [`And ${e[0].toLocaleLowerCase()}${e.substr(1)}`, ...t];
}
function typesAreNotCompatible(e, ...t) {
return [`The types of ${e} are not compatible`, ...t.map(toFullError)];
}
function toFullError(e) {
return "string" == typeof e ? [e] : Array.isArray(e) ? e : toFullError(e.fullError || e.message);
}
function showError(e) {
return e.fullError ? showFullError(e.fullError) : e.key ? `${e.message} in ${e.key}` : e.message;
}
function showFullError([e, ...t], r = "") {
return [`${r}${e}`, ...t.map(e => showFullError(e, r + " "))].join("\n");
}
function InternalArr(e, t) {
assertRuntype(e);
const r = create(
"array",
(t, n) =>
Array.isArray(t)
? createValidationPlaceholder([...t], s => {
let a,
o = void 0;
for (let i = 0; i < t.length; i++) {
const l = n(e, t[i]);
l.success
? (s[i] = l.value)
: (o || (o = unableToAssign(t, r)),
o.push(typesAreNotCompatible(`[${i}]`, l)),
(a =
a ||
failure(l.message, {
key: l.key ? `[${i}].${l.key}` : `[${i}]`,
fullError: o,
})));
}
return a;
})
: expected("an Array", t),
{
isReadonly: t,
element: e,
show() {
return `${t ? "readonly " : ""}${show(e, !0)}[]`;
},
},
);
return t || (r.asReadonly = () => InternalArr(e, !0)), r;
}
function Constraint(e, t, r) {
assertRuntype(e);
const n = create(
"constraint",
(s, a) => {
const o = r && r.name,
i = a(e, s);
if (!i.success) return i;
const l = t(i.value);
if (!l || "string" == typeof l) {
const e = "string" == typeof l ? l : `${showValue(s)} failed ${o || "constraint"} check`;
return failure(e, { fullError: unableToAssign(s, n, e) });
}
return success(i.value);
},
{
underlying: e,
constraint: t,
name: r && r.name,
args: r && r.args,
show(t) {
return (r && r.name) || `WithConstraint<${show(e, t)}>`;
},
},
);
return n;
}
function Intersect(...e) {
return (
assertRuntype(...e),
create(
"intersect",
(t, r) => {
if (Array.isArray(t))
return createValidationPlaceholder([...t], t => {
for (const n of e) {
let e = r(n, t);
if (!e.success) return e;
if (!Array.isArray(e.value))
return failure(
`The validator ${show(
n,
)} attempted to convert the type of this value from an array to something else. That conversion is not valid as the child of an intersect`,
);
t.splice(0, t.length, ...e.value);
}
});
if (t && "object" == typeof t)
return createValidationPlaceholder(Object.create(null), n => {
for (const s of e) {
let e = r(s, t);
if (!e.success) return e;
if (!e.value || "object" != typeof e.value)
return failure(
`The validator ${show(
s,
)} attempted to convert the type of this value from an object to something else. That conversion is not valid as the child of an intersect`,
);
Object.assign(n, e.value);
}
});
let n = t;
for (const t of e) {
let e = r(t, n);
if (!e.success) return e;
n = e.value;
}
return success(n);
},
{
intersectees: e,
show(t) {
return parenthesize("" + e.map(e => show(e, !0)).join(" & "), t);
},
},
)
);
}
function lazyValue(e) {
let t;
return () => t || (t = e());
}
function Literal(e) {
return create(
"literal",
t =>
t === e
? success(t)
: failure(
`Expected literal ${showValue(e)}, but was ${showValue(t)}${
typeof t != typeof e ? ` (i.e. a ${typeof t})` : ""
}`,
),
{
value: e,
show() {
return showValue(e);
},
},
);
}
function hasKey(e, t) {
return "object" == typeof t && e in t;
}
function InternalObject(e, t, r) {
assertRuntype(...Object.values(e));
const n = create(
"object",
(r, s) =>
null == r || "object" != typeof r
? expected(n, r)
: Array.isArray(r)
? failure(`Expected ${show(n)}, but was an Array`)
: createValidationPlaceholder(Object.create(null), a => {
let o,
i = void 0;
for (const l in e)
if (!t || (hasKey(l, r) && void 0 !== r[l])) {
const u = t || hasKey(l, r) ? r[l] : void 0;
let c = s(e[l], u);
c.success
? (a[l] = c.value)
: (i || (i = unableToAssign(r, n)),
i.push(typesAreNotCompatible(`"${l}"`, c)),
(o =
o || failure(c.message, { key: c.key ? `${l}.${c.key}` : l, fullError: i })));
}
return o;
}),
{
isPartial: t,
isReadonly: r,
fields: e,
asPartial: () => InternalObject(n.fields, !0, n.isReadonly),
asReadonly: () => InternalObject(n.fields, n.isPartial, !0),
pick(...n) {
const s = {};
for (const t of n) s[t] = e[t];
return InternalObject(s, t, r);
},
omit(...n) {
const s = { ...e };
for (const e of n) e in s && delete s[e];
return InternalObject(s, t, r);
},
show() {
const n = Object.keys(e);
return n.length
? `{ ${n
.map(n => `${r ? "readonly " : ""}${n}${t ? "?" : ""}: ${show(e[n], !1)};`)
.join(" ")} }`
: "{}";
},
},
);
return n;
}
function createPrimative(e) {
return create(
e,
t =>
typeof t === e
? success(t)
: failure(
`Expected ${e}, but was ${(e =>
`${showValue(e)}${"string" == typeof e ? " (i.e. a string literal)" : ""}`)(t)}`,
),
{},
);
}
function getExpectedBaseType(e) {
switch (e.tag) {
case "string":
return "string";
case "number":
return "number";
case "literal":
return typeof e.value;
case "union":
const t = e.alternatives.map(getExpectedBaseType);
return t.reduce((e, t) => (e === t ? e : "mixed"), t[0]);
case "constraint":
return getExpectedBaseType(e.underlying);
}
}
function Brand(e, t) {
return (
assertRuntype(t),
create("brand", (e, r, n) => n(t, e), {
brand: e,
entity: t,
show(e) {
return show(t, e);
},
})
);
}
function isUnionType(e) {
return "tag" in e && "union" === e.tag;
}
function resolveUnderlyingType(e, t) {
return (e => "tag" in e && "lazy" === e.tag)(e)
? resolveUnderlyingType(e.underlying(), t)
: (e => "tag" in e && "brand" === e.tag)(e)
? resolveUnderlyingType(e.entity, t)
: (e => "tag" in e && "constraint" === e.tag)(e) ||
(e => "tag" in e && "named" === e.tag)(e) ||
("p" === t && isParsedValueRuntype(e))
? resolveUnderlyingType(e.underlying, t)
: "t" === t && isParsedValueRuntype(e)
? e.config.test
? resolveUnderlyingType(e.config.test, t)
: a
: "s" === t && isParsedValueRuntype(e)
? e.config.serialize
? e.config.test
? resolveUnderlyingType(e.config.test, t)
: e
: a
: e;
}
function mapGet(e) {
return (t, r) => {
const n = e.get(t);
if (void 0 !== n) return n;
const s = r();
return e.set(t, s), s;
};
}
function findFields(e, t) {
const r = resolveUnderlyingType(e, t),
n = [],
pushField = (e, r) => {
const s = resolveUnderlyingType(r, t);
if (isUnionType(s)) for (const t of s.alternatives) pushField(e, t);
else n.push([e, s]);
};
if ("tag" in (s = r) && "object" === s.tag && !r.isPartial)
for (const e of Object.keys(r.fields)) pushField(e, r.fields[e]);
var s;
if (
((e => "tag" in e && "tuple" === e.tag)(r) &&
r.components.forEach((e, t) => {
pushField("" + t, e);
}),
(e => "tag" in e && "intersect" === e.tag)(r))
)
for (const e of r.intersectees) n.push(...findFields(e, t));
return n;
}
function Union(...e) {
function validateWithKey(e, t) {
const r =
"" +
Array.from(t.values())
.map(e => show(e, !0))
.join(" | ");
return (n, s) => {
if (!n || "object" != typeof n) return expected(r, n);
const a = t.get(n[e]);
if (a) {
const t = s(a, n);
return t.success
? t
: failure(t.message, {
key: `<${/^\d+$/.test(e) ? `[${e}]` : e}: ${showValue(n[e])}>${
t.key ? "." + t.key : ""
}`,
fullError: unableToAssign(n, r, t),
});
}
{
const s = expected(
Array.from(t.keys())
.map(e => ("string" == typeof e ? `'${e}'` : e))
.join(" | "),
n[e],
{ key: /^\d+$/.test(e) ? `[${e}]` : e },
);
return (
(s.fullError = unableToAssign(
n,
r,
typesAreNotCompatible(/^\d+$/.test(e) ? `[${e}]` : `"${e}"`, s.message),
)),
s
);
}
};
}
function validateWithoutKey(e) {
return (t, r) => {
let s;
for (const a of e) {
const e = r(a, t);
if (e.success) return e;
s
? s.push(andError(e.fullError || unableToAssign(t, a, e)))
: (s = unableToAssign(t, n, e.fullError || unableToAssign(t, a, e)));
}
return expected(n, t, { fullError: s });
};
}
assertRuntype(...e);
const t = [];
for (const r of e) isUnionType(r) ? t.push(...r.alternatives) : t.push(r);
const validatorOf = e => {
const r = t
.filter(t => "never" !== resolveUnderlyingType(t, e).tag)
.map(t => [t, findFields(t, e)]),
n = r.filter(e => 0 !== e[1].length),
s = r.filter(e => 0 === e[1].length),
a = (e => {
const t = (e => {
const t = new Set(e[0]);
for (const r of e) for (const e of t) r.has(e) || t.delete(e);
return t;
})(e.map(([, e]) => new Set(e.map(([e]) => e)))),
r = new Map(["type", "kind", "tag", "version"].map(e => [e, new Map()]));
for (const [s, a] of e)
for (const [e, o] of a)
if ("tag" in (n = o) && "literal" === n.tag) {
const n = mapGet(r)(e, () => new Map());
n.has(o.value) ? t.delete(e) : n.set(o.value, s);
} else t.delete(e);
var n;
for (const [e, n] of r) if (t.has(e)) return [e, n];
})(n);
if (a && s.length) {
const e = a && validateWithKey(a[0], a[1]),
t = validateWithoutKey(s.map(e => e[0]));
return (r, n) => {
const s = e(r, n);
if (s.success) return s;
const a = t(r, n);
return (
a.success ||
a.fullError.push(andError(s.fullError ? s.fullError : unableToAssign(r, "Object"))),
a
);
};
}
return a ? validateWithKey(a[0], a[1]) : validateWithoutKey(t);
},
r = lazyValue(() => ({ p: validatorOf("p"), s: validatorOf("s"), t: validatorOf("t") })),
n = create(
"union",
{
p: (e, t) => r().p(e, t),
s: (e, t) => r().s(e, t),
t(e, t) {
const n = r().s(e, (e, r) => t(e, r) || success(r));
return n.success ? void 0 : n;
},
},
{
alternatives: t,
match: (...t) => r => {
const s = createVisitedState();
for (let n = 0; n < e.length; n++) {
const a = innerValidate(e[n], r, s);
if (a.success) return t[n](a.value);
}
n.assert(r);
},
show(e) {
return parenthesize("" + t.map(e => show(e, !0)).join(" | "), e);
},
},
);
return n;
}
Object.defineProperty(exports, "__esModule", { value: !0 });
const parenthesize = (e, t) => (t ? `(${e})` : e),
e = new Set(),
show = (t, r = !1) => {
if (e.has(t) && "lazy" !== t.tag) return parenthesize("CIRCULAR " + t.tag, r);
if (t.show) {
e.add(t);
try {
return t.show(r);
} finally {
e.delete(t);
}
}
return t.tag;
},
t = "__internal_runtype_methods__";
class ValidationError extends Error {
constructor(e) {
super(showError(e)),
(this.name = "ValidationError"),
(this.shortMessage = e.message),
(this.key = e.key),
(this.fullError = e.fullError);
}
}
const r = create("unknown", e => success(e), {}),
n = Literal(void 0),
s = Literal(null),
a = create("never", e => expected("nothing", e), {}),
o = createPrimative("boolean"),
i = createPrimative("function"),
l = createPrimative("number"),
u = createPrimative("string"),
c = createPrimative("symbol");
(exports.Array = e => InternalArr(e, !1)),
(exports.AsyncContract = (e, t) => ({
enforce: r => (...n) => {
if (n.length < e.length)
return Promise.reject(
new ValidationError({
message: `Expected ${e.length} arguments but only received ${n.length}`,
}),
);
const s = createVisitedState();
for (let t = 0; t < e.length; t++) {
const r = innerValidate(e[t], n[t], s);
if (!r.success) return Promise.reject(new ValidationError(r));
n[t] = r.value;
}
const a = r(...n);
return a instanceof Promise
? a.then(e => {
const r = innerGuard(t, e, createGuardVisitedState());
if (r) throw new ValidationError(r);
return e;
})
: Promise.reject(
new ValidationError({
message: "Expected function to return a promise, but instead got " + a,
}),
);
},
})),
(exports.Boolean = o),
(exports.Brand = Brand),
(exports.Constraint = Constraint),
(exports.Contract = (e, t) => ({
enforce: r => (...n) => {
if (n.length < e.length)
throw new ValidationError({
message: `Expected ${e.length} arguments but only received ${n.length}`,
});
const s = createVisitedState();
for (let t = 0; t < e.length; t++) {
const r = innerValidate(e[t], n[t], s);
if (!r.success) throw new ValidationError(r);
n[t] = r.value;
}
const a = r(...n),
o = innerGuard(t, a, createGuardVisitedState());
if (o) throw new ValidationError(o);
return a;
},
})),
(exports.Enum = (e, t) => {
const r = Object.values(t),
n = new Set(r.some(e => "number" == typeof e) ? r.filter(e => "number" == typeof e) : r);
return create("enum", t => (n.has(t) ? success(t) : expected(e, t)), {
enumObject: t,
show: () => e,
});
}),
(exports.Function = i),
(exports.Guard = (e, t) => r.withGuard(e, t)),
(exports.InstanceOf = e =>
create("instanceof", t => (t instanceof e ? success(t) : expected("" + e.name, t)), {
ctor: e,
show() {
return `InstanceOf<${e.name}>`;
},
})),
(exports.Intersect = Intersect),
(exports.KeyOf = e => {
const t = new Set(Object.keys(e)),
r = [...t]
.sort()
.map(e => showValue(e))
.join(" | ");
return create(
"keyOf",
e => (t.has("number" == typeof e ? e.toString() : e) ? success(e) : expected(r, e)),
{ keys: t, show: e => parenthesize(r, e) },
);
}),
(exports.Lazy = e => {
const t = lazyValue(e);
return create("lazy", (e, r, n) => n(t(), e), {
underlying: t,
show(e) {
return show(t(), e);
},
});
}),
(exports.Literal = Literal),
(exports.Named = (e, t) => (
assertRuntype(t),
create("named", (e, r) => r(t, e), {
underlying: t,
name: e,
show() {
return e;
},
})
)),
(exports.Never = a),
(exports.Null = s),
(exports.Number = l),
(exports.Object = e => InternalObject(e, !1, !1)),
(exports.ParsedValue = ParsedValue),
(exports.Partial = e => InternalObject(e, !0, !1)),
(exports.Readonly = function Readonly(e) {
const t = { ...e };
t.isReadonly = !0;
for (const r of ["asPartial", "pick", "omit"])
"function" == typeof e[r] && (t[r] = (...t) => Readonly(e[r](...t)));
return t;
}),
(exports.ReadonlyArray = e => InternalArr(e, !0)),
(exports.Record = (e, t) => {
assertRuntype(e, t);
const r = lazyValue(() => getExpectedBaseType(e)),
n = create(
"record",
(s, a) =>
null == s || "object" != typeof s
? expected(n, s)
: Object.getPrototypeOf(s) !== Object.prototype && null !== Object.getPrototypeOf(s)
? Array.isArray(s)
? failure("Expected Record, but was Array")
: failure(`Expected ${show(n)}, but was ${Object.getPrototypeOf(s)}`)
: createValidationPlaceholder(Object.create(null), n => {
for (const o in s) {
let i = null;
if ("number" === r()) {
if (isNaN(+o)) return expected("record key to be a number", o);
i = a(e, +o);
} else
"string" === r()
? (i = a(e, o))
: ((i = a(e, o)), i.success || isNaN(+o) || (i = a(e, +o)));
if (!i.success) return expected("record key to be " + show(e), o);
const l = a(t, s[o]);
if (!l.success) return failure(l.message, { key: l.key ? `${o}.${l.key}` : o });
n[i.value] = l.value;
}
}),
{
key: e,
value: t,
isReadonly: !1,
show() {
return `{ [_: ${show(e, !1)}]: ${show(t, !1)} }`;
},
},
);
return n;
}),
(exports.String = u),
(exports.Symbol = c),
(exports.Tuple = (...e) => {
assertRuntype(...e);
const t = create(
"tuple",
(r, n) =>
Array.isArray(r)
? r.length !== e.length
? expected("an array of length " + e.length, r.length)
: createValidationPlaceholder([...r], s => {
let a,
o = void 0;
for (let i = 0; i < e.length; i++) {
let l = n(e[i], r[i]);
l.success
? (s[i] = l.value)
: (o || (o = unableToAssign(r, t)),
o.push(typesAreNotCompatible(`[${i}]`, l)),
(a =
a ||
failure(l.message, {
key: l.key ? `[${i}].${l.key}` : `[${i}]`,
fullError: o,
})));
}
return a;
})
: expected("tuple to be an array", r),
{
components: e,
isReadonly: !1,
show() {
return `[${e.map(e => show(e, !1)).join(", ")}]`;
},
},
);
return t;
}),
(exports.Undefined = n),
(exports.Union = Union),
(exports.Unknown = r),
(exports.ValidationError = ValidationError),
(exports.assertType = (e, t) => {
e.assert(t);
}),
(exports.showError = showError),
(exports.showType = show),
(exports.showValue = showValue);
var e = require("./chunk-dd209c8b.js");
(exports.Array = e.Arr),
(exports.AsyncContract = e.AsyncContract),
(exports.Boolean = e.Boolean),
(exports.Brand = e.Brand),
(exports.Constraint = e.Constraint),
(exports.Contract = e.Contract),
(exports.Enum = e.Enum),
(exports.Function = e.Function),
(exports.Guard = e.Guard),
(exports.InstanceOf = e.InstanceOf),
(exports.Intersect = e.Intersect),
(exports.KeyOf = e.KeyOf),
(exports.Lazy = e.Lazy),
(exports.Literal = e.Literal),
(exports.Mutable = e.Mutable),
(exports.MutableArray = e.Arr),
(exports.MutableObject = e.Obj),
(exports.MutablePartial = e.Partial),
(exports.MutableRecord = e.Record),
(exports.MutableTuple = e.Tuple),
(exports.Named = e.Named),
(exports.Never = e.Never),
(exports.Null = e.Null),
(exports.Number = e.Number),
(exports.Object = e.Obj),
(exports.ParsedValue = e.ParsedValue),
(exports.Partial = e.Partial),
(exports.Readonly = e.Readonly),
(exports.ReadonlyArray = e.ReadonlyArray),
(exports.ReadonlyObject = e.ReadonlyObject),
(exports.ReadonlyPartial = e.ReadonlyPartial),
(exports.ReadonlyRecord = e.ReadonlyRecord),
(exports.ReadonlyTuple = e.ReadonlyTuple),
(exports.Record = e.Record),
(exports.Sealed = e.Sealed),
(exports.String = e.String),
(exports.Symbol = e.Sym),
(exports.Tuple = e.Tuple),
(exports.Undefined = e.Undefined),
(exports.Union = e.Union),
(exports.Unknown = e.Unknown),
(exports.ValidationError = e.ValidationError),
(exports.assertType = e.assertType),
(exports.showError = e.showError),
(exports.showType = e.show),
(exports.showValue = e.showValue);

@@ -1,3 +0,12 @@

import { Result, Union, Intersect, Constraint, ConstraintCheck, Brand, Failure } from './index';
import { ParsedValue, ParsedValueConfig } from './types/ParsedValue';
import type * as t from '.';
import type { Result, Failure } from './result';
import { ParsedValueConfig } from './types/ParsedValue';
interface Helpers {
readonly Union: typeof t.Union;
readonly Intersect: typeof t.Intersect;
readonly Constraint: typeof t.Constraint;
readonly Brand: typeof t.Brand;
readonly ParsedValue: typeof t.ParsedValue;
}
export declare function provideHelpers(h: Helpers): void;
export declare type InnerValidateHelper = <T>(runtype: RuntypeBase<T>, value: unknown) => Result<T>;

@@ -11,6 +20,29 @@ declare const internalSymbol: unique symbol;

}) | Cycle<T>;
export declare type SealedState = {
readonly keysFromIntersect?: ReadonlySet<string>;
readonly deep: boolean;
} | false;
export interface InternalValidation<TParsed> {
p(x: any, innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown) => Result<T>, innerValidateToPlaceholder: <T>(runtype: RuntypeBase<T>, value: unknown) => ResultWithCycle<T>): ResultWithCycle<TParsed>;
t?: (x: any, innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown) => Failure | undefined) => Failure | undefined;
s?: (x: any, innerSerialize: (runtype: RuntypeBase, value: unknown) => Result<any>, innerSerializeToPlaceholder: (runtype: RuntypeBase, value: unknown) => ResultWithCycle<any>) => ResultWithCycle<any>;
/**
* parse
*/
p(x: any, innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown, sealed?: SealedState) => Result<T>, innerValidateToPlaceholder: <T>(runtype: RuntypeBase<T>, value: unknown, sealed?: SealedState) => ResultWithCycle<T>, mode: 'p' | 's' | 't', sealed: SealedState): ResultWithCycle<TParsed>;
/**
* test
*/
t?: (x: any, innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown, sealed?: SealedState) => Failure | undefined, sealed: SealedState) => Failure | undefined;
/**
* serialize
*/
s?: (x: any, innerSerialize: (runtype: RuntypeBase, value: unknown, sealed?: SealedState) => Result<any>, innerSerializeToPlaceholder: (runtype: RuntypeBase, value: unknown, sealed?: SealedState) => ResultWithCycle<any>, mode: 's', sealed: SealedState) => ResultWithCycle<any>;
/**
* get underlying type
*/
u?: (mode: 'p' | 's' | 't') => RuntypeBase | undefined;
/**
* get fields, not called if "u" is implemented, can return
* undefined to indicate that arbitrarily many fields are
* possible.
*/
f?: (mode: 'p' | 't' | 's') => ReadonlySet<string> | undefined;
}

@@ -61,7 +93,7 @@ /**

*/
Or<B extends RuntypeBase>(B: B): Union<[this, B]>;
Or<B extends RuntypeBase>(B: B): t.Union<[this, B]>;
/**
* Intersect this Runtype with another.
*/
And<B extends RuntypeBase>(B: B): Intersect<[this, B]>;
And<B extends RuntypeBase>(B: B): t.Intersect<[this, B]>;
/**

@@ -80,6 +112,6 @@ * Use an arbitrary constraint function to validate a runtype, and optionally

*/
withConstraint<T extends Static<this>, K = unknown>(constraint: ConstraintCheck<this>, options?: {
withConstraint<T extends Static<this>, K = unknown>(constraint: t.ConstraintCheck<this>, options?: {
name?: string;
args?: K;
}): Constraint<this, T, K>;
}): t.Constraint<this, T, K>;
/**

@@ -103,11 +135,11 @@ * Helper function to convert an underlying Runtype into another static type

args?: K;
}): Constraint<this, T, K>;
}): t.Constraint<this, T, K>;
/**
* Adds a brand to the type.
*/
withBrand<B extends string>(brand: B): Brand<B, this>;
withBrand<B extends string>(brand: B): t.Brand<B, this>;
/**
* Apply conversion functions when parsing/serializing this value
*/
withParser<TParsed>(value: ParsedValueConfig<this, TParsed>): ParsedValue<this, TParsed>;
withParser<TParsed>(value: ParsedValueConfig<this, TParsed>): t.ParsedValue<this, TParsed>;
}

@@ -146,2 +178,6 @@ export interface Codec<TParsed> extends Runtype<TParsed> {

};
/**
* Get the underlying type of a runtype, if it is a wrapper around another type
*/
export declare function unwrapRuntype(t: RuntypeBase, mode: 'p' | 's' | 't'): RuntypeBase;
export declare function createValidationPlaceholder<T>(placeholder: T, fn: (placeholder: T) => Failure | undefined): Cycle<T>;

@@ -155,5 +191,10 @@ export declare function mapValidationPlaceholder<T, S>(source: ResultWithCycle<T>, fn: (placeholder: T) => Result<S>, extraGuard?: RuntypeBase<S>): ResultWithCycle<S>;

export declare function createGuardVisitedState(): OpaqueGuardVisitedState;
export declare function innerValidate<T>(targetType: RuntypeBase<T>, value: any, $visited: OpaqueVisitedState): Result<T>;
export declare function innerSerialize<T>(targetType: RuntypeBase<T>, value: any, $visited: OpaqueVisitedState): Result<T>;
export declare function innerGuard(targetType: RuntypeBase, value: any, $visited: OpaqueGuardVisitedState): Failure | undefined;
export declare function innerValidate<T>(targetType: RuntypeBase<T>, value: any, $visited: OpaqueVisitedState, sealed: SealedState): Result<T>;
export declare function innerSerialize<T>(targetType: RuntypeBase<T>, value: any, $visited: OpaqueVisitedState, sealed: SealedState): Result<T>;
export declare function innerGuard(targetType: RuntypeBase, value: any, $visited: OpaqueGuardVisitedState, sealed: SealedState): Failure | undefined;
/**
* Get the possible fields for a runtype
* Returns "undefined" if there can be arbitrary fields (e.g. Record<string, number>)
*/
export declare function getFields(t: RuntypeBase, mode: 'p' | 's' | 't'): ReadonlySet<string> | undefined;
export {};

@@ -10,3 +10,2 @@ import { RuntypeBase, Static, Codec } from '../runtype';

}
export declare function isBrandRuntype(runtype: RuntypeBase): runtype is Brand<string, RuntypeBase>;
export declare function Brand<B extends string, A extends RuntypeBase<unknown>>(brand: B, entity: A): Brand<B, A>;
import { RuntypeBase, Static, Codec } from '../runtype';
import { Unknown } from './unknown';
export declare type ConstraintCheck<A extends RuntypeBase<unknown>> = (x: Static<A>) => boolean | string;
export declare function isConstraintRuntype(runtype: RuntypeBase): runtype is Constraint<RuntypeBase, unknown, unknown>;
export interface Constraint<TUnderlying extends RuntypeBase<unknown>, TConstrained extends Static<TUnderlying> = Static<TUnderlying>, TArgs = unknown> extends Codec<TConstrained> {

@@ -6,0 +5,0 @@ readonly tag: 'constraint';

@@ -7,3 +7,2 @@ import { RuntypeBase, Codec, Static } from '../runtype';

export declare function lazyValue<T>(fn: () => T): () => T;
export declare function isLazyRuntype(runtype: RuntypeBase): runtype is Lazy<RuntypeBase>;
/**

@@ -10,0 +9,0 @@ * Construct a possibly-recursive Runtype.

import { RuntypeBase, Static, Codec } from '../runtype';
export declare type ConstraintCheck<A extends RuntypeBase<unknown>> = (x: Static<A>) => boolean | string;
export declare function isNamedRuntype(runtype: RuntypeBase): runtype is Named<RuntypeBase>;
export interface Named<TUnderlying extends RuntypeBase<unknown>> extends Codec<Static<TUnderlying>> {

@@ -5,0 +4,0 @@ readonly tag: 'named';

@@ -33,2 +33,4 @@ import { Static, RuntypeBase, Codec } from '../runtype';

declare function Obj<O extends RecordFields>(fields: O): Obj<O, false>;
export declare function ReadonlyObject<O extends RecordFields>(fields: O): Obj<O, true>;
export declare function Partial<O extends RecordFields>(fields: O): Partial<O, false>;
export declare function ReadonlyPartial<O extends RecordFields>(fields: O): Partial<O, true>;

@@ -8,3 +8,2 @@ import { Result } from '../result';

}
export declare function isParsedValueRuntype(runtype: RuntypeBase): runtype is ParsedValue<RuntypeBase, unknown>;
export interface ParsedValueConfig<TUnderlying extends RuntypeBase<unknown>, TParsed> {

@@ -11,0 +10,0 @@ name?: string;

@@ -28,1 +28,2 @@ import { Static, RuntypeBase, Codec } from '../runtype';

export declare function Record<K extends KeyRuntypeBase, V extends RuntypeBase<unknown>>(key: K, value: V): Record<K, V>;
export declare function ReadonlyRecord<K extends KeyRuntypeBase, V extends RuntypeBase<unknown>>(key: K, value: V): ReadonlyRecord<K, V>;

@@ -23,1 +23,2 @@ import { RuntypeBase, Codec } from '../runtype';

export declare function Tuple<T extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]] | readonly []>(...components: T): Tuple<T>;
export declare function ReadonlyTuple<T extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]] | readonly []>(...components: T): ReadonlyTuple<T>;
{
"name": "funtypes",
"version": "4.2.0",
"version": "5.0.0",
"description": "Runtime validation for static types",

@@ -9,2 +9,21 @@ "main": "./lib/index.js",

"sideEffects": false,
"exports": {
"./readonly": {
"types": "./lib/readonly.d.ts",
"import": "./lib/readonly.mjs",
"default": "./lib/readonly.js"
},
".": {
"types": "./lib/index.d.ts",
"import": "./lib/index.mjs",
"default": "./lib/index.js"
}
},
"typesVersions": {
"*": {
"readonly": [
"lib/readonly.d.ts"
]
}
},
"scripts": {

@@ -15,3 +34,2 @@ "postbuild": "tsc --noEmit && rimraf lib/**/*.spec.*",

"test": "jest $([ \"$CI\" = true ] && echo --coverage || echo --watch)",
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls",
"typecheck": "tsc --noEmit --watch"

@@ -22,6 +40,5 @@ },

"devDependencies": {
"@types/jest": "24.0.18",
"coveralls": "^3.0.6",
"jest": "24.9.0",
"prettier": "^2.1.1",
"@types/jest": "^27.4.1",
"jest": "^27.5.1",
"prettier": "^2.6.0",
"rollup": "^2.26.11",

@@ -32,5 +49,5 @@ "rollup-plugin-prettier": "^2.1.0",

"rollup-plugin-typescript2": "^0.27.2",
"ts-jest": "^24.1.0",
"ts-jest": "^27.1.3",
"type-assertions": "^1.1.0",
"typescript": "4.0.2"
"typescript": "^4.6.2"
},

@@ -37,0 +54,0 @@ "keywords:": [

@@ -10,3 +10,3 @@ import { sizeSnapshot } from 'rollup-plugin-size-snapshot';

index: 'src/index.ts',
// contracts: 'src/contracts.ts',
readonly: 'src/readonly.ts',
},

@@ -17,2 +17,3 @@ output: [

entryFileNames: '[name].js',
chunkFileNames: 'chunk-[hash].js',
format: 'cjs',

@@ -23,3 +24,3 @@ },

entryFileNames: '[name].mjs',
chunkFileNames: '[name]-[hash].mjs',
chunkFileNames: 'chunk-[hash].mjs',
format: 'es',

@@ -26,0 +27,0 @@ },

@@ -23,36 +23,38 @@ import { ValidationError } from './errors';

return {
enforce: (f: (...args: any[]) => any) => (...args: any[]) => {
if (args.length < argTypes.length) {
return Promise.reject(
new ValidationError({
message: `Expected ${argTypes.length} arguments but only received ${args.length}`,
}),
);
}
const visited: OpaqueVisitedState = createVisitedState();
for (let i = 0; i < argTypes.length; i++) {
const result = innerValidate(argTypes[i], args[i], visited);
if (result.success) {
args[i] = result.value;
} else {
return Promise.reject(new ValidationError(result));
enforce:
(f: (...args: any[]) => any) =>
(...args: any[]) => {
if (args.length < argTypes.length) {
return Promise.reject(
new ValidationError({
message: `Expected ${argTypes.length} arguments but only received ${args.length}`,
}),
);
}
}
const returnedPromise = f(...args);
if (!(returnedPromise instanceof Promise)) {
return Promise.reject(
new ValidationError({
message: `Expected function to return a promise, but instead got ${returnedPromise}`,
}),
);
}
return returnedPromise.then(value => {
const result = innerGuard(returnType, value, createGuardVisitedState());
if (result) {
throw new ValidationError(result);
const visited: OpaqueVisitedState = createVisitedState();
for (let i = 0; i < argTypes.length; i++) {
const result = innerValidate(argTypes[i], args[i], visited, false);
if (result.success) {
args[i] = result.value;
} else {
return Promise.reject(new ValidationError(result));
}
}
return value;
});
},
const returnedPromise = f(...args);
if (!(returnedPromise instanceof Promise)) {
return Promise.reject(
new ValidationError({
message: `Expected function to return a promise, but instead got ${returnedPromise}`,
}),
);
}
return returnedPromise.then(value => {
const result = innerGuard(returnType, value, createGuardVisitedState(), false);
if (result) {
throw new ValidationError(result);
}
return value;
});
},
};
}

@@ -23,24 +23,26 @@ import {

return {
enforce: (f: (...args: A) => Z) => (...args: A): Z => {
if (args.length < argTypes.length)
throw new ValidationError({
message: `Expected ${argTypes.length} arguments but only received ${args.length}`,
});
const visited: OpaqueVisitedState = createVisitedState();
for (let i = 0; i < argTypes.length; i++) {
const result = innerValidate(argTypes[i], args[i], visited);
if (result.success) {
args[i] = result.value;
} else {
enforce:
(f: (...args: A) => Z) =>
(...args: A): Z => {
if (args.length < argTypes.length)
throw new ValidationError({
message: `Expected ${argTypes.length} arguments but only received ${args.length}`,
});
const visited: OpaqueVisitedState = createVisitedState();
for (let i = 0; i < argTypes.length; i++) {
const result = innerValidate(argTypes[i], args[i], visited, false);
if (result.success) {
args[i] = result.value;
} else {
throw new ValidationError(result);
}
}
const rawResult = f(...args);
const result = innerGuard(returnType, rawResult, createGuardVisitedState(), false);
if (result) {
throw new ValidationError(result);
}
}
const rawResult = f(...args);
const result = innerGuard(returnType, rawResult, createGuardVisitedState());
if (result) {
throw new ValidationError(result);
}
return rawResult;
},
return rawResult;
},
};
}

@@ -63,3 +63,3 @@ import {

);
const leftHand: Hand = { left: (null as any) as Hand };
const leftHand: Hand = { left: null as any as Hand };
const rightHand: Hand = { right: leftHand };

@@ -72,3 +72,3 @@ leftHand.left = rightHand;

);
const ambi: Ambi = { left: (null as any) as Ambi, right: (null as any) as Ambi };
const ambi: Ambi = { left: null as any as Ambi, right: null as any as Ambi };
ambi.left = ambi;

@@ -844,3 +844,3 @@ ambi.right = ambi;

fail('value passed validation even though it was not expected to');
} catch (exception) {
} catch (exception: any) {
const { shortMessage: errorMessage, key: errorKey } = exception;

@@ -847,0 +847,0 @@

@@ -0,1 +1,8 @@

import { provideHelpers } from './runtype';
import { Brand } from './types/brand';
import { Constraint } from './types/constraint';
import { Intersect } from './types/intersect';
import { ParsedValue } from './types/ParsedValue';
import { Union } from './types/union';
export { AsyncContract } from './asynccontract';

@@ -11,4 +18,18 @@ export { Contract } from './contract';

export { Readonly } from './types/Readonly';
export { Mutable } from './types/Mutable';
export { Array, Array as MutableArray, ReadonlyArray } from './types/array';
export {
Object,
Object as MutableObject,
ReadonlyObject,
Partial,
Partial as MutablePartial,
ReadonlyPartial,
} from './types/Object';
export { Record, Record as MutableRecord, ReadonlyRecord } from './types/Record';
export { Tuple, Tuple as MutableTuple, ReadonlyTuple } from './types/tuple';
// TODO: should we export StaticIntersect, StaticTuple, StaticUnion etc.
export { Array, ReadonlyArray } from './types/array';
export type { ConstraintCheck } from './types/constraint';

@@ -25,7 +46,4 @@ export { Constraint, Guard } from './types/constraint';

export { Never } from './types/never';
export { Object, Partial } from './types/Object';
export { Boolean, Function, Number, String, Symbol } from './types/primative';
export { Readonly } from './types/Readonly';
export { Record } from './types/Record';
export { Tuple } from './types/tuple';
export { Sealed } from './types/Sealed';
export { Union } from './types/union';

@@ -35,1 +53,9 @@ export { Unknown } from './types/unknown';

export { ParsedValue } from './types/ParsedValue';
provideHelpers({
Union,
Intersect,
Constraint,
Brand,
ParsedValue,
});

@@ -1,11 +0,32 @@

import { Result, Union, Intersect, Constraint, ConstraintCheck, Brand, Failure } from './index';
import type * as t from '.';
// import { Union, Intersect, Constraint, ConstraintCheck, Brand, ParsedValue, ParsedValueConfig } from './index';
import type { Result, Failure } from './result';
import show from './show';
import { ValidationError } from './errors';
import { ParsedValue, ParsedValueConfig } from './types/ParsedValue';
import { ParsedValueConfig } from './types/ParsedValue';
import showValue from './showValue';
import { failure, success } from './result';
// let Union: typeof t.Union;
// let Intersect: typeof t.Intersect;
// let Constraint: typeof t.Constraint;
// let Brand: typeof t.Brand;
// let ParsedValue: typeof t.ParsedValue;
// Importing these directly creates a cycle
interface Helpers {
readonly Union: typeof t.Union;
readonly Intersect: typeof t.Intersect;
readonly Constraint: typeof t.Constraint;
readonly Brand: typeof t.Brand;
readonly ParsedValue: typeof t.ParsedValue;
}
let helpers: Helpers;
export function provideHelpers(h: Helpers) {
helpers = h;
}
export type InnerValidateHelper = <T>(runtype: RuntypeBase<T>, value: unknown) => Result<T>;
declare const internalSymbol: unique symbol;
const internal: typeof internalSymbol = ('__internal_runtype_methods__' as unknown) as typeof internalSymbol;
const internal: typeof internalSymbol =
'__internal_runtype_methods__' as unknown as typeof internalSymbol;

@@ -24,12 +45,36 @@ export function assertRuntype(...values: RuntypeBase[]) {

export type ResultWithCycle<T> = (Result<T> & { cycle?: false }) | Cycle<T>;
export type SealedState =
| { readonly keysFromIntersect?: ReadonlySet<string>; readonly deep: boolean }
| false;
export interface InternalValidation<TParsed> {
/**
* parse
*/
p(
x: any,
innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown) => Result<T>,
innerValidateToPlaceholder: <T>(runtype: RuntypeBase<T>, value: unknown) => ResultWithCycle<T>,
innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown, sealed?: SealedState) => Result<T>,
innerValidateToPlaceholder: <T>(
runtype: RuntypeBase<T>,
value: unknown,
sealed?: SealedState,
) => ResultWithCycle<T>,
mode: 'p' | 's' | 't',
sealed: SealedState,
): ResultWithCycle<TParsed>;
/**
* test
*/
t?: (
x: any,
innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown) => Failure | undefined,
innerValidate: <T>(
runtype: RuntypeBase<T>,
value: unknown,
sealed?: SealedState,
) => Failure | undefined,
sealed: SealedState,
) => Failure | undefined;
/**
* serialize
*/
s?: (

@@ -39,6 +84,24 @@ // any is used here to ensure TypeScript still treats RuntypeBase as

x: any,
innerSerialize: (runtype: RuntypeBase, value: unknown) => Result<any>,
innerSerializeToPlaceholder: (runtype: RuntypeBase, value: unknown) => ResultWithCycle<any>,
innerSerialize: (runtype: RuntypeBase, value: unknown, sealed?: SealedState) => Result<any>,
innerSerializeToPlaceholder: (
runtype: RuntypeBase,
value: unknown,
sealed?: SealedState,
) => ResultWithCycle<any>,
mode: 's',
sealed: SealedState,
) => ResultWithCycle<any>;
/**
* get underlying type
*/
u?: (mode: 'p' | 's' | 't') => RuntypeBase | undefined;
/**
* get fields, not called if "u" is implemented, can return
* undefined to indicate that arbitrarily many fields are
* possible.
*/
f?: (mode: 'p' | 't' | 's') => ReadonlySet<string> | undefined;
}
/**

@@ -95,3 +158,3 @@ * A runtype determines at runtime whether a value conforms to a type specification.

*/
Or<B extends RuntypeBase>(B: B): Union<[this, B]>;
Or<B extends RuntypeBase>(B: B): t.Union<[this, B]>;

@@ -101,3 +164,3 @@ /**

*/
And<B extends RuntypeBase>(B: B): Intersect<[this, B]>;
And<B extends RuntypeBase>(B: B): t.Intersect<[this, B]>;

@@ -118,5 +181,5 @@ /**

withConstraint<T extends Static<this>, K = unknown>(
constraint: ConstraintCheck<this>,
constraint: t.ConstraintCheck<this>,
options?: { name?: string; args?: K },
): Constraint<this, T, K>;
): t.Constraint<this, T, K>;

@@ -141,3 +204,3 @@ /**

options?: { name?: string; args?: K },
): Constraint<this, T, K>;
): t.Constraint<this, T, K>;

@@ -147,3 +210,3 @@ /**

*/
withBrand<B extends string>(brand: B): Brand<B, this>;
withBrand<B extends string>(brand: B): t.Brand<B, this>;

@@ -153,3 +216,3 @@ /**

*/
withParser<TParsed>(value: ParsedValueConfig<this, TParsed>): ParsedValue<this, TParsed>;
withParser<TParsed>(value: ParsedValueConfig<this, TParsed>): t.ParsedValue<this, TParsed>;
}

@@ -210,3 +273,3 @@

assert(x: any): asserts x is Static<TConfig> {
const validated = innerGuard(A, x, createGuardVisitedState());
const validated = innerGuard(A, x, createGuardVisitedState(), false);
if (validated) {

@@ -227,35 +290,34 @@ throw new ValidationError(validated);

safeSerialize,
Or: <B extends RuntypeBase>(B: B): Union<[Codec<Static<TConfig>>, B]> => Union(A, B),
And: <B extends RuntypeBase>(B: B): Intersect<[Codec<Static<TConfig>>, B]> => Intersect(A, B),
Or: <B extends RuntypeBase>(B: B): t.Union<[Codec<Static<TConfig>>, B]> => helpers.Union(A, B),
And: <B extends RuntypeBase>(B: B): t.Intersect<[Codec<Static<TConfig>>, B]> =>
helpers.Intersect(A, B),
withConstraint: <T extends Static<TConfig>, K = unknown>(
constraint: ConstraintCheck<Codec<Static<TConfig>>>,
constraint: t.ConstraintCheck<Codec<Static<TConfig>>>,
options?: { name?: string; args?: K },
): Constraint<Codec<Static<TConfig>>, T, K> =>
Constraint<Codec<Static<TConfig>>, T, K>(A, constraint, options),
): t.Constraint<Codec<Static<TConfig>>, T, K> =>
helpers.Constraint<Codec<Static<TConfig>>, T, K>(A, constraint, options),
withGuard: <T extends Static<TConfig>, K = unknown>(
test: (x: Static<TConfig>) => x is T,
options?: { name?: string; args?: K },
): Constraint<Codec<Static<TConfig>>, T, K> =>
Constraint<Codec<Static<TConfig>>, T, K>(A, test, options),
withBrand: <B extends string>(B: B): Brand<B, Codec<Static<TConfig>>> =>
Brand<B, Codec<Static<TConfig>>>(B, A),
): t.Constraint<Codec<Static<TConfig>>, T, K> =>
helpers.Constraint<Codec<Static<TConfig>>, T, K>(A, test, options),
withBrand: <B extends string>(B: B): t.Brand<B, Codec<Static<TConfig>>> =>
helpers.Brand<B, Codec<Static<TConfig>>>(B, A),
withParser: <TParsed>(
config: ParsedValueConfig<Codec<Static<TConfig>>, TParsed>,
): ParsedValue<Codec<Static<TConfig>>, TParsed> => ParsedValue(A as any, config),
): t.ParsedValue<Codec<Static<TConfig>>, TParsed> => helpers.ParsedValue(A as any, config),
toString: () => `Runtype<${show(A)}>`,
[internal]:
typeof internalImplementation === 'function'
? {
p: internalImplementation,
}
? { p: internalImplementation }
: internalImplementation,
};
return (A as unknown) as TConfig;
return A as unknown as TConfig;
function safeParse(x: any) {
return innerValidate(A, x, createVisitedState());
return innerValidate(A, x, createVisitedState(), false);
}
function safeSerialize(x: any) {
return innerSerialize(A, x, createVisitedState());
return innerSerialize(A, x, createVisitedState(), false);
}

@@ -271,3 +333,3 @@ function parse(x: any) {

function test(x: any): x is Static<TConfig> {
const validated = innerGuard(A, x, createGuardVisitedState());
const validated = innerGuard(A, x, createGuardVisitedState(), false);
return validated === undefined;

@@ -312,2 +374,14 @@ }

/**
* Get the underlying type of a runtype, if it is a wrapper around another type
*/
export function unwrapRuntype(t: RuntypeBase, mode: 'p' | 's' | 't'): RuntypeBase {
const i = t[internal];
const unwrapped = i.u ? i.u(mode) : undefined;
if (unwrapped && unwrapped !== t) {
return unwrapRuntype(unwrapped, mode);
}
return t;
}
export function createValidationPlaceholder<T>(

@@ -331,3 +405,3 @@ placeholder: T,

extraGuard &&
innerGuard(extraGuard, result.value, createGuardVisitedState())) ||
innerGuard(extraGuard, result.value, createGuardVisitedState(), false)) ||
result

@@ -372,7 +446,7 @@ );

extraGuard &&
innerGuard(extraGuard, unwrapResult.value, createGuardVisitedState());
innerGuard(extraGuard, unwrapResult.value, createGuardVisitedState(), false);
cache = guardFailure || unwrapResult;
} else {
const guardFailure =
extraGuard && innerGuard(extraGuard, result.value, createGuardVisitedState());
extraGuard && innerGuard(extraGuard, result.value, createGuardVisitedState(), false);
cache = guardFailure || result;

@@ -425,4 +499,5 @@ }

$visited: OpaqueVisitedState,
sealed: SealedState,
): Result<T> {
const result = innerValidateToPlaceholder(targetType, value, $visited);
const result = innerValidateToPlaceholder(targetType, value, $visited, sealed);
if (result.cycle) {

@@ -438,2 +513,3 @@ return result.unwrap();

$visited: OpaqueVisitedState,
sealed: SealedState,
): ResultWithCycle<T> {

@@ -448,4 +524,6 @@ const visited = unwrapVisitedState($visited);

value,
(t, v) => innerValidate(t, v, $visited),
(t, v) => innerValidateToPlaceholder(t, v, $visited),
(t, v, s) => innerValidate(t, v, $visited, s ?? sealed),
(t, v, s) => innerValidateToPlaceholder(t, v, $visited, s ?? sealed),
'p',
sealed,
);

@@ -463,4 +541,5 @@ if (result.cycle) {

$visited: OpaqueVisitedState,
sealed: SealedState,
): Result<T> {
const result = innerSerializeToPlaceholder(targetType, value, $visited);
const result = innerSerializeToPlaceholder(targetType, value, $visited, sealed);
if (result.cycle) {

@@ -475,2 +554,3 @@ return result.unwrap();

$visited: OpaqueVisitedState,
sealed: SealedState,
): ResultWithCycle<any> {

@@ -485,4 +565,6 @@ const visited = unwrapVisitedState($visited);

value,
(t, v) => innerSerialize(t, v, $visited),
(t, v) => innerSerializeToPlaceholder(t, v, $visited),
(t, v, s) => innerSerialize(t, v, $visited, s ?? sealed),
(t, v, s) => innerSerializeToPlaceholder(t, v, $visited, s ?? sealed),
's',
sealed,
);

@@ -500,2 +582,3 @@ if (result.cycle) {

$visited: OpaqueGuardVisitedState,
sealed: SealedState,
): Failure | undefined {

@@ -510,8 +593,10 @@ const visited = unwrapGuardVisitedState($visited);

if (validator.t) {
return validator.t(value, (t, v) => innerGuard(t, v, $visited));
return validator.t(value, (t, v, s) => innerGuard(t, v, $visited, s ?? sealed), sealed);
}
let result = validator.p(
value,
(t, v) => innerGuard(t, v, $visited) || success(v as any),
(t, v) => innerGuard(t, v, $visited) || success(v as any),
(t, v, s) => innerGuard(t, v, $visited, s ?? sealed) || success(v as any),
(t, v, s) => innerGuard(t, v, $visited, s ?? sealed) || success(v as any),
't',
sealed,
);

@@ -522,1 +607,11 @@ if (result.cycle) result = result.unwrap();

}
/**
* Get the possible fields for a runtype
* Returns "undefined" if there can be arbitrary fields (e.g. Record<string, number>)
*/
export function getFields(t: RuntypeBase, mode: 'p' | 's' | 't'): ReadonlySet<string> | undefined {
const b = unwrapRuntype(t, mode);
const i = b[internal];
return i.f ? i.f(mode) : undefined;
}

@@ -44,3 +44,3 @@ import {

'array',
(xs, innerValidate) => {
(xs, innerValidate, _innerValidateToPlaceholder, _getFields, sealed) => {
if (!Array.isArray(xs)) {

@@ -54,3 +54,7 @@ return expected('an Array', xs);

for (let i = 0; i < xs.length; i++) {
const validated = innerValidate(element, xs[i]);
const validated = innerValidate(
element,
xs[i],
sealed && sealed.deep ? { deep: true } : false,
);
if (!validated.success) {

@@ -57,0 +61,0 @@ if (!fullError) {

@@ -17,6 +17,2 @@ import { RuntypeBase, Static, create, Codec, assertRuntype } from '../runtype';

export function isBrandRuntype(runtype: RuntypeBase): runtype is Brand<string, RuntypeBase> {
return 'tag' in runtype && (runtype as Brand<string, RuntypeBase>).tag === 'brand';
}
export function Brand<B extends string, A extends RuntypeBase<unknown>>(brand: B, entity: A) {

@@ -26,5 +22,8 @@ assertRuntype(entity);

'brand',
(value, _innerValidate, innerValidateToPlaceholder) =>
innerValidateToPlaceholder(entity, value) as any,
{
p: (value, _innerValidate, innerValidateToPlaceholder) =>
innerValidateToPlaceholder(entity, value) as any,
u: () => entity,
},
{
brand,

@@ -31,0 +30,0 @@ entity,

@@ -9,14 +9,6 @@ import { failure, success, unableToAssign } from '../result';

export function isConstraintRuntype(
runtype: RuntypeBase,
): runtype is Constraint<RuntypeBase, unknown, unknown> {
return (
'tag' in runtype && (runtype as Constraint<RuntypeBase, unknown, unknown>).tag === 'constraint'
);
}
export interface Constraint<
TUnderlying extends RuntypeBase<unknown>,
TConstrained extends Static<TUnderlying> = Static<TUnderlying>,
TArgs = unknown
TArgs = unknown,
> extends Codec<TConstrained> {

@@ -35,3 +27,3 @@ readonly tag: 'constraint';

TConstrained extends Static<TUnderlying> = Static<TUnderlying>,
TArgs = unknown
TArgs = unknown,
>(

@@ -47,21 +39,24 @@ underlying: TUnderlying,

'constraint',
(value, innerValidate) => {
const name = options && options.name;
const validated = innerValidate(underlying, value);
{
p(value, innerValidate) {
const name = options && options.name;
const validated = innerValidate(underlying, value);
if (!validated.success) {
return validated;
}
if (!validated.success) {
return validated;
}
const result = constraint(validated.value as any);
if (!result || typeof result === 'string') {
const message =
typeof result === 'string'
? result
: `${showValue(value)} failed ${name || 'constraint'} check`;
return failure(message, {
fullError: unableToAssign(value, runtype, message),
});
}
return success(validated.value as TConstrained);
const result = constraint(validated.value as any);
if (!result || typeof result === 'string') {
const message =
typeof result === 'string'
? result
: `${showValue(value)} failed ${name || 'constraint'} check`;
return failure(message, {
fullError: unableToAssign(value, runtype, message),
});
}
return success(validated.value as TConstrained);
},
u: () => underlying,
},

@@ -68,0 +63,0 @@ {

@@ -9,4 +9,7 @@ import { failure, success } from '../result';

assertRuntype,
SealedState,
getFields,
} from '../runtype';
import show, { parenthesize } from '../show';
import { lazyValue } from './lazy';

@@ -24,3 +27,3 @@ // We use the fact that a union of functions is effectively an intersection of parameters

export interface Intersect<
TIntersectees extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]]
TIntersectees extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]],
> extends Codec<StaticIntersect<TIntersectees>> {

@@ -43,52 +46,99 @@ readonly tag: 'intersect';

export function Intersect<
TIntersectees extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]]
TIntersectees extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]],
>(...intersectees: TIntersectees): Intersect<TIntersectees> {
assertRuntype(...intersectees);
const allFieldInfoForMode = (mode: 'p' | 't' | 's') => {
const intresecteesWithOwnFields = intersectees.map(intersectee => ({
i: intersectee,
f: getFields(intersectee, mode),
}));
const intersecteesWithOtherFields = new Map(
intersectees.map(intersectee => {
const allFields = new Set<string>();
for (const { i, f: fields } of intresecteesWithOwnFields) {
if (i !== intersectee) {
if (fields === undefined) return [intersectee, undefined] as const;
for (const field of fields) {
allFields.add(field);
}
}
}
return [intersectee, allFields] as const;
}),
);
const allFields = new Set<string>();
for (const { f: fields } of intresecteesWithOwnFields) {
if (fields === undefined) return { intersecteesWithOtherFields, allFields: undefined };
for (const field of fields) {
allFields.add(field);
}
}
return { intersecteesWithOtherFields, allFields };
};
// use lazy value here so that:
// 1. If this is never used in a `Sealed` context, we can skip evaluating it
// 2. Circular references using `Lazy` don't break.
const allFieldInfo = {
p: lazyValue(() => allFieldInfoForMode(`p`)),
t: lazyValue(() => allFieldInfoForMode(`t`)),
s: lazyValue(() => allFieldInfoForMode(`s`)),
};
return create<Intersect<TIntersectees>>(
'intersect',
(value, innerValidate) => {
if (Array.isArray(value)) {
return createValidationPlaceholder<any>([...value], placeholder => {
for (const targetType of intersectees) {
let validated = innerValidate(targetType, placeholder);
if (!validated.success) {
return validated;
{
p: (value, innerValidate, _innerValidateToPlaceholder, mode, sealed) => {
const getSealed = sealed
? (targetType: RuntypeBase): SealedState => {
const i = allFieldInfo[mode]().intersecteesWithOtherFields.get(targetType);
if (i === undefined) return false;
else return { keysFromIntersect: i, deep: sealed.deep };
}
if (!Array.isArray(validated.value)) {
return failure(
`The validator ${show(
targetType,
)} attempted to convert the type of this value from an array to something else. That conversion is not valid as the child of an intersect`,
);
: (_i: RuntypeBase): SealedState => false;
if (Array.isArray(value)) {
return createValidationPlaceholder<any>([...value], placeholder => {
for (const targetType of intersectees) {
let validated = innerValidate(targetType, placeholder, getSealed(targetType));
if (!validated.success) {
return validated;
}
if (!Array.isArray(validated.value)) {
return failure(
`The validator ${show(
targetType,
)} attempted to convert the type of this value from an array to something else. That conversion is not valid as the child of an intersect`,
);
}
placeholder.splice(0, placeholder.length, ...validated.value);
}
placeholder.splice(0, placeholder.length, ...validated.value);
}
});
} else if (value && typeof value === 'object') {
return createValidationPlaceholder<any>(Object.create(null), placeholder => {
for (const targetType of intersectees) {
let validated = innerValidate(targetType, value);
if (!validated.success) {
return validated;
});
} else if (value && typeof value === 'object') {
return createValidationPlaceholder<any>(Object.create(null), placeholder => {
for (const targetType of intersectees) {
let validated = innerValidate(targetType, value, getSealed(targetType));
if (!validated.success) {
return validated;
}
if (!(validated.value && typeof validated.value === 'object')) {
return failure(
`The validator ${show(
targetType,
)} attempted to convert the type of this value from an object to something else. That conversion is not valid as the child of an intersect`,
);
}
Object.assign(placeholder, validated.value);
}
if (!(validated.value && typeof validated.value === 'object')) {
return failure(
`The validator ${show(
targetType,
)} attempted to convert the type of this value from an object to something else. That conversion is not valid as the child of an intersect`,
);
}
Object.assign(placeholder, validated.value);
});
}
let result = value;
for (const targetType of intersectees) {
let validated = innerValidate(targetType, result, getSealed(targetType));
if (!validated.success) {
return validated;
}
});
}
let result = value;
for (const targetType of intersectees) {
let validated = innerValidate(targetType, result);
if (!validated.success) {
return validated;
result = validated.value;
}
result = validated.value;
}
return success(result);
return success(result);
},
f: mode => allFieldInfo[mode]().allFields,
},

@@ -95,0 +145,0 @@ {

@@ -16,6 +16,2 @@ import { create, RuntypeBase, Codec, Static } from '../runtype';

export function isLazyRuntype(runtype: RuntypeBase): runtype is Lazy<RuntypeBase> {
return 'tag' in runtype && (runtype as Lazy<RuntypeBase<unknown>>).tag === 'lazy';
}
/**

@@ -31,5 +27,8 @@ * Construct a possibly-recursive Runtype.

'lazy',
(value, _innerValidate, innerValidateToPlaceholder) =>
innerValidateToPlaceholder(underlying(), value) as any,
{
p: (value, _innerValidate, innerValidateToPlaceholder) =>
innerValidateToPlaceholder(underlying(), value) as any,
u: underlying,
},
{
underlying,

@@ -36,0 +35,0 @@ show(needsParens) {

@@ -5,6 +5,2 @@ import { RuntypeBase, Static, create, Codec, assertRuntype } from '../runtype';

export function isNamedRuntype(runtype: RuntypeBase): runtype is Named<RuntypeBase> {
return 'tag' in runtype && (runtype as Named<RuntypeBase>).tag === 'named';
}
export interface Named<TUnderlying extends RuntypeBase<unknown>>

@@ -24,4 +20,7 @@ extends Codec<Static<TUnderlying>> {

'named',
(value, innerValidate) => {
return innerValidate(underlying as any, value);
{
p: (value, _innerValidate, innerValidateToPlaceholder) => {
return innerValidateToPlaceholder(underlying as any, value);
},
u: () => underlying,
},

@@ -28,0 +27,0 @@ {

@@ -11,2 +11,6 @@ import { expected } from '../result';

*/
export const Never: Never = create('never', value => expected('nothing', value), {}) as any;
export const Never: Never = create(
'never',
{ p: value => expected('nothing', value), f: () => new Set() },
{},
) as any;

@@ -1,2 +0,3 @@

import { Object as ObjectType, String } from '..';
import { Object as ObjectType, showType, String } from '..';
import { ReadonlyPartial } from './Object';

@@ -64,1 +65,22 @@ test('pick', () => {

});
test('ReadonlyPartial', () => {
const CrewMember = ReadonlyPartial({
name: String,
rank: String,
home: String,
});
expect(showType(CrewMember)).toMatchInlineSnapshot(
`"{ readonly name?: string; readonly rank?: string; readonly home?: string; }"`,
);
expect(CrewMember.safeParse({ name: 'my name', home: 'my home' })).toMatchInlineSnapshot(`
Object {
"success": true,
"value": Object {
"home": "my home",
"name": "my name",
},
}
`);
});

@@ -18,3 +18,3 @@ import {

IsPartial extends boolean,
IsReadonly extends boolean
IsReadonly extends boolean,
> = IsPartial extends false

@@ -31,3 +31,3 @@ ? IsReadonly extends false

IsPartial extends boolean,
IsReadonly extends boolean
IsReadonly extends boolean,
> extends Codec<RecordStaticType<O, IsPartial, IsReadonly>> {

@@ -74,37 +74,62 @@ readonly tag: 'object';

assertRuntype(...Object.values(fields));
const fieldNames: ReadonlySet<string> = new Set(Object.keys(fields));
const runtype: InternalRecord<O, Part, RO> = create<InternalRecord<O, Part, RO>>(
'object',
(x, innerValidate) => {
if (x === null || x === undefined || typeof x !== 'object') {
return expected(runtype, x);
}
if (Array.isArray(x)) {
return failure(`Expected ${show(runtype)}, but was an Array`);
}
{
p: (x, innerValidate, _innerValidateToPlaceholder, _getFields, sealed) => {
if (x === null || x === undefined || typeof x !== 'object') {
return expected(runtype, x);
}
if (Array.isArray(x)) {
return failure(`Expected ${show(runtype)}, but was an Array`);
}
return createValidationPlaceholder(Object.create(null), (placeholder: any) => {
let fullError: FullError | undefined = undefined;
let firstError: Failure | undefined;
for (const key in fields) {
if (!isPartial || (hasKey(key, x) && x[key] !== undefined)) {
const value = isPartial || hasKey(key, x) ? x[key] : undefined;
let validated = innerValidate(fields[key], value);
if (!validated.success) {
if (!fullError) {
fullError = unableToAssign(x, runtype);
return createValidationPlaceholder(Object.create(null), (placeholder: any) => {
let fullError: FullError | undefined = undefined;
let firstError: Failure | undefined;
for (const key in fields) {
if (!isPartial || (hasKey(key, x) && x[key] !== undefined)) {
const value = isPartial || hasKey(key, x) ? x[key] : undefined;
let validated = innerValidate(
fields[key],
value,
sealed && sealed.deep ? { deep: true } : false,
);
if (!validated.success) {
if (!fullError) {
fullError = unableToAssign(x, runtype);
}
fullError.push(typesAreNotCompatible(`"${key}"`, validated));
firstError =
firstError ||
failure(validated.message, {
key: validated.key ? `${key}.${validated.key}` : key,
fullError: fullError,
});
} else {
placeholder[key] = validated.value;
}
fullError.push(typesAreNotCompatible(`"${key}"`, validated));
firstError =
firstError ||
failure(validated.message, {
key: validated.key ? `${key}.${validated.key}` : key,
fullError: fullError,
});
} else {
placeholder[key] = validated.value;
}
}
}
return firstError;
});
if (!firstError && sealed) {
for (const key of Object.keys(x)) {
if (!fieldNames.has(key) && !sealed.keysFromIntersect?.has(key)) {
const message = `Unexpected property: ${key}`;
if (!fullError) {
fullError = unableToAssign(x, runtype);
}
fullError.push([message]);
firstError =
firstError ||
failure(message, {
key: key,
fullError: fullError,
});
}
}
}
return firstError;
});
},
f: () => fieldNames,
},

@@ -170,2 +195,5 @@ {

}
export function ReadonlyObject<O extends RecordFields>(fields: O): Obj<O, true> {
return InternalObject(fields, false, true);
}

@@ -175,1 +203,5 @@ export function Partial<O extends RecordFields>(fields: O): Partial<O, false> {

}
export function ReadonlyPartial<O extends RecordFields>(fields: O): Partial<O, true> {
return InternalObject(fields, true, true);
}

@@ -13,2 +13,3 @@ import { failure, Result } from '../result';

import show from '../show';
import { Never } from './never';

@@ -22,8 +23,2 @@ export interface ParsedValue<TUnderlying extends RuntypeBase<unknown>, TParsed>

export function isParsedValueRuntype(
runtype: RuntypeBase,
): runtype is ParsedValue<RuntypeBase, unknown> {
return 'tag' in runtype && (runtype as ParsedValue<RuntypeBase, unknown>).tag === 'parsed';
}
export interface ParsedValueConfig<TUnderlying extends RuntypeBase<unknown>, TParsed> {

@@ -57,3 +52,3 @@ name?: string;

},
s(value, _internalSerialize, _internalSerializeToPlaceholder) {
s(value, _internalSerialize, internalSerializeToPlaceholder, _getFields, sealed) {
if (!config.serialize) {

@@ -67,3 +62,3 @@ return failure(

const testResult = config.test
? innerGuard(config.test, value, createGuardVisitedState())
? innerGuard(config.test, value, createGuardVisitedState(), sealed)
: undefined;

@@ -81,4 +76,14 @@

return _internalSerializeToPlaceholder(underlying, serialized.value);
return internalSerializeToPlaceholder(underlying, serialized.value, false);
},
u(mode) {
switch (mode) {
case 'p':
return underlying;
case 't':
return config.test ?? Never;
case 's':
return config.serialize ? config.test : Never;
}
},
},

@@ -85,0 +90,0 @@ {

@@ -27,3 +27,3 @@ import { failure, success } from '../result';

TType extends 'boolean' | 'function' | 'number' | 'string' | 'symbol',
TValue
TValue,
>(type: TType): Codec<TValue> & { readonly tag: TType } {

@@ -30,0 +30,0 @@ return create<Codec<TValue> & { readonly tag: TType }>(

@@ -24,4 +24,6 @@ import * as ta from 'type-assertions';

const obj = ft.Object({ whatever: ft.Number });
expect(obj.isReadonly).toBe(false);
ta.assert<ta.Equal<ReturnType<typeof obj['parse']>, { whatever: number }>>();
const rObj = ft.Readonly(obj);
expect(rObj.isReadonly).toBe(true);
ta.assert<ta.Equal<ReturnType<typeof rObj['parse']>, { readonly whatever: number }>>();

@@ -36,2 +38,4 @@ expect(rObj.safeParse({ whatever: 2 })).toMatchInlineSnapshot(`

`);
expect(obj.asPartial().isReadonly).toBe(false);
expect(rObj.asPartial().isReadonly).toBe(true);
});

@@ -38,0 +42,0 @@

@@ -28,3 +28,3 @@ import { RuntypeBase } from '../runtype';

export function Readonly<
TElements extends readonly RuntypeBase<unknown>[] = readonly RuntypeBase<unknown>[]
TElements extends readonly RuntypeBase<unknown>[] = readonly RuntypeBase<unknown>[],
>(input: Tuple<TElements>): ReadonlyTuple<TElements>;

@@ -31,0 +31,0 @@ export function Readonly<K extends KeyRuntypeBase, V extends RuntypeBase<unknown>>(

@@ -27,2 +27,14 @@ import * as ta from 'type-assertions';

Object {
"fullError": Array [
"The types of bar are not compatible",
Array [
"Unable to assign {value: 24} to { value: 42; }",
Array [
"The types of \\"value\\" are not compatible",
Array [
"Expected literal 42, but was 24",
],
],
],
],
"key": "bar.value",

@@ -89,2 +101,14 @@ "message": "Expected literal 42, but was 24",

Object {
"fullError": Array [
"The types of bar are not compatible",
Array [
"Unable to assign {value: 24} to { value: 42; }",
Array [
"The types of \\"value\\" are not compatible",
Array [
"Expected literal 42, but was 24",
],
],
],
],
"key": "bar.value",

@@ -91,0 +115,0 @@ "message": "Expected literal 42, but was 24",

@@ -15,3 +15,3 @@ import {

import { Union } from './union';
import { expected, failure, Result } from '../result';
import { expected, failure, Result, typesAreNotCompatible } from '../result';

@@ -71,3 +71,3 @@ export type KeyRuntypeBaseWithoutUnion =

'record',
(x, innerValidate) => {
(x, innerValidate, _innerValidateToPlaceholder, _getFields, sealed) => {
if (x === null || x === undefined || typeof x !== 'object') {

@@ -91,9 +91,9 @@ return expected(runtype, x);

if (isNaN(+k)) return expected(`record key to be a number`, k);
keyValidation = innerValidate(key, +k);
keyValidation = innerValidate(key, +k, false);
} else if (expectedBaseType() === 'string') {
keyValidation = innerValidate(key, k);
keyValidation = innerValidate(key, k, false);
} else {
keyValidation = innerValidate(key, k);
keyValidation = innerValidate(key, k, false);
if (!keyValidation.success && !isNaN(+k)) {
keyValidation = innerValidate(key, +k);
keyValidation = innerValidate(key, +k, false);
}

@@ -105,6 +105,11 @@ }

const validated = innerValidate(value, (x as any)[k]);
const validated = innerValidate(
value,
(x as any)[k],
sealed && sealed.deep ? { deep: true } : false,
);
if (!validated.success) {
return failure(validated.message, {
key: validated.key ? `${k}.${validated.key}` : k,
fullError: typesAreNotCompatible(k, validated.fullError ?? [validated.message]),
});

@@ -128,1 +133,10 @@ }

}
export function ReadonlyRecord<K extends KeyRuntypeBase, V extends RuntypeBase<unknown>>(
key: K,
value: V,
): ReadonlyRecord<K, V> {
const record: any = Record(key, value);
record.isReadonly = true;
return record;
}

@@ -20,3 +20,3 @@ import {

export interface Tuple<
TElements extends readonly RuntypeBase<unknown>[] = readonly RuntypeBase<unknown>[]
TElements extends readonly RuntypeBase<unknown>[] = readonly RuntypeBase<unknown>[],
> extends Codec<StaticTuple<TElements>> {

@@ -29,3 +29,3 @@ readonly tag: 'tuple';

export interface ReadonlyTuple<
TElements extends readonly RuntypeBase<unknown>[] = readonly RuntypeBase<unknown>[]
TElements extends readonly RuntypeBase<unknown>[] = readonly RuntypeBase<unknown>[],
> extends Codec<ReadonlyStaticTuple<TElements>> {

@@ -45,3 +45,3 @@ readonly tag: 'tuple';

export function Tuple<
T extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]] | readonly []
T extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]] | readonly [],
>(...components: T): Tuple<T> {

@@ -51,3 +51,3 @@ assertRuntype(...components);

'tuple',
(x, innerValidate) => {
(x, innerValidate, _innerValidateToPlaceholder, _getFields, sealed) => {
if (!Array.isArray(x)) {

@@ -65,3 +65,7 @@ return expected(`tuple to be an array`, x);

for (let i = 0; i < components.length; i++) {
let validatedComponent = innerValidate(components[i], x[i]);
let validatedComponent = innerValidate(
components[i],
x[i],
sealed && sealed.deep ? { deep: true } : false,
);

@@ -90,3 +94,5 @@ if (!validatedComponent.success) {

show() {
return `[${(components as readonly RuntypeBase<unknown>[])
return `${this.isReadonly ? `readonly ` : ``}[${(
components as readonly RuntypeBase<unknown>[]
)
.map(e => show(e, false))

@@ -99,1 +105,9 @@ .join(', ')}]`;

}
export function ReadonlyTuple<
T extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]] | readonly [],
>(...components: T): ReadonlyTuple<T> {
const tuple: any = Tuple(...components);
tuple.isReadonly = true;
return tuple;
}

@@ -11,6 +11,8 @@ import {

assertRuntype,
unwrapRuntype,
getFields,
} from '../runtype';
import show, { parenthesize } from '../show';
import { LiteralValue, isLiteralRuntype } from './literal';
import { lazyValue, isLazyRuntype } from './lazy';
import { lazyValue } from './lazy';
import { isObjectRuntype } from './Object';

@@ -28,9 +30,4 @@ import {

import { isTupleRuntype } from './tuple';
import { isBrandRuntype } from './brand';
import { isConstraintRuntype } from './constraint';
import { isParsedValueRuntype } from './ParsedValue';
import { Never } from '..';
import showValue from '../showValue';
import { isIntersectRuntype } from './intersect';
import { isNamedRuntype } from './Named';

@@ -54,24 +51,2 @@ export type StaticUnion<TAlternatives extends readonly RuntypeBase<unknown>[]> = {

function resolveUnderlyingType(runtype: RuntypeBase, mode: 'p' | 's' | 't'): RuntypeBase {
if (isLazyRuntype(runtype)) return resolveUnderlyingType(runtype.underlying(), mode);
if (isBrandRuntype(runtype)) return resolveUnderlyingType(runtype.entity, mode);
if (isConstraintRuntype(runtype)) return resolveUnderlyingType(runtype.underlying, mode);
if (isNamedRuntype(runtype)) return resolveUnderlyingType(runtype.underlying, mode);
if (mode === 'p' && isParsedValueRuntype(runtype))
return resolveUnderlyingType(runtype.underlying, mode);
if (mode === 't' && isParsedValueRuntype(runtype)) {
return runtype.config.test ? resolveUnderlyingType(runtype.config.test, mode) : Never;
}
if (mode === 's' && isParsedValueRuntype(runtype)) {
if (!runtype.config.serialize) {
// this node can never match
return Never;
}
return runtype.config.test ? resolveUnderlyingType(runtype.config.test, mode) : runtype;
}
return runtype;
}
function mapGet<TKey, TValue>(map: Map<TKey, TValue>) {

@@ -91,6 +66,6 @@ return (key: TKey, fn: () => TValue) => {

): [string, RuntypeBase][] {
const underlying = resolveUnderlyingType(alternative, mode);
const underlying = unwrapRuntype(alternative, mode);
const fields: [string, RuntypeBase][] = [];
const pushField = (fieldName: string, type: RuntypeBase) => {
const f = resolveUnderlyingType(type, mode);
const f = unwrapRuntype(type, mode);
if (isUnionType(f)) {

@@ -169,3 +144,3 @@ for (const type of f.alternatives) {

export function Union<
TAlternatives extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]]
TAlternatives extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]],
>(...alternatives: TAlternatives): Union<TAlternatives> {

@@ -254,3 +229,3 @@ assertRuntype(...alternatives);

const withFields = flatAlternatives
.filter(a => resolveUnderlyingType(a, mode).tag !== 'never')
.filter(a => unwrapRuntype(a, mode).tag !== 'never')
.map(a => [a, findFields(a, mode)] as const);

@@ -271,7 +246,5 @@ const withAtLeastOneField = withFields.filter(a => a[1].length !== 0);

if (!resultWithoutKey.success) {
if (resultWithKey.fullError) {
resultWithoutKey.fullError!.push(andError(resultWithKey.fullError!));
} else {
resultWithoutKey.fullError!.push(andError(unableToAssign(value, `Object`)));
}
resultWithoutKey.fullError!.push(
andError(resultWithKey.fullError ?? unableToAssign(value, `Object`)),
);
}

@@ -292,2 +265,19 @@ return resultWithoutKey;

const getFieldsForMode = (mode: 'p' | 't' | 's') => {
const fields = new Set<string>();
for (const a of alternatives) {
const aFields = getFields(a, mode);
if (aFields === undefined) return undefined;
for (const f of aFields) {
fields.add(f);
}
}
return fields;
};
const fields = {
p: lazyValue(() => getFieldsForMode(`p`)),
t: lazyValue(() => getFieldsForMode(`t`)),
s: lazyValue(() => getFieldsForMode(`s`)),
};
const runtype: Union<TAlternatives> = create<Union<TAlternatives>>(

@@ -306,2 +296,3 @@ 'union',

},
f: mode => fields[mode](),
},

@@ -323,3 +314,3 @@ {

for (let i = 0; i < alternatives.length; i++) {
const input = innerValidate(alternatives[i], x, visited);
const input = innerValidate(alternatives[i], x, visited, false);
if (input.success) {

@@ -326,0 +317,0 @@ return cases[i](input.value);

@@ -12,3 +12,3 @@ {

"declaration": true,
"sourceMap": false,
"sourceMap": true,
"outDir": "lib",

@@ -15,0 +15,0 @@ "forceConsistentCasingInFileNames": true,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet