@sprucelabs/schema
Version:
Static and dynamic binding plus runtime validation and transformation to ensure your app is sound. 🤓
158 lines (157 loc) • 12.7 kB
TypeScript
import { FieldDefinitions, Fields, FieldDefinitionMap, FieldMap } from './.spruce/schemas/fields/fields.types';
import { FieldDefinition, FieldDefinitionValueType, Field, FieldType } from './fields/field.static.types';
export interface SchemaEntity {
schemaId: string;
namespace?: string;
name?: string;
version?: string;
description?: string;
get(fieldName: string, options?: Record<string, any>): any;
set(fieldName: string, value: any, options?: Record<string, any>): this;
getValues(options?: Record<string, any>): Record<string, any>;
setValues(values: Record<string, any>): this;
getNamedFields(options?: Record<string, any>): SchemaNamedField<any>[];
validate(options?: Record<string, any>): void;
isValid(options?: Record<string, any>): boolean;
}
export interface StaticSchemaEntity<S extends Schema> extends SchemaEntity {
readonly schemaId: S['id'];
readonly name: S['name'];
readonly namespace: S['namespace'];
readonly description?: string;
readonly version?: string;
get<F extends SchemaFieldNames<S>, CreateEntityInstances extends boolean = true>(fieldName: F, options?: SchemaNormalizeOptions<S, CreateEntityInstances>): SchemaFieldValueType<S, F, CreateEntityInstances>;
set<F extends SchemaFieldNames<S>>(fieldName: F, value: SchemaFieldValueType<S, F>, options?: SchemaNormalizeOptions<S, false>): this;
getValues<F extends SchemaFieldNames<S> = SchemaFieldNames<S>, PF extends SchemaPublicFieldNames<S> = SchemaPublicFieldNames<S>, CreateEntityInstances extends boolean = true, IncludePrivateFields extends boolean = true>(options?: SchemaGetValuesOptions<S, F, PF, CreateEntityInstances, IncludePrivateFields>): IncludePrivateFields extends false ? Pick<SchemaPublicValues<S, CreateEntityInstances>, PF> : Pick<SchemaAllValues<S, CreateEntityInstances>, F>;
setValues(values: SchemaPartialValues<S>): this;
getNamedFields<F extends SchemaFieldNames<S>>(options?: SchemaNamedFieldsOptions<S, F>): SchemaNamedField<S>[];
validate(options?: SchemaValidateOptions<S>): void;
isValid(options?: SchemaValidateOptions<S>): boolean;
}
/** @ts-ignore */
export type SchemaValues<S extends Schema, CreateEntityInstances extends boolean = false, IncludePrivateFields extends boolean = true, ShouldIncludeNullAndUndefinedFields extends boolean = false, F extends SchemaFieldNames<S> = SchemaFieldNames<S>, PF extends SchemaPublicFieldNames<S> = SchemaPublicFieldNames<S>> = IsDynamicSchema<S> extends true ? DynamicSchemaAllValues<S> : IncludePrivateFields extends false ? ShouldIncludeNullAndUndefinedFields extends true ? Pick<SchemaAllValues<S, CreateEntityInstances>, PF> : Pick<SchemaStaticValues<S, CreateEntityInstances>, PF> : ShouldIncludeNullAndUndefinedFields extends true ? Pick<SchemaAllValues<S, CreateEntityInstances>, F> : Pick<SchemaStaticValues<S, CreateEntityInstances>, F>;
export interface DynamicSchemaEntityByName<ISchema extends Schema, OurField extends Field<any> = ISchema['dynamicFieldSignature'] extends FieldDefinitions ? FieldMap[ISchema['dynamicFieldSignature']['type']] : any> extends SchemaEntity, Omit<StaticSchemaEntity<ISchema>, 'get' | 'set' | 'getValues' | 'setValues' | 'getNamedFields' | 'schemaId' | 'namespace' | 'name' | 'version' | 'description'> {
get<F extends string, CreateEntityInstances extends boolean = true>(fieldName: F, options?: DynamicSchemaNormalizeOptions<CreateEntityInstances>): FieldDefinitionValueType<OurField, CreateEntityInstances>;
set<F extends string>(fieldName: F, value: FieldDefinitionValueType<OurField>, options?: DynamicSchemaNormalizeOptions<false>): this;
getValues<F extends string, CreateEntityInstances extends boolean = true>(options?: DynamicSchemaGetValuesOptions<ISchema, F, CreateEntityInstances>): DynamicSchemaAllValues<ISchema, CreateEntityInstances>;
setValues(values: DynamicSchemaPartialValues<ISchema>): this;
getNamedFields<F extends string>(options?: DynamicSchemaNamedFieldsOptions<F>): DynamicSchemaNamedField[];
validate(options?: DynamicSchemaValidateOptions): void;
isValid(options?: DynamicSchemaValidateOptions): boolean;
}
export type SchemaFieldsByName = Record<string, FieldDefinitions>;
export interface Schema {
id: string;
name?: string;
version?: string;
namespace?: string;
description?: string;
importsWhenLocal?: string[];
importsWhenRemote?: string[];
moduleToImportFromWhenRemote?: string;
typeSuffix?: string;
dynamicFieldSignature?: FieldDefinitions & {
keyName: string;
keyTypeLiteral?: string;
};
fields?: SchemaFieldsByName;
}
export interface SchemaFieldValueUnion<V extends Record<string, any> = Record<string, any>, Id extends string = string, Version extends string | undefined = undefined> {
id: Id;
version?: Version;
values: V;
}
export type SchemaFields<T extends Schema> = {
[F in SchemaFieldNames<T>]: T['fields'][F] extends FieldDefinition ? FieldMap[T['fields'][F]['type']] : never;
};
export type SchemaAllValues<S extends Schema, CreateEntityInstances extends boolean = false> = IsDynamicSchema<S> extends true ? DynamicSchemaAllValues<S, CreateEntityInstances> : StaticSchemaAllValues<S, CreateEntityInstances>;
export type StaticSchemaAllValues<S extends Schema, CreateEntityInstances extends boolean = false> = {
[K in SchemaFieldNames<S>]-?: SchemaFieldValueType<S, K, CreateEntityInstances>;
};
export type DynamicSchemaAllValues<S extends Schema, CreateEntityInstances extends boolean = false> = Record<string, S['dynamicFieldSignature'] extends FieldDefinitions ? FieldDefinitionValueType<S['dynamicFieldSignature'], CreateEntityInstances> : never>;
export type SchemaPartialValues<S extends Schema, CreateEntityInstances extends boolean = false> = IsDynamicSchema<S> extends true ? DynamicSchemaPartialValues<S, CreateEntityInstances> : StaticSchemaPartialValues<S, CreateEntityInstances>;
export type StaticSchemaPartialValues<T extends Schema, CreateEntityInstances extends boolean = false> = {
[K in SchemaFieldNames<T>]?: SchemaFieldValueType<T, K, CreateEntityInstances> | undefined | null;
};
export type DynamicSchemaPartialValues<S extends Schema, CreateEntityInstances extends boolean = false> = Partial<Record<string, S['dynamicFieldSignature'] extends FieldDefinitions ? FieldDefinitionValueType<S['dynamicFieldSignature'], CreateEntityInstances> | undefined | null : never>>;
export type SchemaStaticValues<T extends Schema, CreateEntityInstances extends boolean = false, K extends SchemaOptionalFieldNames<T> = SchemaOptionalFieldNames<T>, V extends SchemaAllValues<T, CreateEntityInstances> = SchemaAllValues<T, CreateEntityInstances>> = Omit<V, K> & Partial<Pick<V, K>>;
export type IsDynamicSchema<S extends Schema> = S['dynamicFieldSignature'] extends FieldDefinitions ? true : false;
export type SchemaDefaultValues<S extends Schema, CreateEntityInstances extends boolean = false, K extends SchemaFieldNamesWithDefaultValue<S> = SchemaFieldNamesWithDefaultValue<S>, V extends SchemaAllValues<S, CreateEntityInstances> = SchemaAllValues<S, CreateEntityInstances>> = {
[F in K]: NonNullable<V[F]>;
};
export type SchemaValuesWithDefaults<T extends Schema> = SchemaValues<T> & SchemaDefaultValues<T>;
export type SchemaOptionalFieldNames<T extends Schema> = {
[K in SchemaFieldNames<T>]: T['fields'][K] extends FieldDefinitions ? T['fields'][K]['isRequired'] extends true ? never : K : never;
}[SchemaFieldNames<T>];
export type SchemaRequiredFieldNames<T extends Schema> = {
[K in SchemaFieldNames<T>]: T['fields'][K] extends FieldDefinitions ? T['fields'][K]['isRequired'] extends true ? K : never : never;
}[SchemaFieldNames<T>];
export type SchemaFieldNamesWithDefaultValue<T extends Schema> = {
[K in SchemaFieldNames<T>]: T['fields'][K] extends FieldDefinitions ? T['fields'][K]['defaultValue'] extends Required<T['fields'][K]['defaultValue']> ? K : never : never;
}[SchemaFieldNames<T>];
export type SchemaFieldValueType<S extends Schema, K extends SchemaFieldNames<S>, CreateEntityInstances extends boolean = false, ShouldIncludeNullAndUndefinedFieldsInSchemas extends boolean = false> = S['fields'][K] extends FieldDefinitions ? FieldDefinitionValueType<S['fields'][K], CreateEntityInstances, ShouldIncludeNullAndUndefinedFieldsInSchemas> : never;
export type SchemaFieldNames<T extends Schema> = Extract<keyof T['fields'], string>;
export type SchemaPublicFieldNames<S extends Schema> = {
[K in SchemaFieldNames<S>]: S['fields'][K] extends FieldDefinitions ? S['fields'][K]['isPrivate'] extends true ? never : K : never;
}[SchemaFieldNames<S>];
export type SchemaPublicValues<S extends Schema, CreateEntityInstances extends boolean = false, PublicFieldNames extends SchemaPublicFieldNames<S> = SchemaPublicFieldNames<S>, AllValues extends SchemaValues<S, CreateEntityInstances> = SchemaValues<S, CreateEntityInstances>> = S['fields'] extends SchemaFieldsByName ? Exclude<Pick<AllValues, PublicFieldNames>, never> : never;
export type SchemaFieldDefinition<T extends Schema, K extends SchemaFieldNames<T>> = T['fields'][K] extends FieldDefinitions ? T['fields'][K]['type'] : never;
export type SchemaFieldType<T extends Schema, K extends SchemaFieldNames<T>> = T['fields'][K] extends FieldDefinitions ? T['fields'][K]['type'] : never;
export interface SchemaNamedField<T extends Schema> {
name: SchemaFieldNames<T>;
field: Fields;
}
export interface DynamicSchemaNamedField {
name: string;
field: Fields;
}
export interface SchemaNormalizeFieldValueOptions<CreateEntityInstances extends boolean> {
/** Should i validate any values passed through */
shouldValidate?: boolean;
/** Should I create schema instances for schema fields (defaults to true) */
shouldCreateEntityInstances?: CreateEntityInstances;
}
export interface SchemaNormalizeOptions<S extends Schema, CreateEntityInstances extends boolean, ShouldIncludeNullAndUndefinedFields extends boolean = true> extends SchemaNormalizeFieldValueOptions<CreateEntityInstances> {
/** Options passed to each field that conforms to the field definition's options */
byField?: {
[K in SchemaFieldNames<S>]?: S['fields'][K] extends FieldDefinition ? Partial<FieldDefinitionMap[S['fields'][K]['type']]['options']> : never;
};
shouldIncludeNullAndUndefinedFields?: ShouldIncludeNullAndUndefinedFields;
shouldRetainDotNotationKeys?: boolean;
}
export interface DynamicSchemaNormalizeOptions<CreateEntityInstances extends boolean> extends SchemaNormalizeFieldValueOptions<CreateEntityInstances> {
}
export type SchemaGetValuesOptions<S extends Schema, F extends SchemaFieldNames<S> = SchemaFieldNames<S>, PF extends SchemaPublicFieldNames<S> = SchemaPublicFieldNames<S>, CreateEntityInstances extends boolean = false, IncludePrivateFields extends boolean = true, ShouldIncludeNullAndUndefinedFields extends boolean = true, ExcludeFields extends SchemaFieldNames<S> | undefined = undefined, PublicExcludeFields extends SchemaPublicFieldNames<S> | undefined = undefined> = SchemaNormalizeOptions<S, CreateEntityInstances, ShouldIncludeNullAndUndefinedFields> & (IncludePrivateFields extends false ? {
shouldIncludePrivateFields: IncludePrivateFields;
fields?: PF[];
excludeFields?: PublicExcludeFields[];
} : {
shouldIncludePrivateFields?: IncludePrivateFields;
fields?: F[];
excludeFields?: ExcludeFields[];
});
export type DynamicSchemaGetValuesOptions<T extends Schema, F extends string, CreateEntityInstances extends boolean> = SchemaNormalizeOptions<T, CreateEntityInstances> & {
fields?: F[];
};
export interface SchemaGetDefaultValuesOptions<T extends Schema, F extends SchemaFieldNamesWithDefaultValue<T>, CreateEntityInstances extends boolean> extends SchemaNormalizeOptions<T, CreateEntityInstances> {
fields?: F[];
}
export interface SchemaNamedFieldsOptions<T extends Schema, F extends SchemaFieldNames<T>> {
fields?: F[];
}
export interface DynamicSchemaValidateOptions<F extends string = string> extends DynamicSchemaNamedFieldsOptions<F> {
}
export interface DynamicSchemaNamedFieldsOptions<F extends string> {
fields?: F[];
}
export interface SchemaValidateOptions<T extends Schema, F extends SchemaFieldNames<T> = SchemaFieldNames<T>> extends SchemaNamedFieldsOptions<T, F> {
shouldMapToParameterErrors?: boolean;
}
export type PickFieldNames<S extends Schema, T extends FieldType> = {
[F in keyof S['fields']]: S['fields'][F] extends FieldDefinitions ? S['fields'][F]['type'] extends T ? F : never : never;
}[Extract<keyof S['fields'], string>];
export interface SchemaIdWithVersion {
id: string;
version?: string;
namespace?: string;
}