jsona
Version:
Provide data formatters (data model builder & json builder) to work with JSON API specification v1.0 in your JavaScript / TypeScript code
203 lines (169 loc) • 6.33 kB
text/typescript
type AtLeastOneProperty<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];
export interface IModelPropertiesMapper {
getId(model: TJsonaModel): string | number;
getType(model: TJsonaModel): string;
getAttributes(model: TJsonaModel): TAnyKeyValueObject;
getRelationships(model: TJsonaModel): TJsonaRelationships;
}
export interface IJsonPropertiesMapper {
createModel(type: string): TJsonaModel;
setId(model: TJsonaModel, id: string | number): void;
setAttributes(model: TJsonaModel, attributes: TAnyKeyValueObject): void;
setMeta(model: TJsonaModel, meta: TAnyKeyValueObject): void;
setLinks(model: TJsonaModel, links: TAnyKeyValueObject): void;
setResourceIdObjMeta(model: TJsonaModel, meta: unknown): void;
setRelationships(model: TJsonaModel, relationships: TJsonaRelationships): void;
setRelationshipLinks(parentModel: TJsonaModel, relationName: string, links: TJsonApiLinks): void;
setRelationshipMeta(parentModel: TJsonaModel, relationName: string, meta: TAnyKeyValueObject): void;
}
export interface IJsonaModelBuilder {
build(): TJsonaModel | Array<TJsonaModel>;
}
export interface IDeserializeCache {
getCachedModel(data: TJsonApiData, resourceIdObject: TResourceIdObj): TJsonaModel | null;
handleModel(model: TJsonaModel, data: TJsonApiData, resourceIdObject: TResourceIdObj): void;
createCacheKey(data: TJsonApiData, resourceIdObject: TResourceIdObj): string;
}
export interface IDeserializeCacheConstructor {
new(): IDeserializeCache;
}
export interface IJsonaDeserializer extends IJsonaModelBuilder {
setDeserializeCache(dc: IDeserializeCache): void;
setPropertiesMapper(pm: IJsonPropertiesMapper): void;
setJsonParsedObject(body: TJsonApiBody): void;
buildModelByData(data: TJsonApiData): TJsonaModel;
buildRelationsByData(data: TJsonApiData, model: TJsonaModel): TJsonaRelationships | null;
buildDataFromIncludedOrData(id: string | number, type: string): TJsonApiData;
buildDataInObject(): { [key: string]: TJsonApiData };
buildIncludedInObject(): { [key: string]: TJsonApiData };
}
export interface IJsonDeserializerConstructor {
new(propertiesMapper: IJsonPropertiesMapper, deserializeCache: IDeserializeCache, options?: TDeserializeOptions): IJsonaDeserializer;
}
export interface IModelsSerializer {
setPropertiesMapper(propertiesMapper: IModelPropertiesMapper): void;
setStuff(stuff: TJsonaModel | TJsonaModel[]): void;
setIncludeNames(includeNames: TJsonaDenormalizedIncludeNames | TJsonaNormalizedIncludeNamesTree): void;
build(): TJsonApiBody;
buildDataByModel(model: TJsonaModel | null): TJsonApiData;
buildRelationshipsByModel(model: TJsonaModel): TJsonApiRelationships;
buildIncludedByModel(
model: TJsonaModel,
includeTree: TJsonaNormalizedIncludeNamesTree,
builtIncluded: TJsonaUniqueIncluded
): void;
buildIncludedItem(
relationModel: TJsonaModel,
subIncludeTree: TJsonaNormalizedIncludeNamesTree,
builtIncluded: TJsonaUniqueIncluded
): void;
}
export interface IModelsSerializerConstructor {
new(propertiesMapper?: IModelPropertiesMapper): IModelsSerializer;
}
export type TDeserializeOptions = {
preferNestedDataFromData?: boolean,
}
export type TAnyKeyValueObject = {
[key: string]: any
};
export type TJsonApiBody = {
data?: TJsonApiData | TJsonApiData[];
included?: Array<TJsonApiData>;
};
export type TJsonApiData = {
type: string;
id?: string|number;
attributes?: TAnyKeyValueObject;
meta?: TAnyKeyValueObject;
links?: TJsonApiLinks;
relationships?: TJsonApiRelationships;
};
export type TJsonApiRelationshipData = {
type: string;
id: string | number;
meta?: TAnyKeyValueObject
[propertyName: string]: any
};
type FullTJsonApiRelation = {
data: TJsonApiRelationshipData | Array<TJsonApiRelationshipData> | null
links: TJsonApiLinks
meta: TAnyKeyValueObject
}
export type TJsonApiRelation = AtLeastOneProperty<FullTJsonApiRelation>;
type LinkKey = "self" | "related" | "first" | "prev" | "next" | "last";
// https://jsonapi.org/format/#document-links
type LinkObjectMember = string | { href?: string; meta?: TAnyKeyValueObject } | null;
export type TJsonApiLinks = {
[key in LinkKey]?: LinkObjectMember;
};
export type TJsonApiRelationships = {
[relationName: string]: TJsonApiRelation
};
export type TJsonaUniqueIncluded = {
[entityTypeId: string]: TJsonApiData
};
/**
* TJsonaDenormalizedIncludeNames example:
* 'user.town.country'
*/
export type TJsonaIncludeNamesChain = string;
/**
* TJsonaDenormalizedIncludeNames example:
* ['user', 'user.town', 'user.town.country', 'comments', 'comments.author']
*/
export type TJsonaDenormalizedIncludeNames = Array<TJsonaIncludeNamesChain>;
/**
* TJsonaNormalizedIncludeNamesTree example:
* {
* user: {
* town: {
* country: null
* }
* comments: {
* author: null
* }
*/
export type TJsonaNormalizedIncludeNamesTree = {
[relationName: string]: null | TJsonaNormalizedIncludeNamesTree
};
export type TJsonaModel = {
[propertyName: string]: any
};
export type TResourceIdObj = TJsonApiRelationshipData & {
type: string,
};
export type TJsonaRelationshipBuild = () => (TJsonaModel | Array<TJsonaModel>);
export type TJsonaRelationships = {
[relationName: string]: TJsonaRelationshipBuild | TJsonaModel | Array<TJsonaModel>
};
export type TReduxObject = {
[entityType: string]: {
[entityId: string]: TReduxObjectModel
}
};
export type TReduxObjectModel = {
id: number | string,
attributes?: TAnyKeyValueObject,
relationships?: TJsonApiRelationships
};
export type TReduxObjectRelation = {
data: {
// '1' or something like '1,12,44' for one-to-many relationships, ['1', '12', '44'] is reserved for future
id: string | Array<string>,
type: string,
}
}
export type SwitchCaseModelMapperOptionsType = {
switchAttributes?: boolean,
switchRelationships?: boolean,
switchType?: boolean,
switchChar?: string,
};
export type SwitchCaseJsonMapperOptionsType = {
camelizeAttributes?: boolean,
camelizeRelationships?: boolean,
camelizeType?: boolean,
camelizeMeta?: boolean,
switchChar?: string,
};