@sinclair/typebox
Version:
Json Schema Type Builder with Static Type Resolution for TypeScript
92 lines (91 loc) • 3.83 kB
JavaScript
import { CreateType } from '../create/type.mjs';
import { Computed } from '../computed/index.mjs';
import { Literal } from '../literal/index.mjs';
import { Never } from '../never/index.mjs';
import { IntersectEvaluated } from '../intersect/index.mjs';
import { UnionEvaluated } from '../union/index.mjs';
// ------------------------------------------------------------------
// Infrastructure
// ------------------------------------------------------------------
import { IndexPropertyKeys } from './indexed-property-keys.mjs';
import { IndexFromMappedKey } from './indexed-from-mapped-key.mjs';
import { IndexFromMappedResult } from './indexed-from-mapped-result.mjs';
// ------------------------------------------------------------------
// KindGuard
// ------------------------------------------------------------------
import { IsArray, IsIntersect, IsObject, IsMappedKey, IsMappedResult, IsNever, IsSchema, IsTuple, IsUnion, IsLiteralValue, IsRef } from '../guard/kind.mjs';
import { IsArray as IsArrayValue } from '../guard/value.mjs';
// prettier-ignore
function FromRest(types, key) {
return types.map(left => IndexFromPropertyKey(left, key));
}
// prettier-ignore
function FromIntersectRest(types) {
return types.filter(left => !IsNever(left));
}
// prettier-ignore
function FromIntersect(types, key) {
return (IntersectEvaluated(FromIntersectRest(FromRest(types, key))));
}
// prettier-ignore
function FromUnionRest(types) {
return (types.some(L => IsNever(L))
? []
: types);
}
// prettier-ignore
function FromUnion(types, key) {
return (UnionEvaluated(FromUnionRest(FromRest(types, key))));
}
// prettier-ignore
function FromTuple(types, key) {
return (key === '[number]' ? UnionEvaluated(types) :
key in types ? types[key] :
Never());
}
// prettier-ignore
function FromArray(type, key) {
// ... ?
return (key === '[number]' ? type : Never());
}
// prettier-ignore
function FromProperty(properties, key) {
return (key in properties ? properties[key] : Never());
}
// prettier-ignore
export function IndexFromPropertyKey(type, key) {
return (IsIntersect(type) ? FromIntersect(type.allOf, key) :
IsUnion(type) ? FromUnion(type.anyOf, key) :
IsTuple(type) ? FromTuple(type.items ?? [], key) :
IsArray(type) ? FromArray(type.items, key) :
IsObject(type) ? FromProperty(type.properties, key) :
Never());
}
// prettier-ignore
export function IndexFromPropertyKeys(type, propertyKeys) {
return propertyKeys.map(left => IndexFromPropertyKey(type, left));
}
// prettier-ignore
function FromType(type, propertyKeys) {
const result = IndexFromPropertyKeys(type, propertyKeys);
return UnionEvaluated(result);
}
// prettier-ignore
function UnionFromPropertyKeys(propertyKeys) {
const result = propertyKeys.reduce((result, key) => IsLiteralValue(key) ? [...result, Literal(key)] : result, []);
return UnionEvaluated(result);
}
/** `[Json]` Returns an Indexed property type for the given keys */
// prettier-ignore
export function Index(type, key, options) {
const typeKey = IsArrayValue(key) ? UnionFromPropertyKeys(key) : key;
const propertyKeys = IsSchema(key) ? IndexPropertyKeys(key) : key;
const isTypeRef = IsRef(type);
const isKeyRef = IsRef(key);
return (IsMappedResult(key) ? IndexFromMappedResult(type, key, options) :
IsMappedKey(key) ? IndexFromMappedKey(type, key, options) :
(isTypeRef && isKeyRef) ? Computed('Index', [type, typeKey], options) :
(!isTypeRef && isKeyRef) ? Computed('Index', [type, typeKey], options) :
(isTypeRef && !isKeyRef) ? Computed('Index', [type, typeKey], options) :
CreateType(FromType(type, propertyKeys), options));
}