Comparing version 0.1.12 to 0.1.13
@@ -13,2 +13,2 @@ import type { TypeIssue, TypePath } from './@type-issue'; | ||
} | ||
export type Exact = ExactContext | boolean; | ||
export type Exact = ExactContext | boolean | 'disabled'; |
@@ -26,4 +26,4 @@ "use strict"; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
if (!Array.isArray(unpacked)) { | ||
_traverse(input, path, exact, callback) { | ||
if (!Array.isArray(input)) { | ||
return [ | ||
@@ -34,3 +34,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call(unpacked)}.`, | ||
message: `Expected an array, got ${toString.call(input)}.`, | ||
}, | ||
@@ -42,81 +42,13 @@ ], | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
const value = []; | ||
const output = []; | ||
const issues = []; | ||
for (const [index, unpackedElement] of unpacked.entries()) { | ||
const [element, entryIssues] = ElementType._decode(medium, unpackedElement, [...path, index], nestedExact); | ||
value.push(element); | ||
for (const [index, value] of input.entries()) { | ||
const [element, entryIssues] = ElementType._traverse(value, [...path, index], nestedExact, callback); | ||
output.push(element); | ||
issues.push(...entryIssues); | ||
} | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(unpacked.keys(), key => key.toString())); | ||
return [(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) ? undefined : value, issues]; | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(input.keys(), key => key.toString())); | ||
return [(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) ? undefined : output, issues]; | ||
} | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
if (diagnose && !Array.isArray(value)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be an array, getting ${toString.call(value)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementType = this.ElementType; | ||
const { context, nestedExact } = diagnose | ||
? this.getExactContext(exact, false) | ||
: type_1.DISABLED_EXACT_CONTEXT_RESULT; | ||
const unpacked = []; | ||
const issues = []; | ||
for (const [index, valueElement] of value.entries()) { | ||
const [unpackedElement, entryIssues] = ElementType._encode(medium, valueElement, [...path, index], nestedExact, diagnose); | ||
unpacked.push(unpackedElement); | ||
issues.push(...entryIssues); | ||
} | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(value.keys(), key => key.toString())); | ||
return [(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) ? undefined : unpacked, issues]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
if (!Array.isArray(unpacked)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementType = this.ElementType; | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
const value = []; | ||
const issues = []; | ||
for (const [index, unpackedElement] of unpacked.entries()) { | ||
const [element, entryIssues] = ElementType._transform(from, to, unpackedElement, [...path, index], nestedExact); | ||
value.push(element); | ||
issues.push(...entryIssues); | ||
} | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(unpacked.keys(), key => key.toString())); | ||
return [(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) ? undefined : value, issues]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
if (!Array.isArray(value)) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting an array, getting ${toString.call(value)}.`, | ||
}, | ||
]; | ||
} | ||
const ElementType = this.ElementType; | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
const issues = value.flatMap((element, index) => ElementType._diagnose(element, [...path, index], nestedExact)); | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(value.keys(), key => key.toString())); | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -123,0 +55,0 @@ var _b; |
@@ -69,22 +69,5 @@ "use strict"; | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
const symbol = this.symbol; | ||
let value; | ||
try { | ||
value = from.getCodec(symbol).decode(unpacked); | ||
} | ||
catch (error) { | ||
return [undefined, [(0, _type_issue_1.buildIssueByError)(error, path)]]; | ||
} | ||
const issues = this._diagnose(value, path, exact); | ||
if ((0, _type_issue_1.hasNonDeferrableTypeIssue)(issues)) { | ||
return [undefined, issues]; | ||
} | ||
try { | ||
return [to.getCodec(symbol).encode(value), issues]; | ||
} | ||
catch (error) { | ||
issues.push((0, _type_issue_1.buildIssueByError)(error, path)); | ||
return [undefined, issues]; | ||
} | ||
_sanitize(value, path) { | ||
const issues = this._diagnose(value, path, 'disabled'); | ||
return [(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) ? undefined : value, issues]; | ||
} | ||
@@ -91,0 +74,0 @@ /** @internal */ |
@@ -5,2 +5,3 @@ "use strict"; | ||
exports.function = exports.fn = exports.FunctionType = void 0; | ||
const _type_issue_1 = require("./@type-issue"); | ||
const type_1 = require("./type"); | ||
@@ -43,3 +44,3 @@ const type_partials_1 = require("./type-partials"); | ||
path: [], | ||
message: `Expecting at least ${ArgumentTypeTuple.length} argument(s), getting ${args.length}.`, | ||
message: `Expected at least ${ArgumentTypeTuple.length} argument(s), got ${args.length}.`, | ||
}, | ||
@@ -67,3 +68,3 @@ ]); | ||
path: [], | ||
message: `Expecting at least ${ArgumentTypeTuple.length} argument(s), getting ${args.length}.`, | ||
message: `Expected at least ${ArgumentTypeTuple.length} argument(s), got ${args.length}.`, | ||
}, | ||
@@ -92,45 +93,15 @@ ]); | ||
/** @internal */ | ||
_decode(_medium, unpacked, path, _exact) { | ||
if (typeof unpacked !== 'function') { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a function, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
return [unpacked, []]; | ||
_decode(_medium, unpacked, path, exact) { | ||
const issues = this._diagnose(unpacked, path, exact); | ||
return [(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) ? undefined : unpacked, issues]; | ||
} | ||
/** @internal */ | ||
_encode(_medium, value, path, _exact, diagnose) { | ||
if (diagnose && typeof value !== 'function') { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be a function, getting ${toString.call(value)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
return [value, []]; | ||
_encode(_medium, value, path, exact, diagnose) { | ||
const issues = diagnose ? this._diagnose(value, path, exact) : []; | ||
return [(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) ? undefined : value, issues]; | ||
} | ||
/** @internal */ | ||
_transform(_from, _to, unpacked, path, _exact) { | ||
if (typeof unpacked !== 'function') { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a function, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
return [unpacked, []]; | ||
_sanitize(value, path) { | ||
const issues = this._diagnose(value, path, 'disabled'); | ||
return [(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) ? undefined : value, issues]; | ||
} | ||
@@ -143,3 +114,3 @@ /** @internal */ | ||
path, | ||
message: `Expecting a function, getting ${toString.call(value)}.`, | ||
message: `Expected a function, got ${toString.call(value)}.`, | ||
}, | ||
@@ -146,0 +117,0 @@ ]; |
@@ -12,3 +12,3 @@ "use strict"; | ||
if (TypeTuple.length < 2) { | ||
throw new TypeError('Expecting at least 2 types for intersection type'); | ||
throw new TypeError('Expected at least 2 elements for intersection type'); | ||
} | ||
@@ -30,3 +30,3 @@ super(); | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
_traverse(input, path, exact, callback) { | ||
const { managedContext, wrappedExact } = this.getExactContext(exact, 'managed'); | ||
@@ -36,3 +36,3 @@ const partials = []; | ||
for (const Type of this.TypeTuple) { | ||
const [partial, partialIssues] = Type._decode(medium, unpacked, path, wrappedExact); | ||
const [partial, partialIssues] = callback(Type, input, path, wrappedExact); | ||
partials.push(partial); | ||
@@ -42,3 +42,3 @@ issues.push(...partialIssues); | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
issues.push(...managedContext.getUnknownKeyIssues(input, path)); | ||
} | ||
@@ -53,53 +53,2 @@ return [ | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
const { managedContext, wrappedExact } = diagnose | ||
? this.getExactContext(exact, 'managed') | ||
: type_1.DISABLED_EXACT_CONTEXT_RESULT; | ||
const partials = []; | ||
const issues = []; | ||
for (const Type of this.TypeTuple) { | ||
const [partial, partialIssues] = Type._encode(medium, value, path, wrappedExact, diagnose); | ||
partials.push(partial); | ||
issues.push(...partialIssues); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return [ | ||
(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) | ||
? undefined | ||
: internal_mergeIntersectionPartials(partials), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
const { managedContext, wrappedExact } = this.getExactContext(exact, 'managed'); | ||
const partials = []; | ||
const issues = []; | ||
for (const Type of this.TypeTuple) { | ||
const [partial, partialIssues] = Type._transform(from, to, unpacked, path, wrappedExact); | ||
partials.push(partial); | ||
issues.push(...partialIssues); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
} | ||
return [ | ||
(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) | ||
? undefined | ||
: internal_mergeIntersectionPartials(partials), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
const { managedContext, wrappedExact } = this.getExactContext(exact, 'managed'); | ||
const issues = this.TypeTuple.flatMap(Type => Type._diagnose(value, path, wrappedExact)); | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -106,0 +55,0 @@ var _b; |
@@ -56,4 +56,4 @@ "use strict"; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
_traverse(input, path, exact, callback) { | ||
if (typeof input !== 'object' || input === null) { | ||
return [ | ||
@@ -64,3 +64,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call(unpacked)}.`, | ||
message: `Expected a non-null object, got ${toString.call(input)}.`, | ||
}, | ||
@@ -74,11 +74,11 @@ ], | ||
for (const [key, Type] of Object.entries(this.definition)) { | ||
const [value, entryIssues] = Type._decode(medium, unpacked[key], [...path, key], nestedExact); | ||
const [value, entryIssues] = callback(Type, input[key], [...path, key], nestedExact); | ||
entries.push([key, value]); | ||
issues.push(...entryIssues); | ||
} | ||
if (wrappedExact) { | ||
if (typeof wrappedExact === 'object') { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
issues.push(...managedContext.getUnknownKeyIssues(input, path)); | ||
} | ||
@@ -93,100 +93,2 @@ return [ | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
if (diagnose && (typeof value !== 'object' || value === null)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be a non-null object, getting ${toString.call(value)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const { managedContext, wrappedExact, nestedExact } = diagnose | ||
? this.getExactContext(exact, 'managed') | ||
: { | ||
managedContext: undefined, | ||
wrappedExact: false, | ||
nestedExact: false, | ||
}; | ||
const entries = []; | ||
const issues = []; | ||
for (const [key, Type] of Object.entries(this.definition)) { | ||
const [unpacked, entryIssues] = Type._encode(medium, value[key], [...path, key], nestedExact, diagnose); | ||
entries.push([key, unpacked]); | ||
issues.push(...entryIssues); | ||
} | ||
if (wrappedExact) { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return [ | ||
(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) | ||
? undefined | ||
: Object.fromEntries(entries), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const { managedContext, wrappedExact, nestedExact } = this.getExactContext(exact, 'managed'); | ||
const entries = []; | ||
const issues = []; | ||
for (const [key, Type] of Object.entries(this.definition)) { | ||
const [transformedUnpacked, entryIssues] = Type._transform(from, to, unpacked[key], [...path, key], nestedExact); | ||
entries.push([key, transformedUnpacked]); | ||
issues.push(...entryIssues); | ||
} | ||
if (wrappedExact) { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
} | ||
return [ | ||
(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) | ||
? undefined | ||
: Object.fromEntries(entries), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
if (typeof value !== 'object' || value === null) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting a non-null object, getting ${toString.call(value)}.`, | ||
}, | ||
]; | ||
} | ||
const { managedContext, wrappedExact, nestedExact } = this.getExactContext(exact, 'managed'); | ||
const issues = []; | ||
const entries = Object.entries(this.definition); | ||
for (const [key, Type] of entries) { | ||
issues.push(...Type._diagnose(value[key], [...path, key], nestedExact)); | ||
} | ||
if (wrappedExact) { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -193,0 +95,0 @@ var _b; |
@@ -25,24 +25,8 @@ "use strict"; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
return unpacked === undefined | ||
_traverse(input, path, exact, callback) { | ||
return input === undefined | ||
? [undefined, []] | ||
: this.Type._decode(medium, unpacked, path, exact); | ||
: callback(this.Type, input, path, exact); | ||
} | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
return value === undefined | ||
? [undefined, []] | ||
: this.Type._encode(medium, value, path, exact, diagnose); | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
return unpacked === undefined | ||
? [undefined, []] | ||
: this.Type._transform(from, to, unpacked, path, exact); | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
return value === undefined ? [] : this.Type._diagnose(value, path, exact); | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -49,0 +33,0 @@ const { schema } = this.Type._toJSONSchema(context, exact); |
@@ -32,4 +32,4 @@ "use strict"; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
_traverse(input, path, exact, callback) { | ||
if (typeof input !== 'object' || input === null) { | ||
return [ | ||
@@ -40,3 +40,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call(unpacked)}.`, | ||
message: `Expected a non-null object, got ${toString.call(input)}.`, | ||
}, | ||
@@ -51,99 +51,17 @@ ], | ||
const entries = []; | ||
const issues = []; | ||
for (const [key, unpackedValue] of getRecordEntries(unpacked)) { | ||
const [value, valueIssues] = Value._decode(medium, unpackedValue, [...path, key], nestedExact); | ||
entries.push([key, value]); | ||
issues.push(...Key._diagnose(key, [...path, { key }], nestedExact), ...valueIssues); | ||
const aggregatedIssues = []; | ||
for (const [key, value] of getRecordEntries(input)) { | ||
const keyIssues = Key._diagnose(key, [...path, { key }], nestedExact); | ||
const [output, valueIssues] = Value._traverse(value, [...path, key], nestedExact, callback); | ||
entries.push([key, output]); | ||
aggregatedIssues.push(...keyIssues, ...valueIssues); | ||
} | ||
return [ | ||
(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) | ||
(0, _type_issue_1.hasNonDeferrableTypeIssue)(aggregatedIssues) | ||
? undefined | ||
: buildRecord(entries, unpacked), | ||
issues, | ||
: buildRecord(entries, input), | ||
aggregatedIssues, | ||
]; | ||
} | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
if (diagnose && (typeof value !== 'object' || value === null)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be a non-null object, getting ${toString.call(value)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const Key = this.Key; | ||
const Value = this.Value; | ||
const { context, nestedExact } = diagnose | ||
? this.getExactContext(exact, false) | ||
: type_1.DISABLED_EXACT_CONTEXT_RESULT; | ||
context === null || context === void 0 ? void 0 : context.neutralize(); | ||
const entries = []; | ||
const issues = []; | ||
for (const [key, nestedValue] of getRecordEntries(value)) { | ||
const [unpacked, valueIssues] = Value._encode(medium, nestedValue, [...path, key], nestedExact, diagnose); | ||
entries.push([key, unpacked]); | ||
issues.push(...Key._diagnose(key, [...path, { key }], nestedExact), ...valueIssues); | ||
} | ||
return [ | ||
(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) | ||
? undefined | ||
: buildRecord(entries, value), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const Key = this.Key; | ||
const Value = this.Value; | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
context === null || context === void 0 ? void 0 : context.neutralize(); | ||
const entries = []; | ||
const issues = []; | ||
for (const [key, unpackedValue] of getRecordEntries(unpacked)) { | ||
const [transformedUnpacked, valueIssues] = Value._transform(from, to, unpackedValue, [...path, key], nestedExact); | ||
entries.push([key, transformedUnpacked]); | ||
issues.push(...Key._diagnose(key, [...path, { key }], nestedExact), ...valueIssues); | ||
} | ||
return [ | ||
(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) | ||
? undefined | ||
: buildRecord(entries, unpacked), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
if (typeof value !== 'object' || value === null) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting a non-null object, getting ${toString.call(value)}.`, | ||
}, | ||
]; | ||
} | ||
const Key = this.Key; | ||
const Value = this.Value; | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
context === null || context === void 0 ? void 0 : context.neutralize(); | ||
return getRecordEntries(value).flatMap(([key, nestedValue]) => [ | ||
...Key._diagnose(key, [...path, { key }], nestedExact), | ||
...Value._diagnose(nestedValue, [...path, key], nestedExact), | ||
]); | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -150,0 +68,0 @@ var _b; |
@@ -25,18 +25,6 @@ "use strict"; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
return this.Type._decode(medium, unpacked, path, exact); | ||
_traverse(input, path, exact, callback) { | ||
return callback(this.Type, input, path, exact); | ||
} | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
return this.Type._encode(medium, value, path, exact, diagnose); | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
return this.Type._transform(from, to, unpacked, path, exact); | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
return this.Type._diagnose(value, path, exact); | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -43,0 +31,0 @@ var _b; |
@@ -62,3 +62,3 @@ "use strict"; | ||
path, | ||
message: 'Expecting encoding value to be stable after refinements.', | ||
message: 'Expected encoding value to be stable after refinements.', | ||
}); | ||
@@ -73,9 +73,13 @@ } | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
const [value, issues] = this._decode(from, unpacked, path, exact); | ||
_sanitize(value, path) { | ||
const [sanitized, issues] = this.Type._sanitize(value, path); | ||
if ((0, _type_issue_1.hasNonDeferrableTypeIssue)(issues)) { | ||
return [undefined, issues]; | ||
} | ||
const [transformedUnpacked] = this._encode(to, value, path, false, false); | ||
return [transformedUnpacked, issues]; | ||
const [refined, refinementIssues] = this.processRefinements(sanitized, path); | ||
issues.push(...refinementIssues); | ||
if ((0, _type_issue_1.hasNonDeferrableTypeIssue)(refinementIssues)) { | ||
return [undefined, issues]; | ||
} | ||
return [refined, issues]; | ||
} | ||
@@ -82,0 +86,0 @@ /** @internal */ |
@@ -26,4 +26,4 @@ "use strict"; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
if (!Array.isArray(unpacked)) { | ||
_traverse(input, path, exact, callback) { | ||
if (!Array.isArray(input)) { | ||
return [ | ||
@@ -34,3 +34,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call(unpacked)}.`, | ||
message: `Expected an array, got ${toString.call(input)}.`, | ||
}, | ||
@@ -41,3 +41,3 @@ ], | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if (unpacked.length !== ElementTypeTuple.length) { | ||
if (input.length !== ElementTypeTuple.length) { | ||
return [ | ||
@@ -48,3 +48,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value with ${ElementTypeTuple.length} instead of ${unpacked.length} element(s).`, | ||
message: `Expected value with ${ElementTypeTuple.length} instead of ${input.length} element(s).`, | ||
}, | ||
@@ -58,3 +58,3 @@ ], | ||
for (const [index, Element] of ElementTypeTuple.entries()) { | ||
const [element, entryIssues] = Element._decode(medium, unpacked[index], [...path, index], nestedExact); | ||
const [element, entryIssues] = callback(Element, input[index], [...path, index], nestedExact); | ||
value.push(element); | ||
@@ -67,100 +67,2 @@ issues.push(...entryIssues); | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
if (diagnose && !Array.isArray(value)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be an array, getting ${toString.call(value)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if (value.length !== ElementTypeTuple.length) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value with ${ElementTypeTuple.length} instead of ${value.length} element(s).`, | ||
}, | ||
], | ||
]; | ||
} | ||
const { context, nestedExact } = diagnose | ||
? this.getExactContext(exact, false) | ||
: type_1.DISABLED_EXACT_CONTEXT_RESULT; | ||
const unpacked = []; | ||
const issues = []; | ||
for (const [index, Element] of ElementTypeTuple.entries()) { | ||
const [unpackedElement, entryIssues] = Element._encode(medium, value[index], [...path, index], nestedExact, diagnose); | ||
unpacked.push(unpackedElement); | ||
issues.push(...entryIssues); | ||
} | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(ElementTypeTuple.keys(), key => key.toString())); | ||
return [(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) ? undefined : unpacked, issues]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
if (!Array.isArray(unpacked)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if (unpacked.length !== ElementTypeTuple.length) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value with ${ElementTypeTuple.length} instead of ${unpacked.length} element(s).`, | ||
}, | ||
], | ||
]; | ||
} | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
const value = []; | ||
const issues = []; | ||
for (const [index, Element] of ElementTypeTuple.entries()) { | ||
const [element, entryIssues] = Element._transform(from, to, unpacked[index], [...path, index], nestedExact); | ||
value.push(element); | ||
issues.push(...entryIssues); | ||
} | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(ElementTypeTuple.keys(), key => key.toString())); | ||
return [(0, _type_issue_1.hasNonDeferrableTypeIssue)(issues) ? undefined : value, issues]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
if (!Array.isArray(value)) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting an array, getting ${toString.call(value)}.`, | ||
}, | ||
]; | ||
} | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if (value.length !== ElementTypeTuple.length) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting value with ${ElementTypeTuple.length} instead of ${value.length} element(s).`, | ||
}, | ||
]; | ||
} | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
const issues = ElementTypeTuple.flatMap((Element, index) => Element._diagnose(value[index], [...path, index], nestedExact)); | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(ElementTypeTuple.keys(), key => key.toString())); | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -167,0 +69,0 @@ var _b; |
@@ -0,1 +1,3 @@ | ||
import type { Exact } from './@exact-context'; | ||
import type { TypeIssue, TypePath } from './@type-issue'; | ||
import type { JSONSchema } from './json-schema'; | ||
@@ -19,2 +21,3 @@ import { __type_in_mediums, __type_kind } from './type-partials'; | ||
} | ||
export type TraverseCallback = (Type: TypeLike, value: unknown, path: TypePath, exact: Exact) => [unknown, TypeIssue[]]; | ||
export interface JSONSchemaData { | ||
@@ -21,0 +24,0 @@ schema: JSONSchema; |
@@ -15,2 +15,26 @@ "use strict"; | ||
} | ||
/** @internal */ | ||
_traverse(input, path, exact, callback) { | ||
return callback(this, input, path, exact); | ||
} | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact, callback) { | ||
return this._traverse(unpacked, path, exact, (Type, value, path, exact) => Type._decode(medium, value, path, exact, callback)); | ||
} | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose, callback) { | ||
return this._traverse(value, path, exact, (Type, value, path, exact) => Type._encode(medium, value, path, exact, diagnose, callback)); | ||
} | ||
/** @internal */ | ||
_sanitize(value, path) { | ||
return this._traverse(value, path, 'disabled', (Type, value, path) => Type._sanitize(value, path)); | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
const [, issues] = this._traverse(value, path, exact, (Type, value, path, exact) => [ | ||
undefined, | ||
Type._diagnose(value, path, exact), | ||
]); | ||
return issues; | ||
} | ||
} | ||
@@ -17,0 +41,0 @@ exports.TypeLike = TypeLike; |
@@ -20,6 +20,7 @@ import type { Exact } from './@exact-context'; | ||
transform<TFromMedium extends Medium<object>, TToMedium extends Medium<object>>(from: TFromMedium, to: TToMedium, value: MediumPackedType<TFromMedium, TInMediums>): MediumPackedType<TToMedium, TInMediums>; | ||
sanitize(value: unknown): TInMediums['value']; | ||
diagnose(value: unknown): TypeIssue[]; | ||
satisfies(value: unknown): TInMediums['value']; | ||
asserts(value: unknown): void; | ||
is(value: unknown): value is TInMediums['value']; | ||
diagnose(value: unknown): TypeIssue[]; | ||
toJSONSchema(): JSONSchema; | ||
@@ -32,3 +33,3 @@ protected getExactContext(exact: Exact, wrapper: 'managed'): { | ||
managedContext: ExactContext | undefined; | ||
wrappedExact: ExactContext | false; | ||
wrappedExact: ExactContext | false | 'disabled'; | ||
nestedExact: Exact; | ||
@@ -35,0 +36,0 @@ }; |
@@ -47,3 +47,10 @@ "use strict"; | ||
const unpacked = from.unpack(packed); | ||
const [transformedUnpacked, issues] = this._transform(from, to, unpacked, [], (_a = this._exact) !== null && _a !== void 0 ? _a : false); | ||
const callback = (Type, value, path, exact) => { | ||
const [decoded, issues] = Type._decode(from, value, path, exact); | ||
if (issues.length > 0) { | ||
return [undefined, issues]; | ||
} | ||
return Type._encode(to, decoded, path, exact, false); | ||
}; | ||
const [transformedUnpacked, issues] = this._traverse(unpacked, [], (_a = this._exact) !== null && _a !== void 0 ? _a : false, callback); | ||
if (issues.length > 0) { | ||
@@ -54,2 +61,13 @@ throw new TypeConstraintError(`Failed to transform medium`, issues); | ||
} | ||
sanitize(value) { | ||
const [sanitized, issues] = this._sanitize(value, []); | ||
if (issues.length > 0) { | ||
throw new TypeConstraintError('Value does not satisfy the type', issues); | ||
} | ||
return sanitized; | ||
} | ||
diagnose(value) { | ||
var _a; | ||
return this._diagnose(value, [], (_a = this._exact) !== null && _a !== void 0 ? _a : false); | ||
} | ||
satisfies(value) { | ||
@@ -68,6 +86,2 @@ const issues = this.diagnose(value); | ||
} | ||
diagnose(value) { | ||
var _a; | ||
return this._diagnose(value, [], (_a = this._exact) !== null && _a !== void 0 ? _a : false); | ||
} | ||
toJSONSchema() { | ||
@@ -82,2 +96,10 @@ var _a; | ||
getExactContext(exact, wrapper) { | ||
if (exact === 'disabled') { | ||
return { | ||
context: undefined, | ||
managedContext: undefined, | ||
wrappedExact: 'disabled', | ||
nestedExact: 'disabled', | ||
}; | ||
} | ||
const context = typeof exact === 'boolean' ? undefined : exact; | ||
@@ -84,0 +106,0 @@ const selfExact = this._exact; |
@@ -12,3 +12,3 @@ "use strict"; | ||
if (TypeTuple.length < 2) { | ||
throw new TypeError('Expecting at least 2 type for union type'); | ||
throw new TypeError('Expected at least 2 elements for union type'); | ||
} | ||
@@ -30,3 +30,3 @@ super(); | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
_traverse(input, path, exact, callback) { | ||
const { wrappedExact } = this.getExactContext(exact, 'transparent'); | ||
@@ -36,4 +36,4 @@ let maxIssuePathLength = -1; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = typeof wrappedExact === 'boolean' ? wrappedExact : new _exact_context_1.ExactContext(); | ||
const [value, issues] = Type._decode(medium, unpacked, path, dedicatedExact); | ||
const dedicatedExact = typeof wrappedExact === 'object' ? new _exact_context_1.ExactContext() : wrappedExact; | ||
const [value, issues] = callback(Type, input, path, dedicatedExact); | ||
if ((0, _type_issue_1.hasNonDeferrableTypeIssue)(issues)) { | ||
@@ -55,3 +55,3 @@ const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
path, | ||
message: 'The unpacked value satisfies none of the type in the union type.', | ||
message: 'Value satisfies none of the type in the union type.', | ||
}, | ||
@@ -63,92 +63,2 @@ ...outputIssues, | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
const { wrappedExact } = diagnose | ||
? this.getExactContext(exact, 'transparent') | ||
: type_1.DISABLED_EXACT_CONTEXT_RESULT; | ||
let maxIssuePathLength = -1; | ||
let outputIssues; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = typeof wrappedExact === 'boolean' ? wrappedExact : new _exact_context_1.ExactContext(); | ||
const [unpacked, issues] = Type._encode(medium, value, path, dedicatedExact, diagnose); | ||
if ((0, _type_issue_1.hasNonDeferrableTypeIssue)(issues)) { | ||
const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
if (pathLength > maxIssuePathLength) { | ||
maxIssuePathLength = pathLength; | ||
outputIssues = issues; | ||
} | ||
continue; | ||
} | ||
syncDedicatedExact(wrappedExact, dedicatedExact); | ||
return [unpacked, issues]; | ||
} | ||
// If diagnose is `false`, it will never reach here. | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: 'The value satisfies none of the type in the union type.', | ||
}, | ||
...outputIssues, | ||
], | ||
]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
const { wrappedExact } = this.getExactContext(exact, 'transparent'); | ||
let maxIssuePathLength = -1; | ||
let outputIssues; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = typeof wrappedExact === 'boolean' ? wrappedExact : new _exact_context_1.ExactContext(); | ||
const [transformedUnpacked, issues] = Type._transform(from, to, unpacked, path, dedicatedExact); | ||
if ((0, _type_issue_1.hasNonDeferrableTypeIssue)(issues)) { | ||
const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
if (pathLength > maxIssuePathLength) { | ||
maxIssuePathLength = pathLength; | ||
outputIssues = issues; | ||
} | ||
continue; | ||
} | ||
syncDedicatedExact(wrappedExact, dedicatedExact); | ||
return [transformedUnpacked, issues]; | ||
} | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: 'The unpacked value satisfies none of the type in the union type.', | ||
}, | ||
...outputIssues, | ||
], | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
const { wrappedExact } = this.getExactContext(exact, 'transparent'); | ||
let maxIssuePathLength = -1; | ||
let outputIssues; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = typeof wrappedExact === 'boolean' ? wrappedExact : new _exact_context_1.ExactContext(); | ||
const issues = Type._diagnose(value, path, dedicatedExact); | ||
if ((0, _type_issue_1.hasNonDeferrableTypeIssue)(issues)) { | ||
const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
if (pathLength > maxIssuePathLength) { | ||
maxIssuePathLength = pathLength; | ||
outputIssues = issues; | ||
} | ||
continue; | ||
} | ||
syncDedicatedExact(wrappedExact, dedicatedExact); | ||
return issues; | ||
} | ||
return [ | ||
{ | ||
path, | ||
message: 'The value satisfies none of the type in the union type.', | ||
}, | ||
...outputIssues, | ||
]; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -172,4 +82,3 @@ var _b; | ||
function syncDedicatedExact(wrappedExact, dedicatedExact) { | ||
if (typeof wrappedExact !== 'boolean' && | ||
typeof dedicatedExact !== 'boolean') { | ||
if (typeof wrappedExact === 'object' && typeof dedicatedExact === 'object') { | ||
if (dedicatedExact.touched) { | ||
@@ -176,0 +85,0 @@ wrappedExact.addKeys(dedicatedExact.keys); |
@@ -14,3 +14,3 @@ "use strict"; | ||
if (typeof value !== 'string') { | ||
throw new TypeError(`Expected bigint string, getting ${toString.call(value)}`); | ||
throw new TypeError(`Expected bigint string, got ${toString.call(value)}`); | ||
} | ||
@@ -26,3 +26,3 @@ return BigInt(value); | ||
if (typeof value !== 'string') { | ||
throw new TypeError(`Expected ISO date string, getting ${toString.call(value)}`); | ||
throw new TypeError(`Expected ISO date string, got ${toString.call(value)}`); | ||
} | ||
@@ -42,3 +42,3 @@ const date = new Date(value); | ||
if (typeof value !== 'string') { | ||
throw new TypeError(`Expected regular expression literal, getting ${toString.call(value)}`); | ||
throw new TypeError(`Expected regular expression literal, got ${toString.call(value)}`); | ||
} | ||
@@ -45,0 +45,0 @@ const groups = REGEXP_LITERAL_REGEX.exec(value); |
@@ -54,3 +54,3 @@ "use strict"; | ||
if (typeof dict !== 'object' || dict === null) { | ||
throw new TypeError(`Expected non-null object, getting ${toString.call(dict)}`); | ||
throw new TypeError(`Expected non-null object, got ${toString.call(dict)}`); | ||
} | ||
@@ -57,0 +57,0 @@ return Object.entries(dict) |
@@ -9,3 +9,3 @@ "use strict"; | ||
exports.never = (0, core_1.atomic)(exports.neverTypeSymbol, value => { | ||
throw `Expected never, getting ${toString.call(value)}.`; | ||
throw `Expected never, got ${toString.call(value)}.`; | ||
}); | ||
@@ -15,22 +15,22 @@ exports.unknownTypeSymbol = Symbol(); | ||
exports.undefinedTypeSymbol = Symbol(); | ||
exports.undefined = (0, core_1.atomic)(exports.undefinedTypeSymbol, value => (0, utils_1.constraint)(value === void 0, () => `Expected undefined, getting ${toString.call(value)}.`)); | ||
exports.undefined = (0, core_1.atomic)(exports.undefinedTypeSymbol, value => (0, utils_1.constraint)(value === void 0, () => `Expected undefined, got ${toString.call(value)}.`)); | ||
exports.voidTypeSymbol = Symbol(); | ||
exports.voidType = (0, core_1.atomic)(exports.voidTypeSymbol, value => (0, utils_1.constraint)(value === void 0, () => `Expected undefined, getting ${toString.call(value)}.`)); | ||
exports.voidType = (0, core_1.atomic)(exports.voidTypeSymbol, value => (0, utils_1.constraint)(value === void 0, () => `Expected undefined, got ${toString.call(value)}.`)); | ||
exports.void = exports.voidType; | ||
exports.nullTypeSymbol = Symbol(); | ||
exports.nullType = (0, core_1.atomic)(exports.nullTypeSymbol, value => (0, utils_1.constraint)(value === null, () => `Expected null, getting ${toString.call(value)}.`), { type: 'null' }); | ||
exports.nullType = (0, core_1.atomic)(exports.nullTypeSymbol, value => (0, utils_1.constraint)(value === null, () => `Expected null, got ${toString.call(value)}.`), { type: 'null' }); | ||
exports.stringTypeSymbol = Symbol(); | ||
exports.string = (0, core_1.atomic)(exports.stringTypeSymbol, value => (0, utils_1.constraint)(typeof value === 'string', () => `Expected string, getting ${toString.call(value)}.`), { type: 'string' }); | ||
exports.string = (0, core_1.atomic)(exports.stringTypeSymbol, value => (0, utils_1.constraint)(typeof value === 'string', () => `Expected string, got ${toString.call(value)}.`), { type: 'string' }); | ||
exports.numberTypeSymbol = Symbol(); | ||
exports.number = (0, core_1.atomic)(exports.numberTypeSymbol, value => (0, utils_1.constraint)(typeof value === 'number', () => `Expected number, getting ${toString.call(value)}.`), { type: 'number' }); | ||
exports.number = (0, core_1.atomic)(exports.numberTypeSymbol, value => (0, utils_1.constraint)(typeof value === 'number', () => `Expected number, got ${toString.call(value)}.`), { type: 'number' }); | ||
exports.bigintTypeSymbol = Symbol(); | ||
exports.bigint = (0, core_1.atomic)(exports.bigintTypeSymbol, value => (0, utils_1.constraint)(typeof value === 'bigint', () => `Expected bigint, getting ${toString.call(value)}.`), { type: 'integer' }); | ||
exports.bigint = (0, core_1.atomic)(exports.bigintTypeSymbol, value => (0, utils_1.constraint)(typeof value === 'bigint', () => `Expected bigint, got ${toString.call(value)}.`), { type: 'integer' }); | ||
exports.booleanTypeSymbol = Symbol(); | ||
exports.boolean = (0, core_1.atomic)(exports.booleanTypeSymbol, value => (0, utils_1.constraint)(typeof value === 'boolean', () => `Expected boolean, getting ${toString.call(value)}.`), { type: 'boolean' }); | ||
exports.boolean = (0, core_1.atomic)(exports.booleanTypeSymbol, value => (0, utils_1.constraint)(typeof value === 'boolean', () => `Expected boolean, got ${toString.call(value)}.`), { type: 'boolean' }); | ||
exports.functionTypeSymbol = Symbol(); | ||
exports.Function = (0, core_1.atomic)(exports.functionTypeSymbol, value => (0, utils_1.constraint)(typeof value === 'function', () => `Expected function, getting ${toString.call(value)}.`)); | ||
exports.Function = (0, core_1.atomic)(exports.functionTypeSymbol, value => (0, utils_1.constraint)(typeof value === 'function', () => `Expected function, got ${toString.call(value)}.`)); | ||
exports.dateTypeSymbol = Symbol(); | ||
exports.Date = (0, core_1.atomic)(exports.dateTypeSymbol, value => (0, utils_1.constraint)(value instanceof globalThis.Date, () => `Expected instance of Date, getting ${toString.call(value)}.`)); | ||
exports.Date = (0, core_1.atomic)(exports.dateTypeSymbol, value => (0, utils_1.constraint)(value instanceof globalThis.Date, () => `Expected instance of Date, got ${toString.call(value)}.`)); | ||
exports.regexpTypeSymbol = Symbol(); | ||
exports.RegExp = (0, core_1.atomic)(exports.regexpTypeSymbol, value => (0, utils_1.constraint)(value instanceof globalThis.RegExp, () => `Expected instance of RegExp, getting ${toString.call(value)}.`)); | ||
exports.RegExp = (0, core_1.atomic)(exports.regexpTypeSymbol, value => (0, utils_1.constraint)(value instanceof globalThis.RegExp, () => `Expected instance of RegExp, got ${toString.call(value)}.`)); | ||
//# sourceMappingURL=types.js.map |
@@ -12,7 +12,7 @@ "use strict"; | ||
case 'string': | ||
return types_1.string.refined(value => (0, utils_1.refinement)(value === literal, value, () => `Expected string ${JSON.stringify(literal)}, getting ${JSON.stringify(value)}.`), { const: literal }); | ||
return types_1.string.refined(value => (0, utils_1.refinement)(value === literal, value, () => `Expected string ${JSON.stringify(literal)}, got ${JSON.stringify(value)}.`), { const: literal }); | ||
case 'number': | ||
return types_1.number.refined(value => (0, utils_1.refinement)(value === literal, value, () => `Expected number ${literal}, getting ${value}.`), { const: literal }); | ||
return types_1.number.refined(value => (0, utils_1.refinement)(value === literal, value, () => `Expected number ${literal}, got ${value}.`), { const: literal }); | ||
case 'boolean': | ||
return types_1.boolean.refined(value => (0, utils_1.refinement)(value === literal, value, () => `Expected boolean ${literal}, getting ${value}.`), { const: literal }); | ||
return types_1.boolean.refined(value => (0, utils_1.refinement)(value === literal, value, () => `Expected boolean ${literal}, got ${value}.`), { const: literal }); | ||
default: | ||
@@ -19,0 +19,0 @@ throw new TypeError('Unsupported literal value'); |
@@ -6,10 +6,10 @@ "use strict"; | ||
const utils_1 = require("../utils"); | ||
exports.Integer = types_1.number.refined(value => (0, utils_1.refinement)(Number.isInteger(value), value, () => `Expected integer, getting ${value}.`), { type: 'integer' }); | ||
exports.Integer = types_1.number.refined(value => (0, utils_1.refinement)(Number.isInteger(value), value, () => `Expected integer, got ${value}.`), { type: 'integer' }); | ||
function integerRange({ min = -Infinity, max = Infinity, }) { | ||
return exports.Integer.refined(value => { | ||
if (value < min) { | ||
throw `Expected integer >= ${min}, getting ${value}.`; | ||
throw `Expected integer >= ${min}, got ${value}.`; | ||
} | ||
if (value > max) { | ||
throw `Expected integer <= ${max}, getting ${value}.`; | ||
throw `Expected integer <= ${max}, got ${value}.`; | ||
} | ||
@@ -26,12 +26,12 @@ return value; | ||
if (value < minInclusive) { | ||
throw `Expected number >= ${minInclusive}, getting ${value}.`; | ||
throw `Expected number >= ${minInclusive}, got ${value}.`; | ||
} | ||
if (value <= minExclusive) { | ||
throw `Expected number > ${minExclusive}, getting ${value}.`; | ||
throw `Expected number > ${minExclusive}, got ${value}.`; | ||
} | ||
if (value > maxInclusive) { | ||
throw `Expected number <= ${maxInclusive}, getting ${value}.`; | ||
throw `Expected number <= ${maxInclusive}, got ${value}.`; | ||
} | ||
if (value >= maxExclusive) { | ||
throw `Expected number < ${maxExclusive}, getting ${value}.`; | ||
throw `Expected number < ${maxExclusive}, got ${value}.`; | ||
} | ||
@@ -38,0 +38,0 @@ return value; |
var _a; | ||
import { hasNonDeferrableTypeIssue } from './@type-issue'; | ||
import { DISABLED_EXACT_CONTEXT_RESULT, Type } from './type'; | ||
import { Type } from './type'; | ||
import { __type_kind } from './type-partials'; | ||
@@ -23,4 +23,4 @@ const toString = Object.prototype.toString; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
if (!Array.isArray(unpacked)) { | ||
_traverse(input, path, exact, callback) { | ||
if (!Array.isArray(input)) { | ||
return [ | ||
@@ -31,3 +31,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call(unpacked)}.`, | ||
message: `Expected an array, got ${toString.call(input)}.`, | ||
}, | ||
@@ -39,81 +39,13 @@ ], | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
const value = []; | ||
const output = []; | ||
const issues = []; | ||
for (const [index, unpackedElement] of unpacked.entries()) { | ||
const [element, entryIssues] = ElementType._decode(medium, unpackedElement, [...path, index], nestedExact); | ||
value.push(element); | ||
for (const [index, value] of input.entries()) { | ||
const [element, entryIssues] = ElementType._traverse(value, [...path, index], nestedExact, callback); | ||
output.push(element); | ||
issues.push(...entryIssues); | ||
} | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(unpacked.keys(), key => key.toString())); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(input.keys(), key => key.toString())); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : output, issues]; | ||
} | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
if (diagnose && !Array.isArray(value)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be an array, getting ${toString.call(value)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementType = this.ElementType; | ||
const { context, nestedExact } = diagnose | ||
? this.getExactContext(exact, false) | ||
: DISABLED_EXACT_CONTEXT_RESULT; | ||
const unpacked = []; | ||
const issues = []; | ||
for (const [index, valueElement] of value.entries()) { | ||
const [unpackedElement, entryIssues] = ElementType._encode(medium, valueElement, [...path, index], nestedExact, diagnose); | ||
unpacked.push(unpackedElement); | ||
issues.push(...entryIssues); | ||
} | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(value.keys(), key => key.toString())); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : unpacked, issues]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
if (!Array.isArray(unpacked)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementType = this.ElementType; | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
const value = []; | ||
const issues = []; | ||
for (const [index, unpackedElement] of unpacked.entries()) { | ||
const [element, entryIssues] = ElementType._transform(from, to, unpackedElement, [...path, index], nestedExact); | ||
value.push(element); | ||
issues.push(...entryIssues); | ||
} | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(unpacked.keys(), key => key.toString())); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
if (!Array.isArray(value)) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting an array, getting ${toString.call(value)}.`, | ||
}, | ||
]; | ||
} | ||
const ElementType = this.ElementType; | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
const issues = value.flatMap((element, index) => ElementType._diagnose(element, [...path, index], nestedExact)); | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(value.keys(), key => key.toString())); | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -120,0 +52,0 @@ var _b; |
@@ -66,22 +66,5 @@ var _a; | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
const symbol = this.symbol; | ||
let value; | ||
try { | ||
value = from.getCodec(symbol).decode(unpacked); | ||
} | ||
catch (error) { | ||
return [undefined, [buildIssueByError(error, path)]]; | ||
} | ||
const issues = this._diagnose(value, path, exact); | ||
if (hasNonDeferrableTypeIssue(issues)) { | ||
return [undefined, issues]; | ||
} | ||
try { | ||
return [to.getCodec(symbol).encode(value), issues]; | ||
} | ||
catch (error) { | ||
issues.push(buildIssueByError(error, path)); | ||
return [undefined, issues]; | ||
} | ||
_sanitize(value, path) { | ||
const issues = this._diagnose(value, path, 'disabled'); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
} | ||
@@ -88,0 +71,0 @@ /** @internal */ |
var _a; | ||
import { hasNonDeferrableTypeIssue, } from './@type-issue'; | ||
import { Type, TypeConstraintError } from './type'; | ||
@@ -39,3 +40,3 @@ import { __type_kind } from './type-partials'; | ||
path: [], | ||
message: `Expecting at least ${ArgumentTypeTuple.length} argument(s), getting ${args.length}.`, | ||
message: `Expected at least ${ArgumentTypeTuple.length} argument(s), got ${args.length}.`, | ||
}, | ||
@@ -63,3 +64,3 @@ ]); | ||
path: [], | ||
message: `Expecting at least ${ArgumentTypeTuple.length} argument(s), getting ${args.length}.`, | ||
message: `Expected at least ${ArgumentTypeTuple.length} argument(s), got ${args.length}.`, | ||
}, | ||
@@ -88,45 +89,15 @@ ]); | ||
/** @internal */ | ||
_decode(_medium, unpacked, path, _exact) { | ||
if (typeof unpacked !== 'function') { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a function, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
return [unpacked, []]; | ||
_decode(_medium, unpacked, path, exact) { | ||
const issues = this._diagnose(unpacked, path, exact); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : unpacked, issues]; | ||
} | ||
/** @internal */ | ||
_encode(_medium, value, path, _exact, diagnose) { | ||
if (diagnose && typeof value !== 'function') { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be a function, getting ${toString.call(value)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
return [value, []]; | ||
_encode(_medium, value, path, exact, diagnose) { | ||
const issues = diagnose ? this._diagnose(value, path, exact) : []; | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
} | ||
/** @internal */ | ||
_transform(_from, _to, unpacked, path, _exact) { | ||
if (typeof unpacked !== 'function') { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a function, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
return [unpacked, []]; | ||
_sanitize(value, path) { | ||
const issues = this._diagnose(value, path, 'disabled'); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
} | ||
@@ -139,3 +110,3 @@ /** @internal */ | ||
path, | ||
message: `Expecting a function, getting ${toString.call(value)}.`, | ||
message: `Expected a function, got ${toString.call(value)}.`, | ||
}, | ||
@@ -142,0 +113,0 @@ ]; |
var _a; | ||
import { hasNonDeferrableTypeIssue } from './@type-issue'; | ||
import { DISABLED_EXACT_CONTEXT_RESULT, Type } from './type'; | ||
import { Type } from './type'; | ||
import { __type_kind } from './type-partials'; | ||
@@ -9,3 +9,3 @@ const hasOwnProperty = Object.prototype.hasOwnProperty; | ||
if (TypeTuple.length < 2) { | ||
throw new TypeError('Expecting at least 2 types for intersection type'); | ||
throw new TypeError('Expected at least 2 elements for intersection type'); | ||
} | ||
@@ -27,3 +27,3 @@ super(); | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
_traverse(input, path, exact, callback) { | ||
const { managedContext, wrappedExact } = this.getExactContext(exact, 'managed'); | ||
@@ -33,3 +33,3 @@ const partials = []; | ||
for (const Type of this.TypeTuple) { | ||
const [partial, partialIssues] = Type._decode(medium, unpacked, path, wrappedExact); | ||
const [partial, partialIssues] = callback(Type, input, path, wrappedExact); | ||
partials.push(partial); | ||
@@ -39,3 +39,3 @@ issues.push(...partialIssues); | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
issues.push(...managedContext.getUnknownKeyIssues(input, path)); | ||
} | ||
@@ -50,53 +50,2 @@ return [ | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
const { managedContext, wrappedExact } = diagnose | ||
? this.getExactContext(exact, 'managed') | ||
: DISABLED_EXACT_CONTEXT_RESULT; | ||
const partials = []; | ||
const issues = []; | ||
for (const Type of this.TypeTuple) { | ||
const [partial, partialIssues] = Type._encode(medium, value, path, wrappedExact, diagnose); | ||
partials.push(partial); | ||
issues.push(...partialIssues); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: internal_mergeIntersectionPartials(partials), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
const { managedContext, wrappedExact } = this.getExactContext(exact, 'managed'); | ||
const partials = []; | ||
const issues = []; | ||
for (const Type of this.TypeTuple) { | ||
const [partial, partialIssues] = Type._transform(from, to, unpacked, path, wrappedExact); | ||
partials.push(partial); | ||
issues.push(...partialIssues); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: internal_mergeIntersectionPartials(partials), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
const { managedContext, wrappedExact } = this.getExactContext(exact, 'managed'); | ||
const issues = this.TypeTuple.flatMap(Type => Type._diagnose(value, path, wrappedExact)); | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -103,0 +52,0 @@ var _b; |
@@ -53,4 +53,4 @@ var _a; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
_traverse(input, path, exact, callback) { | ||
if (typeof input !== 'object' || input === null) { | ||
return [ | ||
@@ -61,3 +61,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call(unpacked)}.`, | ||
message: `Expected a non-null object, got ${toString.call(input)}.`, | ||
}, | ||
@@ -71,11 +71,11 @@ ], | ||
for (const [key, Type] of Object.entries(this.definition)) { | ||
const [value, entryIssues] = Type._decode(medium, unpacked[key], [...path, key], nestedExact); | ||
const [value, entryIssues] = callback(Type, input[key], [...path, key], nestedExact); | ||
entries.push([key, value]); | ||
issues.push(...entryIssues); | ||
} | ||
if (wrappedExact) { | ||
if (typeof wrappedExact === 'object') { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
issues.push(...managedContext.getUnknownKeyIssues(input, path)); | ||
} | ||
@@ -90,100 +90,2 @@ return [ | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
if (diagnose && (typeof value !== 'object' || value === null)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be a non-null object, getting ${toString.call(value)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const { managedContext, wrappedExact, nestedExact } = diagnose | ||
? this.getExactContext(exact, 'managed') | ||
: { | ||
managedContext: undefined, | ||
wrappedExact: false, | ||
nestedExact: false, | ||
}; | ||
const entries = []; | ||
const issues = []; | ||
for (const [key, Type] of Object.entries(this.definition)) { | ||
const [unpacked, entryIssues] = Type._encode(medium, value[key], [...path, key], nestedExact, diagnose); | ||
entries.push([key, unpacked]); | ||
issues.push(...entryIssues); | ||
} | ||
if (wrappedExact) { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: Object.fromEntries(entries), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const { managedContext, wrappedExact, nestedExact } = this.getExactContext(exact, 'managed'); | ||
const entries = []; | ||
const issues = []; | ||
for (const [key, Type] of Object.entries(this.definition)) { | ||
const [transformedUnpacked, entryIssues] = Type._transform(from, to, unpacked[key], [...path, key], nestedExact); | ||
entries.push([key, transformedUnpacked]); | ||
issues.push(...entryIssues); | ||
} | ||
if (wrappedExact) { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: Object.fromEntries(entries), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
if (typeof value !== 'object' || value === null) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting a non-null object, getting ${toString.call(value)}.`, | ||
}, | ||
]; | ||
} | ||
const { managedContext, wrappedExact, nestedExact } = this.getExactContext(exact, 'managed'); | ||
const issues = []; | ||
const entries = Object.entries(this.definition); | ||
for (const [key, Type] of entries) { | ||
issues.push(...Type._diagnose(value[key], [...path, key], nestedExact)); | ||
} | ||
if (wrappedExact) { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -190,0 +92,0 @@ var _b; |
@@ -22,24 +22,8 @@ var _a; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
return unpacked === undefined | ||
_traverse(input, path, exact, callback) { | ||
return input === undefined | ||
? [undefined, []] | ||
: this.Type._decode(medium, unpacked, path, exact); | ||
: callback(this.Type, input, path, exact); | ||
} | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
return value === undefined | ||
? [undefined, []] | ||
: this.Type._encode(medium, value, path, exact, diagnose); | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
return unpacked === undefined | ||
? [undefined, []] | ||
: this.Type._transform(from, to, unpacked, path, exact); | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
return value === undefined ? [] : this.Type._diagnose(value, path, exact); | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -46,0 +30,0 @@ const { schema } = this.Type._toJSONSchema(context, exact); |
var _a; | ||
import { hasNonDeferrableTypeIssue } from './@type-issue'; | ||
import { DISABLED_EXACT_CONTEXT_RESULT, Type } from './type'; | ||
import { Type } from './type'; | ||
import { __type_kind } from './type-partials'; | ||
@@ -29,4 +29,4 @@ const toString = Object.prototype.toString; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
_traverse(input, path, exact, callback) { | ||
if (typeof input !== 'object' || input === null) { | ||
return [ | ||
@@ -37,3 +37,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call(unpacked)}.`, | ||
message: `Expected a non-null object, got ${toString.call(input)}.`, | ||
}, | ||
@@ -48,99 +48,17 @@ ], | ||
const entries = []; | ||
const issues = []; | ||
for (const [key, unpackedValue] of getRecordEntries(unpacked)) { | ||
const [value, valueIssues] = Value._decode(medium, unpackedValue, [...path, key], nestedExact); | ||
entries.push([key, value]); | ||
issues.push(...Key._diagnose(key, [...path, { key }], nestedExact), ...valueIssues); | ||
const aggregatedIssues = []; | ||
for (const [key, value] of getRecordEntries(input)) { | ||
const keyIssues = Key._diagnose(key, [...path, { key }], nestedExact); | ||
const [output, valueIssues] = Value._traverse(value, [...path, key], nestedExact, callback); | ||
entries.push([key, output]); | ||
aggregatedIssues.push(...keyIssues, ...valueIssues); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
hasNonDeferrableTypeIssue(aggregatedIssues) | ||
? undefined | ||
: buildRecord(entries, unpacked), | ||
issues, | ||
: buildRecord(entries, input), | ||
aggregatedIssues, | ||
]; | ||
} | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
if (diagnose && (typeof value !== 'object' || value === null)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be a non-null object, getting ${toString.call(value)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const Key = this.Key; | ||
const Value = this.Value; | ||
const { context, nestedExact } = diagnose | ||
? this.getExactContext(exact, false) | ||
: DISABLED_EXACT_CONTEXT_RESULT; | ||
context === null || context === void 0 ? void 0 : context.neutralize(); | ||
const entries = []; | ||
const issues = []; | ||
for (const [key, nestedValue] of getRecordEntries(value)) { | ||
const [unpacked, valueIssues] = Value._encode(medium, nestedValue, [...path, key], nestedExact, diagnose); | ||
entries.push([key, unpacked]); | ||
issues.push(...Key._diagnose(key, [...path, { key }], nestedExact), ...valueIssues); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: buildRecord(entries, value), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const Key = this.Key; | ||
const Value = this.Value; | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
context === null || context === void 0 ? void 0 : context.neutralize(); | ||
const entries = []; | ||
const issues = []; | ||
for (const [key, unpackedValue] of getRecordEntries(unpacked)) { | ||
const [transformedUnpacked, valueIssues] = Value._transform(from, to, unpackedValue, [...path, key], nestedExact); | ||
entries.push([key, transformedUnpacked]); | ||
issues.push(...Key._diagnose(key, [...path, { key }], nestedExact), ...valueIssues); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: buildRecord(entries, unpacked), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
if (typeof value !== 'object' || value === null) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting a non-null object, getting ${toString.call(value)}.`, | ||
}, | ||
]; | ||
} | ||
const Key = this.Key; | ||
const Value = this.Value; | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
context === null || context === void 0 ? void 0 : context.neutralize(); | ||
return getRecordEntries(value).flatMap(([key, nestedValue]) => [ | ||
...Key._diagnose(key, [...path, { key }], nestedExact), | ||
...Value._diagnose(nestedValue, [...path, key], nestedExact), | ||
]); | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -147,0 +65,0 @@ var _b; |
@@ -22,18 +22,6 @@ var _a; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
return this.Type._decode(medium, unpacked, path, exact); | ||
_traverse(input, path, exact, callback) { | ||
return callback(this.Type, input, path, exact); | ||
} | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
return this.Type._encode(medium, value, path, exact, diagnose); | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
return this.Type._transform(from, to, unpacked, path, exact); | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
return this.Type._diagnose(value, path, exact); | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -40,0 +28,0 @@ var _b; |
@@ -59,3 +59,3 @@ var _a; | ||
path, | ||
message: 'Expecting encoding value to be stable after refinements.', | ||
message: 'Expected encoding value to be stable after refinements.', | ||
}); | ||
@@ -70,9 +70,13 @@ } | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
const [value, issues] = this._decode(from, unpacked, path, exact); | ||
_sanitize(value, path) { | ||
const [sanitized, issues] = this.Type._sanitize(value, path); | ||
if (hasNonDeferrableTypeIssue(issues)) { | ||
return [undefined, issues]; | ||
} | ||
const [transformedUnpacked] = this._encode(to, value, path, false, false); | ||
return [transformedUnpacked, issues]; | ||
const [refined, refinementIssues] = this.processRefinements(sanitized, path); | ||
issues.push(...refinementIssues); | ||
if (hasNonDeferrableTypeIssue(refinementIssues)) { | ||
return [undefined, issues]; | ||
} | ||
return [refined, issues]; | ||
} | ||
@@ -79,0 +83,0 @@ /** @internal */ |
var _a; | ||
import { hasNonDeferrableTypeIssue } from './@type-issue'; | ||
import { DISABLED_EXACT_CONTEXT_RESULT, Type } from './type'; | ||
import { Type } from './type'; | ||
import { __type_kind } from './type-partials'; | ||
@@ -23,4 +23,4 @@ const toString = Object.prototype.toString; | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
if (!Array.isArray(unpacked)) { | ||
_traverse(input, path, exact, callback) { | ||
if (!Array.isArray(input)) { | ||
return [ | ||
@@ -31,3 +31,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call(unpacked)}.`, | ||
message: `Expected an array, got ${toString.call(input)}.`, | ||
}, | ||
@@ -38,3 +38,3 @@ ], | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if (unpacked.length !== ElementTypeTuple.length) { | ||
if (input.length !== ElementTypeTuple.length) { | ||
return [ | ||
@@ -45,3 +45,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value with ${ElementTypeTuple.length} instead of ${unpacked.length} element(s).`, | ||
message: `Expected value with ${ElementTypeTuple.length} instead of ${input.length} element(s).`, | ||
}, | ||
@@ -55,3 +55,3 @@ ], | ||
for (const [index, Element] of ElementTypeTuple.entries()) { | ||
const [element, entryIssues] = Element._decode(medium, unpacked[index], [...path, index], nestedExact); | ||
const [element, entryIssues] = callback(Element, input[index], [...path, index], nestedExact); | ||
value.push(element); | ||
@@ -64,100 +64,2 @@ issues.push(...entryIssues); | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
if (diagnose && !Array.isArray(value)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be an array, getting ${toString.call(value)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if (value.length !== ElementTypeTuple.length) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value with ${ElementTypeTuple.length} instead of ${value.length} element(s).`, | ||
}, | ||
], | ||
]; | ||
} | ||
const { context, nestedExact } = diagnose | ||
? this.getExactContext(exact, false) | ||
: DISABLED_EXACT_CONTEXT_RESULT; | ||
const unpacked = []; | ||
const issues = []; | ||
for (const [index, Element] of ElementTypeTuple.entries()) { | ||
const [unpackedElement, entryIssues] = Element._encode(medium, value[index], [...path, index], nestedExact, diagnose); | ||
unpacked.push(unpackedElement); | ||
issues.push(...entryIssues); | ||
} | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(ElementTypeTuple.keys(), key => key.toString())); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : unpacked, issues]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
if (!Array.isArray(unpacked)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call(unpacked)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if (unpacked.length !== ElementTypeTuple.length) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value with ${ElementTypeTuple.length} instead of ${unpacked.length} element(s).`, | ||
}, | ||
], | ||
]; | ||
} | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
const value = []; | ||
const issues = []; | ||
for (const [index, Element] of ElementTypeTuple.entries()) { | ||
const [element, entryIssues] = Element._transform(from, to, unpacked[index], [...path, index], nestedExact); | ||
value.push(element); | ||
issues.push(...entryIssues); | ||
} | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(ElementTypeTuple.keys(), key => key.toString())); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
if (!Array.isArray(value)) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting an array, getting ${toString.call(value)}.`, | ||
}, | ||
]; | ||
} | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if (value.length !== ElementTypeTuple.length) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting value with ${ElementTypeTuple.length} instead of ${value.length} element(s).`, | ||
}, | ||
]; | ||
} | ||
const { context, nestedExact } = this.getExactContext(exact, false); | ||
const issues = ElementTypeTuple.flatMap((Element, index) => Element._diagnose(value[index], [...path, index], nestedExact)); | ||
context === null || context === void 0 ? void 0 : context.addKeys(Array.from(ElementTypeTuple.keys(), key => key.toString())); | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -164,0 +66,0 @@ var _b; |
@@ -12,2 +12,26 @@ var _a; | ||
} | ||
/** @internal */ | ||
_traverse(input, path, exact, callback) { | ||
return callback(this, input, path, exact); | ||
} | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact, callback) { | ||
return this._traverse(unpacked, path, exact, (Type, value, path, exact) => Type._decode(medium, value, path, exact, callback)); | ||
} | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose, callback) { | ||
return this._traverse(value, path, exact, (Type, value, path, exact) => Type._encode(medium, value, path, exact, diagnose, callback)); | ||
} | ||
/** @internal */ | ||
_sanitize(value, path) { | ||
return this._traverse(value, path, 'disabled', (Type, value, path) => Type._sanitize(value, path)); | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
const [, issues] = this._traverse(value, path, exact, (Type, value, path, exact) => [ | ||
undefined, | ||
Type._diagnose(value, path, exact), | ||
]); | ||
return issues; | ||
} | ||
} | ||
@@ -14,0 +38,0 @@ _a = __type_in_mediums; |
@@ -44,3 +44,10 @@ import { ExactContext } from './@exact-context'; | ||
const unpacked = from.unpack(packed); | ||
const [transformedUnpacked, issues] = this._transform(from, to, unpacked, [], (_a = this._exact) !== null && _a !== void 0 ? _a : false); | ||
const callback = (Type, value, path, exact) => { | ||
const [decoded, issues] = Type._decode(from, value, path, exact); | ||
if (issues.length > 0) { | ||
return [undefined, issues]; | ||
} | ||
return Type._encode(to, decoded, path, exact, false); | ||
}; | ||
const [transformedUnpacked, issues] = this._traverse(unpacked, [], (_a = this._exact) !== null && _a !== void 0 ? _a : false, callback); | ||
if (issues.length > 0) { | ||
@@ -51,2 +58,13 @@ throw new TypeConstraintError(`Failed to transform medium`, issues); | ||
} | ||
sanitize(value) { | ||
const [sanitized, issues] = this._sanitize(value, []); | ||
if (issues.length > 0) { | ||
throw new TypeConstraintError('Value does not satisfy the type', issues); | ||
} | ||
return sanitized; | ||
} | ||
diagnose(value) { | ||
var _a; | ||
return this._diagnose(value, [], (_a = this._exact) !== null && _a !== void 0 ? _a : false); | ||
} | ||
satisfies(value) { | ||
@@ -65,6 +83,2 @@ const issues = this.diagnose(value); | ||
} | ||
diagnose(value) { | ||
var _a; | ||
return this._diagnose(value, [], (_a = this._exact) !== null && _a !== void 0 ? _a : false); | ||
} | ||
toJSONSchema() { | ||
@@ -79,2 +93,10 @@ var _a; | ||
getExactContext(exact, wrapper) { | ||
if (exact === 'disabled') { | ||
return { | ||
context: undefined, | ||
managedContext: undefined, | ||
wrappedExact: 'disabled', | ||
nestedExact: 'disabled', | ||
}; | ||
} | ||
const context = typeof exact === 'boolean' ? undefined : exact; | ||
@@ -81,0 +103,0 @@ const selfExact = this._exact; |
var _a; | ||
import { ExactContext } from './@exact-context'; | ||
import { hasNonDeferrableTypeIssue } from './@type-issue'; | ||
import { DISABLED_EXACT_CONTEXT_RESULT, Type } from './type'; | ||
import { Type } from './type'; | ||
import { __type_kind } from './type-partials'; | ||
@@ -9,3 +9,3 @@ export class UnionType extends Type { | ||
if (TypeTuple.length < 2) { | ||
throw new TypeError('Expecting at least 2 type for union type'); | ||
throw new TypeError('Expected at least 2 elements for union type'); | ||
} | ||
@@ -27,3 +27,3 @@ super(); | ||
/** @internal */ | ||
_decode(medium, unpacked, path, exact) { | ||
_traverse(input, path, exact, callback) { | ||
const { wrappedExact } = this.getExactContext(exact, 'transparent'); | ||
@@ -33,4 +33,4 @@ let maxIssuePathLength = -1; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = typeof wrappedExact === 'boolean' ? wrappedExact : new ExactContext(); | ||
const [value, issues] = Type._decode(medium, unpacked, path, dedicatedExact); | ||
const dedicatedExact = typeof wrappedExact === 'object' ? new ExactContext() : wrappedExact; | ||
const [value, issues] = callback(Type, input, path, dedicatedExact); | ||
if (hasNonDeferrableTypeIssue(issues)) { | ||
@@ -52,3 +52,3 @@ const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
path, | ||
message: 'The unpacked value satisfies none of the type in the union type.', | ||
message: 'Value satisfies none of the type in the union type.', | ||
}, | ||
@@ -60,92 +60,2 @@ ...outputIssues, | ||
/** @internal */ | ||
_encode(medium, value, path, exact, diagnose) { | ||
const { wrappedExact } = diagnose | ||
? this.getExactContext(exact, 'transparent') | ||
: DISABLED_EXACT_CONTEXT_RESULT; | ||
let maxIssuePathLength = -1; | ||
let outputIssues; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = typeof wrappedExact === 'boolean' ? wrappedExact : new ExactContext(); | ||
const [unpacked, issues] = Type._encode(medium, value, path, dedicatedExact, diagnose); | ||
if (hasNonDeferrableTypeIssue(issues)) { | ||
const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
if (pathLength > maxIssuePathLength) { | ||
maxIssuePathLength = pathLength; | ||
outputIssues = issues; | ||
} | ||
continue; | ||
} | ||
syncDedicatedExact(wrappedExact, dedicatedExact); | ||
return [unpacked, issues]; | ||
} | ||
// If diagnose is `false`, it will never reach here. | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: 'The value satisfies none of the type in the union type.', | ||
}, | ||
...outputIssues, | ||
], | ||
]; | ||
} | ||
/** @internal */ | ||
_transform(from, to, unpacked, path, exact) { | ||
const { wrappedExact } = this.getExactContext(exact, 'transparent'); | ||
let maxIssuePathLength = -1; | ||
let outputIssues; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = typeof wrappedExact === 'boolean' ? wrappedExact : new ExactContext(); | ||
const [transformedUnpacked, issues] = Type._transform(from, to, unpacked, path, dedicatedExact); | ||
if (hasNonDeferrableTypeIssue(issues)) { | ||
const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
if (pathLength > maxIssuePathLength) { | ||
maxIssuePathLength = pathLength; | ||
outputIssues = issues; | ||
} | ||
continue; | ||
} | ||
syncDedicatedExact(wrappedExact, dedicatedExact); | ||
return [transformedUnpacked, issues]; | ||
} | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: 'The unpacked value satisfies none of the type in the union type.', | ||
}, | ||
...outputIssues, | ||
], | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value, path, exact) { | ||
const { wrappedExact } = this.getExactContext(exact, 'transparent'); | ||
let maxIssuePathLength = -1; | ||
let outputIssues; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = typeof wrappedExact === 'boolean' ? wrappedExact : new ExactContext(); | ||
const issues = Type._diagnose(value, path, dedicatedExact); | ||
if (hasNonDeferrableTypeIssue(issues)) { | ||
const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
if (pathLength > maxIssuePathLength) { | ||
maxIssuePathLength = pathLength; | ||
outputIssues = issues; | ||
} | ||
continue; | ||
} | ||
syncDedicatedExact(wrappedExact, dedicatedExact); | ||
return issues; | ||
} | ||
return [ | ||
{ | ||
path, | ||
message: 'The value satisfies none of the type in the union type.', | ||
}, | ||
...outputIssues, | ||
]; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context, exact) { | ||
@@ -167,4 +77,3 @@ var _b; | ||
function syncDedicatedExact(wrappedExact, dedicatedExact) { | ||
if (typeof wrappedExact !== 'boolean' && | ||
typeof dedicatedExact !== 'boolean') { | ||
if (typeof wrappedExact === 'object' && typeof dedicatedExact === 'object') { | ||
if (dedicatedExact.touched) { | ||
@@ -171,0 +80,0 @@ wrappedExact.addKeys(dedicatedExact.keys); |
@@ -11,3 +11,3 @@ import { bigintTypeSymbol, dateTypeSymbol, regexpTypeSymbol } from '../types'; | ||
if (typeof value !== 'string') { | ||
throw new TypeError(`Expected bigint string, getting ${toString.call(value)}`); | ||
throw new TypeError(`Expected bigint string, got ${toString.call(value)}`); | ||
} | ||
@@ -23,3 +23,3 @@ return BigInt(value); | ||
if (typeof value !== 'string') { | ||
throw new TypeError(`Expected ISO date string, getting ${toString.call(value)}`); | ||
throw new TypeError(`Expected ISO date string, got ${toString.call(value)}`); | ||
} | ||
@@ -39,3 +39,3 @@ const date = new Date(value); | ||
if (typeof value !== 'string') { | ||
throw new TypeError(`Expected regular expression literal, getting ${toString.call(value)}`); | ||
throw new TypeError(`Expected regular expression literal, got ${toString.call(value)}`); | ||
} | ||
@@ -42,0 +42,0 @@ const groups = REGEXP_LITERAL_REGEX.exec(value); |
@@ -51,3 +51,3 @@ import { atomicTypeSymbol, medium } from '../core'; | ||
if (typeof dict !== 'object' || dict === null) { | ||
throw new TypeError(`Expected non-null object, getting ${toString.call(dict)}`); | ||
throw new TypeError(`Expected non-null object, got ${toString.call(dict)}`); | ||
} | ||
@@ -54,0 +54,0 @@ return Object.entries(dict) |
@@ -6,3 +6,3 @@ import { atomic } from './core'; | ||
export const never = atomic(neverTypeSymbol, value => { | ||
throw `Expected never, getting ${toString.call(value)}.`; | ||
throw `Expected never, got ${toString.call(value)}.`; | ||
}); | ||
@@ -12,22 +12,22 @@ export const unknownTypeSymbol = Symbol(); | ||
export const undefinedTypeSymbol = Symbol(); | ||
export const undefined = atomic(undefinedTypeSymbol, value => constraint(value === void 0, () => `Expected undefined, getting ${toString.call(value)}.`)); | ||
export const undefined = atomic(undefinedTypeSymbol, value => constraint(value === void 0, () => `Expected undefined, got ${toString.call(value)}.`)); | ||
export const voidTypeSymbol = Symbol(); | ||
export const voidType = atomic(voidTypeSymbol, value => constraint(value === void 0, () => `Expected undefined, getting ${toString.call(value)}.`)); | ||
export const voidType = atomic(voidTypeSymbol, value => constraint(value === void 0, () => `Expected undefined, got ${toString.call(value)}.`)); | ||
export { voidType as void }; | ||
export const nullTypeSymbol = Symbol(); | ||
export const nullType = atomic(nullTypeSymbol, value => constraint(value === null, () => `Expected null, getting ${toString.call(value)}.`), { type: 'null' }); | ||
export const nullType = atomic(nullTypeSymbol, value => constraint(value === null, () => `Expected null, got ${toString.call(value)}.`), { type: 'null' }); | ||
export const stringTypeSymbol = Symbol(); | ||
export const string = atomic(stringTypeSymbol, value => constraint(typeof value === 'string', () => `Expected string, getting ${toString.call(value)}.`), { type: 'string' }); | ||
export const string = atomic(stringTypeSymbol, value => constraint(typeof value === 'string', () => `Expected string, got ${toString.call(value)}.`), { type: 'string' }); | ||
export const numberTypeSymbol = Symbol(); | ||
export const number = atomic(numberTypeSymbol, value => constraint(typeof value === 'number', () => `Expected number, getting ${toString.call(value)}.`), { type: 'number' }); | ||
export const number = atomic(numberTypeSymbol, value => constraint(typeof value === 'number', () => `Expected number, got ${toString.call(value)}.`), { type: 'number' }); | ||
export const bigintTypeSymbol = Symbol(); | ||
export const bigint = atomic(bigintTypeSymbol, value => constraint(typeof value === 'bigint', () => `Expected bigint, getting ${toString.call(value)}.`), { type: 'integer' }); | ||
export const bigint = atomic(bigintTypeSymbol, value => constraint(typeof value === 'bigint', () => `Expected bigint, got ${toString.call(value)}.`), { type: 'integer' }); | ||
export const booleanTypeSymbol = Symbol(); | ||
export const boolean = atomic(booleanTypeSymbol, value => constraint(typeof value === 'boolean', () => `Expected boolean, getting ${toString.call(value)}.`), { type: 'boolean' }); | ||
export const boolean = atomic(booleanTypeSymbol, value => constraint(typeof value === 'boolean', () => `Expected boolean, got ${toString.call(value)}.`), { type: 'boolean' }); | ||
export const functionTypeSymbol = Symbol(); | ||
export const Function = atomic(functionTypeSymbol, value => constraint(typeof value === 'function', () => `Expected function, getting ${toString.call(value)}.`)); | ||
export const Function = atomic(functionTypeSymbol, value => constraint(typeof value === 'function', () => `Expected function, got ${toString.call(value)}.`)); | ||
export const dateTypeSymbol = Symbol(); | ||
export const Date = atomic(dateTypeSymbol, value => constraint(value instanceof globalThis.Date, () => `Expected instance of Date, getting ${toString.call(value)}.`)); | ||
export const Date = atomic(dateTypeSymbol, value => constraint(value instanceof globalThis.Date, () => `Expected instance of Date, got ${toString.call(value)}.`)); | ||
export const regexpTypeSymbol = Symbol(); | ||
export const RegExp = atomic(regexpTypeSymbol, value => constraint(value instanceof globalThis.RegExp, () => `Expected instance of RegExp, getting ${toString.call(value)}.`)); | ||
export const RegExp = atomic(regexpTypeSymbol, value => constraint(value instanceof globalThis.RegExp, () => `Expected instance of RegExp, got ${toString.call(value)}.`)); | ||
//# sourceMappingURL=types.js.map |
@@ -8,7 +8,7 @@ import isEqual from 'lodash.isequal'; | ||
case 'string': | ||
return string.refined(value => refinement(value === literal, value, () => `Expected string ${JSON.stringify(literal)}, getting ${JSON.stringify(value)}.`), { const: literal }); | ||
return string.refined(value => refinement(value === literal, value, () => `Expected string ${JSON.stringify(literal)}, got ${JSON.stringify(value)}.`), { const: literal }); | ||
case 'number': | ||
return number.refined(value => refinement(value === literal, value, () => `Expected number ${literal}, getting ${value}.`), { const: literal }); | ||
return number.refined(value => refinement(value === literal, value, () => `Expected number ${literal}, got ${value}.`), { const: literal }); | ||
case 'boolean': | ||
return boolean.refined(value => refinement(value === literal, value, () => `Expected boolean ${literal}, getting ${value}.`), { const: literal }); | ||
return boolean.refined(value => refinement(value === literal, value, () => `Expected boolean ${literal}, got ${value}.`), { const: literal }); | ||
default: | ||
@@ -15,0 +15,0 @@ throw new TypeError('Unsupported literal value'); |
import { number } from '../types'; | ||
import { refinement } from '../utils'; | ||
export const Integer = number.refined(value => refinement(Number.isInteger(value), value, () => `Expected integer, getting ${value}.`), { type: 'integer' }); | ||
export const Integer = number.refined(value => refinement(Number.isInteger(value), value, () => `Expected integer, got ${value}.`), { type: 'integer' }); | ||
export function integerRange({ min = -Infinity, max = Infinity, }) { | ||
return Integer.refined(value => { | ||
if (value < min) { | ||
throw `Expected integer >= ${min}, getting ${value}.`; | ||
throw `Expected integer >= ${min}, got ${value}.`; | ||
} | ||
if (value > max) { | ||
throw `Expected integer <= ${max}, getting ${value}.`; | ||
throw `Expected integer <= ${max}, got ${value}.`; | ||
} | ||
@@ -21,12 +21,12 @@ return value; | ||
if (value < minInclusive) { | ||
throw `Expected number >= ${minInclusive}, getting ${value}.`; | ||
throw `Expected number >= ${minInclusive}, got ${value}.`; | ||
} | ||
if (value <= minExclusive) { | ||
throw `Expected number > ${minExclusive}, getting ${value}.`; | ||
throw `Expected number > ${minExclusive}, got ${value}.`; | ||
} | ||
if (value > maxInclusive) { | ||
throw `Expected number <= ${maxInclusive}, getting ${value}.`; | ||
throw `Expected number <= ${maxInclusive}, got ${value}.`; | ||
} | ||
if (value >= maxExclusive) { | ||
throw `Expected number < ${maxExclusive}, getting ${value}.`; | ||
throw `Expected number < ${maxExclusive}, got ${value}.`; | ||
} | ||
@@ -33,0 +33,0 @@ return value; |
@@ -9,3 +9,3 @@ "use strict"; | ||
exports.bufferTypeSymbol = Symbol(); | ||
exports.Buffer = x.atomic(exports.bufferTypeSymbol, value => x.constraint(value instanceof BufferClass, `Expected instance of Buffer, getting ${toString.call(value)}.`)); | ||
exports.Buffer = x.atomic(exports.bufferTypeSymbol, value => x.constraint(value instanceof BufferClass, `Expected instance of Buffer, got ${toString.call(value)}.`)); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "x-value", | ||
"version": "0.1.12", | ||
"version": "0.1.13", | ||
"repository": "https://github.com/vilic/x-value.git", | ||
@@ -11,12 +11,15 @@ "license": "MIT", | ||
"import": "./bld/library/esm/index.js", | ||
"require": "./bld/library/cjs/index.js" | ||
"require": "./bld/library/cjs/index.js", | ||
"default": "./bld/library/esm/index.js" | ||
}, | ||
"./node": { | ||
"types": "./bld/node/index.d.ts", | ||
"require": "./bld/node/index.js" | ||
"require": "./bld/node/index.js", | ||
"default": "./bld/node/index.js" | ||
} | ||
}, | ||
"scripts": { | ||
"3": "yarn && yarn-deduplicate && yarn", | ||
"build": "rimraf ./bld && tsc --build", | ||
"lint": "run-in-every eslint-project --parallel --echo -- eslint --config {configFileName} --no-error-on-unmatched-pattern .", | ||
"lint": "eslint --no-error-on-unmatched-pattern . && run-in-every eslint-project --parallel --echo -- eslint --no-error-on-unmatched-pattern .", | ||
"lint-prettier": "prettier --check .", | ||
@@ -28,19 +31,20 @@ "test": "yarn lint-prettier && yarn build && yarn lint && jest --coverage", | ||
"lodash.isequal": "^4.5.0", | ||
"tslib": "^2.5.0" | ||
"tslib": "^2.6.0" | ||
}, | ||
"devDependencies": { | ||
"@mufan/code": "^0.2.16", | ||
"@mufan/eslint-plugin": "^0.1.77", | ||
"@mufan/eslint-plugin": "^0.1.81", | ||
"@types/jest": "^29.4.0", | ||
"@types/lodash.isequal": "^4.5.6", | ||
"@types/node": "^18.13.0", | ||
"eslint": "^8.39.0", | ||
"eslint": "^8.43.0", | ||
"jest": "^29.4.2", | ||
"prettier": "^2.8.7", | ||
"rimraf": "^4.4.1", | ||
"prettier": "^2.8.8", | ||
"rimraf": "^5.0.1", | ||
"run-in-every": "^0.2.0", | ||
"ts-jest": "^29.0.5", | ||
"tslang": "^0.1.27", | ||
"typescript": "^5.0.4" | ||
"typescript": "^5.1.3", | ||
"yarn-deduplicate": "^6.0.2" | ||
} | ||
} |
@@ -37,2 +37,3 @@ [![NPM version](https://img.shields.io/npm/v/x-value?color=%23cb3837&style=flat-square)](https://www.npmjs.com/package/x-value) | ||
- [Transform from Medium to Medium](#transform-from-medium-to-medium) | ||
- [Sanitize Value](#sanitize-value) | ||
- [Type Guards](#type-guards) | ||
@@ -454,2 +455,13 @@ - [Type Diagnostics](#type-diagnostics) | ||
### Sanitize Value | ||
```ts | ||
const Data = x.object({ | ||
foo: x.string, | ||
bar: x.number, | ||
}); | ||
Data.sanitize({foo: 'abc', bar: 123, extra: true}); // {foo: 'abc', bar: 123} | ||
``` | ||
### Type Guards | ||
@@ -456,0 +468,0 @@ |
@@ -56,2 +56,2 @@ import type {TypeIssue, TypePath} from './@type-issue'; | ||
export type Exact = ExactContext | boolean; | ||
export type Exact = ExactContext | boolean | 'disabled'; |
import type {Exact} from './@exact-context'; | ||
import type {TypeIssue, TypePath} from './@type-issue'; | ||
import {hasNonDeferrableTypeIssue} from './@type-issue'; | ||
import type {Medium} from './medium'; | ||
import {DISABLED_EXACT_CONTEXT_RESULT, Type} from './type'; | ||
import type {JSONSchemaContext, JSONSchemaData} from './type-like'; | ||
import {Type} from './type'; | ||
import type { | ||
JSONSchemaContext, | ||
JSONSchemaData, | ||
TraverseCallback, | ||
} from './type-like'; | ||
import type {TypeInMediumsPartial, __type_in_mediums} from './type-partials'; | ||
@@ -23,9 +26,9 @@ import {__type_kind} from './type-partials'; | ||
/** @internal */ | ||
_decode( | ||
medium: Medium, | ||
unpacked: unknown, | ||
override _traverse( | ||
input: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
callback: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
if (!Array.isArray(unpacked)) { | ||
if (!Array.isArray(input)) { | ||
return [ | ||
@@ -36,5 +39,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call( | ||
unpacked, | ||
)}.`, | ||
message: `Expected an array, got ${toString.call(input)}.`, | ||
}, | ||
@@ -49,145 +50,23 @@ ], | ||
const value: unknown[] = []; | ||
const output: unknown[] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const [index, unpackedElement] of unpacked.entries()) { | ||
const [element, entryIssues] = ElementType._decode( | ||
medium, | ||
unpackedElement, | ||
for (const [index, value] of input.entries()) { | ||
const [element, entryIssues] = ElementType._traverse( | ||
value, | ||
[...path, index], | ||
nestedExact, | ||
callback, | ||
); | ||
value.push(element); | ||
output.push(element); | ||
issues.push(...entryIssues); | ||
} | ||
context?.addKeys(Array.from(unpacked.keys(), key => key.toString())); | ||
context?.addKeys(Array.from(input.keys(), key => key.toString())); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : output, issues]; | ||
} | ||
/** @internal */ | ||
_encode( | ||
medium: Medium, | ||
value: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
diagnose: boolean, | ||
): [unknown, TypeIssue[]] { | ||
if (diagnose && !Array.isArray(value)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be an array, getting ${toString.call( | ||
value, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementType = this.ElementType; | ||
const {context, nestedExact} = diagnose | ||
? this.getExactContext(exact, false) | ||
: DISABLED_EXACT_CONTEXT_RESULT; | ||
const unpacked: unknown[] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const [index, valueElement] of (value as unknown[]).entries()) { | ||
const [unpackedElement, entryIssues] = ElementType._encode( | ||
medium, | ||
valueElement, | ||
[...path, index], | ||
nestedExact, | ||
diagnose, | ||
); | ||
unpacked.push(unpackedElement); | ||
issues.push(...entryIssues); | ||
} | ||
context?.addKeys( | ||
Array.from((value as unknown[]).keys(), key => key.toString()), | ||
); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : unpacked, issues]; | ||
} | ||
/** @internal */ | ||
_transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
if (!Array.isArray(unpacked)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call( | ||
unpacked, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementType = this.ElementType; | ||
const {context, nestedExact} = this.getExactContext(exact, false); | ||
const value: unknown[] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const [index, unpackedElement] of unpacked.entries()) { | ||
const [element, entryIssues] = ElementType._transform( | ||
from, | ||
to, | ||
unpackedElement, | ||
[...path, index], | ||
nestedExact, | ||
); | ||
value.push(element); | ||
issues.push(...entryIssues); | ||
} | ||
context?.addKeys(Array.from(unpacked.keys(), key => key.toString())); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
} | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[] { | ||
if (!Array.isArray(value)) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting an array, getting ${toString.call(value)}.`, | ||
}, | ||
]; | ||
} | ||
const ElementType = this.ElementType; | ||
const {context, nestedExact} = this.getExactContext(exact, false); | ||
const issues = value.flatMap((element, index) => | ||
ElementType._diagnose(element, [...path, index], nestedExact), | ||
); | ||
context?.addKeys(Array.from(value.keys(), key => key.toString())); | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context: JSONSchemaContext, exact: boolean): JSONSchemaData { | ||
@@ -194,0 +73,0 @@ exact = this._exact ?? exact; |
@@ -29,3 +29,3 @@ import type {Exact} from './@exact-context'; | ||
/** @internal */ | ||
_decode( | ||
override _decode( | ||
medium: Medium, | ||
@@ -50,3 +50,3 @@ unpacked: unknown, | ||
/** @internal */ | ||
_encode( | ||
override _encode( | ||
medium: Medium, | ||
@@ -80,36 +80,14 @@ value: unknown, | ||
/** @internal */ | ||
_transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
const symbol = this.symbol; | ||
override _sanitize(value: unknown, path: TypePath): [unknown, TypeIssue[]] { | ||
const issues = this._diagnose(value, path, 'disabled'); | ||
let value: unknown; | ||
try { | ||
value = from.getCodec(symbol).decode(unpacked); | ||
} catch (error) { | ||
return [undefined, [buildIssueByError(error, path)]]; | ||
} | ||
const issues = this._diagnose(value, path, exact); | ||
if (hasNonDeferrableTypeIssue(issues)) { | ||
return [undefined, issues]; | ||
} | ||
try { | ||
return [to.getCodec(symbol).encode(value), issues]; | ||
} catch (error) { | ||
issues.push(buildIssueByError(error, path)); | ||
return [undefined, issues]; | ||
} | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
} | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, _exact: Exact): TypeIssue[] { | ||
override _diagnose( | ||
value: unknown, | ||
path: TypePath, | ||
_exact: Exact, | ||
): TypeIssue[] { | ||
const issues: TypeIssue[] = []; | ||
@@ -116,0 +94,0 @@ |
import type {Exact} from './@exact-context'; | ||
import type {TypeIssue, TypePath} from './@type-issue'; | ||
import { | ||
hasNonDeferrableTypeIssue, | ||
type TypeIssue, | ||
type TypePath, | ||
} from './@type-issue'; | ||
import type {Medium, UsingMediumName} from './medium'; | ||
@@ -42,3 +46,3 @@ import {Type, TypeConstraintError} from './type'; | ||
path: [], | ||
message: `Expecting at least ${ArgumentTypeTuple.length} argument(s), getting ${args.length}.`, | ||
message: `Expected at least ${ArgumentTypeTuple.length} argument(s), got ${args.length}.`, | ||
}, | ||
@@ -81,3 +85,3 @@ ]); | ||
path: [], | ||
message: `Expecting at least ${ArgumentTypeTuple.length} argument(s), getting ${args.length}.`, | ||
message: `Expected at least ${ArgumentTypeTuple.length} argument(s), got ${args.length}.`, | ||
}, | ||
@@ -138,77 +142,36 @@ ]); | ||
/** @internal */ | ||
_decode( | ||
override _decode( | ||
_medium: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
_exact: Exact, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
if (typeof unpacked !== 'function') { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a function, getting ${toString.call( | ||
unpacked, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
return [unpacked, []]; | ||
const issues = this._diagnose(unpacked, path, exact); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : unpacked, issues]; | ||
} | ||
/** @internal */ | ||
_encode( | ||
override _encode( | ||
_medium: Medium, | ||
value: unknown, | ||
path: TypePath, | ||
_exact: Exact, | ||
exact: Exact, | ||
diagnose: boolean, | ||
): [unknown, TypeIssue[]] { | ||
if (diagnose && typeof value !== 'function') { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be a function, getting ${toString.call( | ||
value, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const issues = diagnose ? this._diagnose(value, path, exact) : []; | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
} | ||
return [value, []]; | ||
/** @internal */ | ||
override _sanitize(value: unknown, path: TypePath): [unknown, TypeIssue[]] { | ||
const issues = this._diagnose(value, path, 'disabled'); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
} | ||
/** @internal */ | ||
_transform( | ||
_from: Medium, | ||
_to: Medium, | ||
unpacked: unknown, | ||
override _diagnose( | ||
value: unknown, | ||
path: TypePath, | ||
_exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
if (typeof unpacked !== 'function') { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a function, getting ${toString.call( | ||
unpacked, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
return [unpacked, []]; | ||
} | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, _exact: Exact): TypeIssue[] { | ||
): TypeIssue[] { | ||
if (typeof value !== 'function') { | ||
@@ -218,3 +181,3 @@ return [ | ||
path, | ||
message: `Expecting a function, getting ${toString.call(value)}.`, | ||
message: `Expected a function, got ${toString.call(value)}.`, | ||
}, | ||
@@ -221,0 +184,0 @@ ]; |
@@ -6,5 +6,8 @@ import type {Exact} from './@exact-context'; | ||
import type {JSONSchema} from './json-schema'; | ||
import type {Medium} from './medium'; | ||
import {DISABLED_EXACT_CONTEXT_RESULT, Type} from './type'; | ||
import type {JSONSchemaContext, JSONSchemaData} from './type-like'; | ||
import {Type} from './type'; | ||
import type { | ||
JSONSchemaContext, | ||
JSONSchemaData, | ||
TraverseCallback, | ||
} from './type-like'; | ||
import {__type_kind} from './type-partials'; | ||
@@ -27,3 +30,3 @@ import type {TypeInMediumsPartial} from './type-partials'; | ||
if (TypeTuple.length < 2) { | ||
throw new TypeError('Expecting at least 2 types for intersection type'); | ||
throw new TypeError('Expected at least 2 elements for intersection type'); | ||
} | ||
@@ -35,7 +38,7 @@ | ||
/** @internal */ | ||
_decode( | ||
medium: Medium, | ||
unpacked: unknown, | ||
override _traverse( | ||
input: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
callback: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
@@ -51,5 +54,5 @@ const {managedContext, wrappedExact} = this.getExactContext( | ||
for (const Type of this.TypeTuple) { | ||
const [partial, partialIssues] = Type._decode( | ||
medium, | ||
unpacked, | ||
const [partial, partialIssues] = callback( | ||
Type, | ||
input, | ||
path, | ||
@@ -64,3 +67,3 @@ wrappedExact, | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
issues.push(...managedContext.getUnknownKeyIssues(input, path)); | ||
} | ||
@@ -77,101 +80,2 @@ | ||
/** @internal */ | ||
_encode( | ||
medium: Medium, | ||
value: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
diagnose: boolean, | ||
): [unknown, TypeIssue[]] { | ||
const {managedContext, wrappedExact} = diagnose | ||
? this.getExactContext(exact, 'managed') | ||
: DISABLED_EXACT_CONTEXT_RESULT; | ||
const partials: unknown[] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const Type of this.TypeTuple) { | ||
const [partial, partialIssues] = Type._encode( | ||
medium, | ||
value, | ||
path, | ||
wrappedExact, | ||
diagnose, | ||
); | ||
partials.push(partial); | ||
issues.push(...partialIssues); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: internal_mergeIntersectionPartials(partials), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
const {managedContext, wrappedExact} = this.getExactContext( | ||
exact, | ||
'managed', | ||
); | ||
const partials: unknown[] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const Type of this.TypeTuple) { | ||
const [partial, partialIssues] = Type._transform( | ||
from, | ||
to, | ||
unpacked, | ||
path, | ||
wrappedExact, | ||
); | ||
partials.push(partial); | ||
issues.push(...partialIssues); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: internal_mergeIntersectionPartials(partials), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[] { | ||
const {managedContext, wrappedExact} = this.getExactContext( | ||
exact, | ||
'managed', | ||
); | ||
const issues = this.TypeTuple.flatMap(Type => | ||
Type._diagnose(value, path, wrappedExact), | ||
); | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context: JSONSchemaContext, exact: boolean): JSONSchemaData { | ||
@@ -178,0 +82,0 @@ exact = this._exact ?? exact; |
@@ -5,7 +5,11 @@ import type {Exact} from './@exact-context'; | ||
import type {JSONSchema} from './json-schema'; | ||
import type {Medium} from './medium'; | ||
import {OptionalType} from './optional-type'; | ||
import {Type} from './type'; | ||
import type {JSONSchemaContext, JSONSchemaData, TypeLike} from './type-like'; | ||
import type { | ||
JSONSchemaContext, | ||
JSONSchemaData, | ||
TraverseCallback, | ||
TypeLike, | ||
} from './type-like'; | ||
import type { | ||
TypeInMediumsPartial, | ||
@@ -82,9 +86,9 @@ TypeKindPartial, | ||
/** @internal */ | ||
_decode( | ||
medium: Medium, | ||
unpacked: unknown, | ||
override _traverse( | ||
input: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
callback: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
if (typeof input !== 'object' || input === null) { | ||
return [ | ||
@@ -95,5 +99,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call( | ||
unpacked, | ||
)}.`, | ||
message: `Expected a non-null object, got ${toString.call(input)}.`, | ||
}, | ||
@@ -113,5 +115,5 @@ ], | ||
for (const [key, Type] of Object.entries(this.definition)) { | ||
const [value, entryIssues] = Type._decode( | ||
medium, | ||
(unpacked as any)[key], | ||
const [value, entryIssues] = callback( | ||
Type, | ||
(input as any)[key], | ||
[...path, key], | ||
@@ -125,3 +127,3 @@ nestedExact, | ||
if (wrappedExact) { | ||
if (typeof wrappedExact === 'object') { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
@@ -131,3 +133,3 @@ } | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
issues.push(...managedContext.getUnknownKeyIssues(input, path)); | ||
} | ||
@@ -144,161 +146,2 @@ | ||
/** @internal */ | ||
_encode( | ||
medium: Medium, | ||
value: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
diagnose: boolean, | ||
): [unknown, TypeIssue[]] { | ||
if (diagnose && (typeof value !== 'object' || value === null)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be a non-null object, getting ${toString.call( | ||
value, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const {managedContext, wrappedExact, nestedExact} = diagnose | ||
? this.getExactContext(exact, 'managed') | ||
: { | ||
managedContext: undefined, | ||
wrappedExact: false as false, | ||
nestedExact: false, | ||
}; | ||
const entries: [string, unknown][] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const [key, Type] of Object.entries(this.definition)) { | ||
const [unpacked, entryIssues] = Type._encode( | ||
medium, | ||
(value as any)[key], | ||
[...path, key], | ||
nestedExact, | ||
diagnose, | ||
); | ||
entries.push([key, unpacked]); | ||
issues.push(...entryIssues); | ||
} | ||
if (wrappedExact) { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: Object.fromEntries(entries), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call( | ||
unpacked, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const {managedContext, wrappedExact, nestedExact} = this.getExactContext( | ||
exact, | ||
'managed', | ||
); | ||
const entries: [string, unknown][] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const [key, Type] of Object.entries(this.definition)) { | ||
const [transformedUnpacked, entryIssues] = Type._transform( | ||
from, | ||
to, | ||
(unpacked as any)[key], | ||
[...path, key], | ||
nestedExact, | ||
); | ||
entries.push([key, transformedUnpacked]); | ||
issues.push(...entryIssues); | ||
} | ||
if (wrappedExact) { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(unpacked, path)); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: Object.fromEntries(entries), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[] { | ||
if (typeof value !== 'object' || value === null) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting a non-null object, getting ${toString.call( | ||
value, | ||
)}.`, | ||
}, | ||
]; | ||
} | ||
const {managedContext, wrappedExact, nestedExact} = this.getExactContext( | ||
exact, | ||
'managed', | ||
); | ||
const issues: TypeIssue[] = []; | ||
const entries = Object.entries(this.definition); | ||
for (const [key, Type] of entries) { | ||
issues.push( | ||
...Type._diagnose((value as any)[key], [...path, key], nestedExact), | ||
); | ||
} | ||
if (wrappedExact) { | ||
wrappedExact.addKeys(entries.map(([key]) => key)); | ||
} | ||
if (managedContext) { | ||
issues.push(...managedContext.getUnknownKeyIssues(value, path)); | ||
} | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context: JSONSchemaContext, exact: boolean): JSONSchemaData { | ||
@@ -305,0 +148,0 @@ exact = this._exact ?? exact; |
import type {Exact} from './@exact-context'; | ||
import type {TypeIssue, TypePath} from './@type-issue'; | ||
import type {Medium} from './medium'; | ||
import {Type} from './type'; | ||
import type {JSONSchemaContext, JSONSchemaData} from './type-like'; | ||
import type { | ||
JSONSchemaContext, | ||
JSONSchemaData, | ||
TraverseCallback, | ||
} from './type-like'; | ||
import {TypeLike} from './type-like'; | ||
@@ -21,45 +24,14 @@ import type {TypeInMediumsPartial, __type_in_mediums} from './type-partials'; | ||
/** @internal */ | ||
_decode( | ||
medium: Medium, | ||
unpacked: unknown, | ||
override _traverse( | ||
input: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
callback: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
return unpacked === undefined | ||
return input === undefined | ||
? [undefined, []] | ||
: this.Type._decode(medium, unpacked, path, exact); | ||
: callback(this.Type, input, path, exact); | ||
} | ||
/** @internal */ | ||
_encode( | ||
medium: Medium, | ||
value: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
diagnose: boolean, | ||
): [unknown, TypeIssue[]] { | ||
return value === undefined | ||
? [undefined, []] | ||
: this.Type._encode(medium, value, path, exact, diagnose); | ||
} | ||
/** @internal */ | ||
_transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
return unpacked === undefined | ||
? [undefined, []] | ||
: this.Type._transform(from, to, unpacked, path, exact); | ||
} | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[] { | ||
return value === undefined ? [] : this.Type._diagnose(value, path, exact); | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context: JSONSchemaContext, exact: boolean): JSONSchemaData { | ||
@@ -66,0 +38,0 @@ const {schema} = this.Type._toJSONSchema(context, exact); |
import type {Exact} from './@exact-context'; | ||
import type {TypeIssue, TypePath} from './@type-issue'; | ||
import {hasNonDeferrableTypeIssue} from './@type-issue'; | ||
import type {Medium} from './medium'; | ||
import {DISABLED_EXACT_CONTEXT_RESULT, Type} from './type'; | ||
import type {JSONSchemaContext, JSONSchemaData} from './type-like'; | ||
import {Type} from './type'; | ||
import type { | ||
JSONSchemaContext, | ||
JSONSchemaData, | ||
TraverseCallback, | ||
} from './type-like'; | ||
import type {TypeInMediumsPartial, __type_in_mediums} from './type-partials'; | ||
@@ -24,9 +27,9 @@ import {__type_kind} from './type-partials'; | ||
/** @internal */ | ||
_decode( | ||
medium: Medium, | ||
unpacked: unknown, | ||
override _traverse( | ||
input: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
callback: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
if (typeof input !== 'object' || input === null) { | ||
return [ | ||
@@ -37,5 +40,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call( | ||
unpacked, | ||
)}.`, | ||
message: `Expected a non-null object, got ${toString.call(input)}.`, | ||
}, | ||
@@ -54,138 +55,24 @@ ], | ||
const entries: [string | number, unknown][] = []; | ||
const issues: TypeIssue[] = []; | ||
const aggregatedIssues: TypeIssue[] = []; | ||
for (const [key, unpackedValue] of getRecordEntries(unpacked)) { | ||
const [value, valueIssues] = Value._decode( | ||
medium, | ||
unpackedValue, | ||
[...path, key], | ||
nestedExact, | ||
); | ||
for (const [key, value] of getRecordEntries(input)) { | ||
const keyIssues = Key._diagnose(key, [...path, {key}], nestedExact); | ||
entries.push([key, value]); | ||
issues.push( | ||
...Key._diagnose(key, [...path, {key}], nestedExact), | ||
...valueIssues, | ||
); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: buildRecord(entries, unpacked), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_encode( | ||
medium: Medium, | ||
value: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
diagnose: boolean, | ||
): [unknown, TypeIssue[]] { | ||
if (diagnose && (typeof value !== 'object' || value === null)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be a non-null object, getting ${toString.call( | ||
value, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const Key = this.Key; | ||
const Value = this.Value; | ||
const {context, nestedExact} = diagnose | ||
? this.getExactContext(exact, false) | ||
: DISABLED_EXACT_CONTEXT_RESULT; | ||
context?.neutralize(); | ||
const entries: [string | number, unknown][] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const [key, nestedValue] of getRecordEntries(value as object)) { | ||
const [unpacked, valueIssues] = Value._encode( | ||
medium, | ||
nestedValue, | ||
const [output, valueIssues] = Value._traverse( | ||
value, | ||
[...path, key], | ||
nestedExact, | ||
diagnose, | ||
callback, | ||
); | ||
entries.push([key, unpacked]); | ||
issues.push( | ||
...Key._diagnose(key, [...path, {key}], nestedExact), | ||
...valueIssues, | ||
); | ||
} | ||
entries.push([key, output]); | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
? undefined | ||
: buildRecord(entries, value as object), | ||
issues, | ||
]; | ||
} | ||
/** @internal */ | ||
_transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
if (typeof unpacked !== 'object' || unpacked === null) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be a non-null object, getting ${toString.call( | ||
unpacked, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
aggregatedIssues.push(...keyIssues, ...valueIssues); | ||
} | ||
const Key = this.Key; | ||
const Value = this.Value; | ||
const {context, nestedExact} = this.getExactContext(exact, false); | ||
context?.neutralize(); | ||
const entries: [string | number, unknown][] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const [key, unpackedValue] of getRecordEntries(unpacked)) { | ||
const [transformedUnpacked, valueIssues] = Value._transform( | ||
from, | ||
to, | ||
unpackedValue, | ||
[...path, key], | ||
nestedExact, | ||
); | ||
entries.push([key, transformedUnpacked]); | ||
issues.push( | ||
...Key._diagnose(key, [...path, {key}], nestedExact), | ||
...valueIssues, | ||
); | ||
} | ||
return [ | ||
hasNonDeferrableTypeIssue(issues) | ||
hasNonDeferrableTypeIssue(aggregatedIssues) | ||
? undefined | ||
: buildRecord(entries, unpacked), | ||
issues, | ||
: buildRecord(entries, input), | ||
aggregatedIssues, | ||
]; | ||
@@ -195,28 +82,2 @@ } | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[] { | ||
if (typeof value !== 'object' || value === null) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting a non-null object, getting ${toString.call( | ||
value, | ||
)}.`, | ||
}, | ||
]; | ||
} | ||
const Key = this.Key; | ||
const Value = this.Value; | ||
const {context, nestedExact} = this.getExactContext(exact, false); | ||
context?.neutralize(); | ||
return getRecordEntries(value).flatMap(([key, nestedValue]) => [ | ||
...Key._diagnose(key, [...path, {key}], nestedExact), | ||
...Value._diagnose(nestedValue, [...path, key], nestedExact), | ||
]); | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context: JSONSchemaContext, exact: boolean): JSONSchemaData { | ||
@@ -223,0 +84,0 @@ exact = this._exact ?? exact; |
import type {Exact} from './@exact-context'; | ||
import type {TypeIssue, TypePath} from './@type-issue'; | ||
import type {Medium} from './medium'; | ||
import {Type} from './type'; | ||
import type {JSONSchemaContext, JSONSchemaData} from './type-like'; | ||
import type { | ||
JSONSchemaContext, | ||
JSONSchemaData, | ||
TraverseCallback, | ||
} from './type-like'; | ||
import {__type_kind} from './type-partials'; | ||
@@ -22,39 +25,12 @@ import type {TypeInMediumsPartial, __type_in_mediums} from './type-partials'; | ||
/** @internal */ | ||
_decode( | ||
medium: Medium, | ||
unpacked: unknown, | ||
override _traverse( | ||
input: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
callback: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
return this.Type._decode(medium, unpacked, path, exact); | ||
return callback(this.Type, input, path, exact); | ||
} | ||
/** @internal */ | ||
_encode( | ||
medium: Medium, | ||
value: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
diagnose: boolean, | ||
): [unknown, TypeIssue[]] { | ||
return this.Type._encode(medium, value, path, exact, diagnose); | ||
} | ||
/** @internal */ | ||
_transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
return this.Type._transform(from, to, unpacked, path, exact); | ||
} | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[] { | ||
return this.Type._diagnose(value, path, exact); | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context: JSONSchemaContext, exact: boolean): JSONSchemaData { | ||
@@ -61,0 +37,0 @@ exact = this._exact ?? exact; |
@@ -33,3 +33,3 @@ import type {Exact} from './@exact-context'; | ||
/** @internal */ | ||
_decode( | ||
override _decode( | ||
medium: Medium, | ||
@@ -59,3 +59,3 @@ unpacked: unknown, | ||
/** @internal */ | ||
_encode( | ||
override _encode( | ||
medium: Medium, | ||
@@ -90,3 +90,3 @@ value: unknown, | ||
path, | ||
message: 'Expecting encoding value to be stable after refinements.', | ||
message: 'Expected encoding value to be stable after refinements.', | ||
}); | ||
@@ -104,10 +104,4 @@ } | ||
/** @internal */ | ||
_transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
const [value, issues] = this._decode(from, unpacked, path, exact); | ||
override _sanitize(value: unknown, path: TypePath): [unknown, TypeIssue[]] { | ||
const [sanitized, issues] = this.Type._sanitize(value, path); | ||
@@ -118,9 +112,22 @@ if (hasNonDeferrableTypeIssue(issues)) { | ||
const [transformedUnpacked] = this._encode(to, value, path, false, false); | ||
const [refined, refinementIssues] = this.processRefinements( | ||
sanitized, | ||
path, | ||
); | ||
return [transformedUnpacked, issues]; | ||
issues.push(...refinementIssues); | ||
if (hasNonDeferrableTypeIssue(refinementIssues)) { | ||
return [undefined, issues]; | ||
} | ||
return [refined, issues]; | ||
} | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[] { | ||
override _diagnose( | ||
value: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): TypeIssue[] { | ||
const issues = this.Type._diagnose(value, path, exact); | ||
@@ -127,0 +134,0 @@ |
@@ -5,5 +5,8 @@ import type {Exact} from './@exact-context'; | ||
import type {TupleInMedium} from './@utils'; | ||
import type {Medium} from './medium'; | ||
import {DISABLED_EXACT_CONTEXT_RESULT, Type} from './type'; | ||
import type {JSONSchemaContext, JSONSchemaData} from './type-like'; | ||
import {Type} from './type'; | ||
import type { | ||
JSONSchemaContext, | ||
JSONSchemaData, | ||
TraverseCallback, | ||
} from './type-like'; | ||
import {__type_kind} from './type-partials'; | ||
@@ -25,9 +28,9 @@ import type {TypeInMediumsPartial} from './type-partials'; | ||
/** @internal */ | ||
_decode( | ||
medium: Medium, | ||
unpacked: unknown, | ||
override _traverse( | ||
input: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
callback: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
if (!Array.isArray(unpacked)) { | ||
if (!Array.isArray(input)) { | ||
return [ | ||
@@ -38,5 +41,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call( | ||
unpacked, | ||
)}.`, | ||
message: `Expected an array, got ${toString.call(input)}.`, | ||
}, | ||
@@ -49,3 +50,3 @@ ], | ||
if (unpacked.length !== ElementTypeTuple.length) { | ||
if (input.length !== ElementTypeTuple.length) { | ||
return [ | ||
@@ -56,3 +57,3 @@ undefined, | ||
path, | ||
message: `Expecting unpacked value with ${ElementTypeTuple.length} instead of ${unpacked.length} element(s).`, | ||
message: `Expected value with ${ElementTypeTuple.length} instead of ${input.length} element(s).`, | ||
}, | ||
@@ -69,5 +70,5 @@ ], | ||
for (const [index, Element] of ElementTypeTuple.entries()) { | ||
const [element, entryIssues] = Element._decode( | ||
medium, | ||
unpacked[index], | ||
const [element, entryIssues] = callback( | ||
Element, | ||
input[index], | ||
[...path, index], | ||
@@ -89,163 +90,2 @@ nestedExact, | ||
/** @internal */ | ||
_encode( | ||
medium: Medium, | ||
value: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
diagnose: boolean, | ||
): [unknown, TypeIssue[]] { | ||
if (diagnose && !Array.isArray(value)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value to be an array, getting ${toString.call( | ||
value, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if ((value as unknown[]).length !== ElementTypeTuple.length) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting value with ${ | ||
ElementTypeTuple.length | ||
} instead of ${(value as unknown[]).length} element(s).`, | ||
}, | ||
], | ||
]; | ||
} | ||
const {context, nestedExact} = diagnose | ||
? this.getExactContext(exact, false) | ||
: DISABLED_EXACT_CONTEXT_RESULT; | ||
const unpacked: unknown[] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const [index, Element] of ElementTypeTuple.entries()) { | ||
const [unpackedElement, entryIssues] = Element._encode( | ||
medium, | ||
(value as unknown[])[index], | ||
[...path, index], | ||
nestedExact, | ||
diagnose, | ||
); | ||
unpacked.push(unpackedElement); | ||
issues.push(...entryIssues); | ||
} | ||
context?.addKeys( | ||
Array.from(ElementTypeTuple.keys(), key => key.toString()), | ||
); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : unpacked, issues]; | ||
} | ||
/** @internal */ | ||
_transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
if (!Array.isArray(unpacked)) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value to be an array, getting ${toString.call( | ||
unpacked, | ||
)}.`, | ||
}, | ||
], | ||
]; | ||
} | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if (unpacked.length !== ElementTypeTuple.length) { | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: `Expecting unpacked value with ${ElementTypeTuple.length} instead of ${unpacked.length} element(s).`, | ||
}, | ||
], | ||
]; | ||
} | ||
const {context, nestedExact} = this.getExactContext(exact, false); | ||
const value: unknown[] = []; | ||
const issues: TypeIssue[] = []; | ||
for (const [index, Element] of ElementTypeTuple.entries()) { | ||
const [element, entryIssues] = Element._transform( | ||
from, | ||
to, | ||
unpacked[index], | ||
[...path, index], | ||
nestedExact, | ||
); | ||
value.push(element); | ||
issues.push(...entryIssues); | ||
} | ||
context?.addKeys( | ||
Array.from(ElementTypeTuple.keys(), key => key.toString()), | ||
); | ||
return [hasNonDeferrableTypeIssue(issues) ? undefined : value, issues]; | ||
} | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[] { | ||
if (!Array.isArray(value)) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting an array, getting ${toString.call(value)}.`, | ||
}, | ||
]; | ||
} | ||
const ElementTypeTuple = this.ElementTypeTuple; | ||
if ((value as unknown[]).length !== ElementTypeTuple.length) { | ||
return [ | ||
{ | ||
path, | ||
message: `Expecting value with ${ElementTypeTuple.length} instead of ${value.length} element(s).`, | ||
}, | ||
]; | ||
} | ||
const {context, nestedExact} = this.getExactContext(exact, false); | ||
const issues = ElementTypeTuple.flatMap((Element, index) => | ||
Element._diagnose(value[index], [...path, index], nestedExact), | ||
); | ||
context?.addKeys( | ||
Array.from(ElementTypeTuple.keys(), key => key.toString()), | ||
); | ||
return issues; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context: JSONSchemaContext, exact: boolean): JSONSchemaData { | ||
@@ -252,0 +92,0 @@ exact = this._exact ?? exact; |
@@ -16,3 +16,13 @@ import type {Exact} from './@exact-context'; | ||
/** @internal */ | ||
abstract _decode( | ||
_traverse( | ||
input: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
callback: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
return callback(this, input, path, exact); | ||
} | ||
/** @internal */ | ||
_decode( | ||
medium: Medium, | ||
@@ -22,6 +32,11 @@ unpacked: unknown, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]]; | ||
callback?: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
return this._traverse(unpacked, path, exact, (Type, value, path, exact) => | ||
Type._decode(medium, value, path, exact, callback), | ||
); | ||
} | ||
/** @internal */ | ||
abstract _encode( | ||
_encode( | ||
medium: Medium, | ||
@@ -32,16 +47,31 @@ value: unknown, | ||
diagnose: boolean, | ||
): [unknown, TypeIssue[]]; | ||
callback?: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
return this._traverse(value, path, exact, (Type, value, path, exact) => | ||
Type._encode(medium, value, path, exact, diagnose, callback), | ||
); | ||
} | ||
/** @internal */ | ||
abstract _transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]]; | ||
_sanitize(value: unknown, path: TypePath): [unknown, TypeIssue[]] { | ||
return this._traverse(value, path, 'disabled', (Type, value, path) => | ||
Type._sanitize(value, path), | ||
); | ||
} | ||
/** @internal */ | ||
abstract _diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[]; | ||
_diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[] { | ||
const [, issues] = this._traverse( | ||
value, | ||
path, | ||
exact, | ||
(Type, value, path, exact) => [ | ||
undefined, | ||
Type._diagnose(value, path, exact), | ||
], | ||
); | ||
return issues; | ||
} | ||
/** @internal */ | ||
@@ -121,2 +151,9 @@ abstract _toJSONSchema( | ||
export type TraverseCallback = ( | ||
Type: TypeLike, | ||
value: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
) => [unknown, TypeIssue[]]; | ||
export interface JSONSchemaData { | ||
@@ -123,0 +160,0 @@ schema: JSONSchema; |
@@ -6,2 +6,3 @@ import type {Exact} from './@exact-context'; | ||
import type {Medium, MediumPackedType} from './medium'; | ||
import type {TraverseCallback} from './type-like'; | ||
import {JSONSchemaContext, TypeLike} from './type-like'; | ||
@@ -40,2 +41,3 @@ import type { | ||
const unpacked = medium.unpack(packed); | ||
const [value, issues] = this._decode( | ||
@@ -85,8 +87,18 @@ medium, | ||
const unpacked = from.unpack(packed); | ||
const [transformedUnpacked, issues] = this._transform( | ||
from, | ||
to, | ||
const callback: TraverseCallback = (Type, value, path, exact) => { | ||
const [decoded, issues] = Type._decode(from, value, path, exact); | ||
if (issues.length > 0) { | ||
return [undefined, issues]; | ||
} | ||
return Type._encode(to, decoded, path, exact, false); | ||
}; | ||
const [transformedUnpacked, issues] = this._traverse( | ||
unpacked, | ||
[], | ||
this._exact ?? false, | ||
callback, | ||
); | ||
@@ -101,2 +113,16 @@ | ||
sanitize(value: unknown): TInMediums['value'] { | ||
const [sanitized, issues] = this._sanitize(value, []); | ||
if (issues.length > 0) { | ||
throw new TypeConstraintError('Value does not satisfy the type', issues); | ||
} | ||
return sanitized; | ||
} | ||
diagnose(value: unknown): TypeIssue[] { | ||
return this._diagnose(value, [], this._exact ?? false); | ||
} | ||
satisfies(value: unknown): TInMediums['value'] { | ||
@@ -120,6 +146,2 @@ const issues = this.diagnose(value); | ||
diagnose(value: unknown): TypeIssue[] { | ||
return this._diagnose(value, [], this._exact ?? false); | ||
} | ||
toJSONSchema(): JSONSchema { | ||
@@ -143,3 +165,3 @@ const context = new JSONSchemaContext(); | ||
managedContext: ExactContext | undefined; | ||
wrappedExact: ExactContext | false; | ||
wrappedExact: ExactContext | false | 'disabled'; | ||
nestedExact: Exact; | ||
@@ -174,2 +196,11 @@ }; | ||
} { | ||
if (exact === 'disabled') { | ||
return { | ||
context: undefined, | ||
managedContext: undefined, | ||
wrappedExact: 'disabled', | ||
nestedExact: 'disabled', | ||
}; | ||
} | ||
const context = typeof exact === 'boolean' ? undefined : exact; | ||
@@ -176,0 +207,0 @@ |
@@ -6,5 +6,8 @@ import type {Exact} from './@exact-context'; | ||
import type {TupleInMedium} from './@utils'; | ||
import type {Medium} from './medium'; | ||
import {DISABLED_EXACT_CONTEXT_RESULT, Type} from './type'; | ||
import type {JSONSchemaContext, JSONSchemaData} from './type-like'; | ||
import {Type} from './type'; | ||
import type { | ||
JSONSchemaContext, | ||
JSONSchemaData, | ||
TraverseCallback, | ||
} from './type-like'; | ||
import {__type_kind} from './type-partials'; | ||
@@ -25,3 +28,3 @@ import type {TypeInMediumsPartial} from './type-partials'; | ||
if (TypeTuple.length < 2) { | ||
throw new TypeError('Expecting at least 2 type for union type'); | ||
throw new TypeError('Expected at least 2 elements for union type'); | ||
} | ||
@@ -33,7 +36,7 @@ | ||
/** @internal */ | ||
_decode( | ||
medium: Medium, | ||
unpacked: unknown, | ||
override _traverse( | ||
input: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
callback: TraverseCallback, | ||
): [unknown, TypeIssue[]] { | ||
@@ -47,10 +50,5 @@ const {wrappedExact} = this.getExactContext(exact, 'transparent'); | ||
const dedicatedExact = | ||
typeof wrappedExact === 'boolean' ? wrappedExact : new ExactContext(); | ||
typeof wrappedExact === 'object' ? new ExactContext() : wrappedExact; | ||
const [value, issues] = Type._decode( | ||
medium, | ||
unpacked, | ||
path, | ||
dedicatedExact, | ||
); | ||
const [value, issues] = callback(Type, input, path, dedicatedExact); | ||
@@ -78,4 +76,3 @@ if (hasNonDeferrableTypeIssue(issues)) { | ||
path, | ||
message: | ||
'The unpacked value satisfies none of the type in the union type.', | ||
message: 'Value satisfies none of the type in the union type.', | ||
}, | ||
@@ -88,151 +85,2 @@ ...outputIssues, | ||
/** @internal */ | ||
_encode( | ||
medium: Medium, | ||
value: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
diagnose: boolean, | ||
): [unknown, TypeIssue[]] { | ||
const {wrappedExact} = diagnose | ||
? this.getExactContext(exact, 'transparent') | ||
: DISABLED_EXACT_CONTEXT_RESULT; | ||
let maxIssuePathLength = -1; | ||
let outputIssues!: TypeIssue[]; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = | ||
typeof wrappedExact === 'boolean' ? wrappedExact : new ExactContext(); | ||
const [unpacked, issues] = Type._encode( | ||
medium, | ||
value, | ||
path, | ||
dedicatedExact, | ||
diagnose, | ||
); | ||
if (hasNonDeferrableTypeIssue(issues)) { | ||
const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
if (pathLength > maxIssuePathLength) { | ||
maxIssuePathLength = pathLength; | ||
outputIssues = issues; | ||
} | ||
continue; | ||
} | ||
syncDedicatedExact(wrappedExact, dedicatedExact); | ||
return [unpacked, issues]; | ||
} | ||
// If diagnose is `false`, it will never reach here. | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: 'The value satisfies none of the type in the union type.', | ||
}, | ||
...outputIssues, | ||
], | ||
]; | ||
} | ||
/** @internal */ | ||
_transform( | ||
from: Medium, | ||
to: Medium, | ||
unpacked: unknown, | ||
path: TypePath, | ||
exact: Exact, | ||
): [unknown, TypeIssue[]] { | ||
const {wrappedExact} = this.getExactContext(exact, 'transparent'); | ||
let maxIssuePathLength = -1; | ||
let outputIssues!: TypeIssue[]; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = | ||
typeof wrappedExact === 'boolean' ? wrappedExact : new ExactContext(); | ||
const [transformedUnpacked, issues] = Type._transform( | ||
from, | ||
to, | ||
unpacked, | ||
path, | ||
dedicatedExact, | ||
); | ||
if (hasNonDeferrableTypeIssue(issues)) { | ||
const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
if (pathLength > maxIssuePathLength) { | ||
maxIssuePathLength = pathLength; | ||
outputIssues = issues; | ||
} | ||
continue; | ||
} | ||
syncDedicatedExact(wrappedExact, dedicatedExact); | ||
return [transformedUnpacked, issues]; | ||
} | ||
return [ | ||
undefined, | ||
[ | ||
{ | ||
path, | ||
message: | ||
'The unpacked value satisfies none of the type in the union type.', | ||
}, | ||
...outputIssues, | ||
], | ||
]; | ||
} | ||
/** @internal */ | ||
_diagnose(value: unknown, path: TypePath, exact: Exact): TypeIssue[] { | ||
const {wrappedExact} = this.getExactContext(exact, 'transparent'); | ||
let maxIssuePathLength = -1; | ||
let outputIssues!: TypeIssue[]; | ||
for (const Type of this.TypeTuple) { | ||
const dedicatedExact = | ||
typeof wrappedExact === 'boolean' ? wrappedExact : new ExactContext(); | ||
const issues = Type._diagnose(value, path, dedicatedExact); | ||
if (hasNonDeferrableTypeIssue(issues)) { | ||
const pathLength = Math.max(...issues.map(issue => issue.path.length)); | ||
if (pathLength > maxIssuePathLength) { | ||
maxIssuePathLength = pathLength; | ||
outputIssues = issues; | ||
} | ||
continue; | ||
} | ||
syncDedicatedExact(wrappedExact, dedicatedExact); | ||
return issues; | ||
} | ||
return [ | ||
{ | ||
path, | ||
message: 'The value satisfies none of the type in the union type.', | ||
}, | ||
...outputIssues, | ||
]; | ||
} | ||
/** @internal */ | ||
_toJSONSchema(context: JSONSchemaContext, exact: boolean): JSONSchemaData { | ||
@@ -268,6 +116,3 @@ exact = this._exact ?? exact; | ||
function syncDedicatedExact(wrappedExact: Exact, dedicatedExact: Exact): void { | ||
if ( | ||
typeof wrappedExact !== 'boolean' && | ||
typeof dedicatedExact !== 'boolean' | ||
) { | ||
if (typeof wrappedExact === 'object' && typeof dedicatedExact === 'object') { | ||
if (dedicatedExact.touched) { | ||
@@ -274,0 +119,0 @@ wrappedExact.addKeys(dedicatedExact.keys); |
@@ -22,3 +22,3 @@ import type {MediumAtomicCodecs} from '../core'; | ||
throw new TypeError( | ||
`Expected bigint string, getting ${toString.call(value)}`, | ||
`Expected bigint string, got ${toString.call(value)}`, | ||
); | ||
@@ -37,3 +37,3 @@ } | ||
throw new TypeError( | ||
`Expected ISO date string, getting ${toString.call(value)}`, | ||
`Expected ISO date string, got ${toString.call(value)}`, | ||
); | ||
@@ -58,5 +58,3 @@ } | ||
throw new TypeError( | ||
`Expected regular expression literal, getting ${toString.call( | ||
value, | ||
)}`, | ||
`Expected regular expression literal, got ${toString.call(value)}`, | ||
); | ||
@@ -63,0 +61,0 @@ } |
@@ -77,5 +77,3 @@ import {atomicTypeSymbol, medium} from '../core'; | ||
if (typeof dict !== 'object' || dict === null) { | ||
throw new TypeError( | ||
`Expected non-null object, getting ${toString.call(dict)}`, | ||
); | ||
throw new TypeError(`Expected non-null object, got ${toString.call(dict)}`); | ||
} | ||
@@ -82,0 +80,0 @@ |
@@ -33,3 +33,3 @@ import {atomic} from './core'; | ||
export const never = atomic(neverTypeSymbol, value => { | ||
throw `Expected never, getting ${toString.call(value)}.`; | ||
throw `Expected never, got ${toString.call(value)}.`; | ||
}); | ||
@@ -44,3 +44,3 @@ | ||
value === void 0, | ||
() => `Expected undefined, getting ${toString.call(value)}.`, | ||
() => `Expected undefined, got ${toString.call(value)}.`, | ||
), | ||
@@ -53,3 +53,3 @@ ); | ||
value === void 0, | ||
() => `Expected undefined, getting ${toString.call(value)}.`, | ||
() => `Expected undefined, got ${toString.call(value)}.`, | ||
), | ||
@@ -66,3 +66,3 @@ ); | ||
value === null, | ||
() => `Expected null, getting ${toString.call(value)}.`, | ||
() => `Expected null, got ${toString.call(value)}.`, | ||
), | ||
@@ -78,3 +78,3 @@ {type: 'null'}, | ||
typeof value === 'string', | ||
() => `Expected string, getting ${toString.call(value)}.`, | ||
() => `Expected string, got ${toString.call(value)}.`, | ||
), | ||
@@ -90,3 +90,3 @@ {type: 'string'}, | ||
typeof value === 'number', | ||
() => `Expected number, getting ${toString.call(value)}.`, | ||
() => `Expected number, got ${toString.call(value)}.`, | ||
), | ||
@@ -102,3 +102,3 @@ {type: 'number'}, | ||
typeof value === 'bigint', | ||
() => `Expected bigint, getting ${toString.call(value)}.`, | ||
() => `Expected bigint, got ${toString.call(value)}.`, | ||
), | ||
@@ -114,3 +114,3 @@ {type: 'integer'}, | ||
typeof value === 'boolean', | ||
() => `Expected boolean, getting ${toString.call(value)}.`, | ||
() => `Expected boolean, got ${toString.call(value)}.`, | ||
), | ||
@@ -124,3 +124,3 @@ {type: 'boolean'}, | ||
typeof value === 'function', | ||
() => `Expected function, getting ${toString.call(value)}.`, | ||
() => `Expected function, got ${toString.call(value)}.`, | ||
), | ||
@@ -133,3 +133,3 @@ ); | ||
value instanceof globalThis.Date, | ||
() => `Expected instance of Date, getting ${toString.call(value)}.`, | ||
() => `Expected instance of Date, got ${toString.call(value)}.`, | ||
), | ||
@@ -142,4 +142,4 @@ ); | ||
value instanceof globalThis.RegExp, | ||
() => `Expected instance of RegExp, getting ${toString.call(value)}.`, | ||
() => `Expected instance of RegExp, got ${toString.call(value)}.`, | ||
), | ||
); |
@@ -38,5 +38,5 @@ import isEqual from 'lodash.isequal'; | ||
() => | ||
`Expected string ${JSON.stringify( | ||
literal, | ||
)}, getting ${JSON.stringify(value)}.`, | ||
`Expected string ${JSON.stringify(literal)}, got ${JSON.stringify( | ||
value, | ||
)}.`, | ||
), | ||
@@ -51,3 +51,3 @@ {const: literal}, | ||
value, | ||
() => `Expected number ${literal}, getting ${value}.`, | ||
() => `Expected number ${literal}, got ${value}.`, | ||
), | ||
@@ -62,3 +62,3 @@ {const: literal}, | ||
value, | ||
() => `Expected boolean ${literal}, getting ${value}.`, | ||
() => `Expected boolean ${literal}, got ${value}.`, | ||
), | ||
@@ -65,0 +65,0 @@ {const: literal}, |
@@ -10,3 +10,3 @@ import type {RefinedType, TypeOf} from '../core'; | ||
value, | ||
() => `Expected integer, getting ${value}.`, | ||
() => `Expected integer, got ${value}.`, | ||
), | ||
@@ -30,7 +30,7 @@ {type: 'integer'}, | ||
if (value < min) { | ||
throw `Expected integer >= ${min}, getting ${value}.`; | ||
throw `Expected integer >= ${min}, got ${value}.`; | ||
} | ||
if (value > max) { | ||
throw `Expected integer <= ${max}, getting ${value}.`; | ||
throw `Expected integer <= ${max}, got ${value}.`; | ||
} | ||
@@ -63,15 +63,15 @@ | ||
if (value < minInclusive) { | ||
throw `Expected number >= ${minInclusive}, getting ${value}.`; | ||
throw `Expected number >= ${minInclusive}, got ${value}.`; | ||
} | ||
if (value <= minExclusive) { | ||
throw `Expected number > ${minExclusive}, getting ${value}.`; | ||
throw `Expected number > ${minExclusive}, got ${value}.`; | ||
} | ||
if (value > maxInclusive) { | ||
throw `Expected number <= ${maxInclusive}, getting ${value}.`; | ||
throw `Expected number <= ${maxInclusive}, got ${value}.`; | ||
} | ||
if (value >= maxExclusive) { | ||
throw `Expected number < ${maxExclusive}, getting ${value}.`; | ||
throw `Expected number < ${maxExclusive}, got ${value}.`; | ||
} | ||
@@ -78,0 +78,0 @@ |
@@ -19,4 +19,4 @@ import * as x from 'x-value'; | ||
value instanceof BufferClass, | ||
`Expected instance of Buffer, getting ${toString.call(value)}.`, | ||
`Expected instance of Buffer, got ${toString.call(value)}.`, | ||
), | ||
); |
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
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
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
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
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
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
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
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
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
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
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
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
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
706
373817
14
7054
Updatedtslib@^2.6.0