New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

funtypes

Package Overview
Dependencies
Maintainers
2
Versions
18
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 4.2.0 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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc