You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

json-api-models

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json-api-models - npm Package Compare versions

Comparing version

to
0.1.0-beta.8

LICENSE

2

dist/index.cjs.js

@@ -1,1 +0,1 @@

"use strict";Object.defineProperty(exports,"__esModule",{value:!0});class t{constructor(t,e){this.store=e,this.attributes={},this.relationships={},this.meta={},this.links={},this.casts={},this.merge(t)}getAttribute(t){const e=this.attributes[t],s=this.casts[t];return s&&null!=e?s!==String&&s!==Number&&s!==Boolean&&((i=s).prototype&&i.prototype.constructor.name)?new s(e):s(e):e;var i}getRelationship(t){return this.store.find(this.relationships[t].data)}identifier(){return{id:this.id,type:this.type}}merge(t){if("type"in t&&(this.type=t.type),"id"in t&&(this.id=t.id),"attributes"in t&&(Object.assign(this.attributes,t.attributes),Object.keys(t.attributes).forEach((t=>{Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),t)||Object.defineProperty(this,t,{configurable:!0,get:()=>this.getAttribute(t)})}))),"relationships"in t)for(const[e,s]of Object.entries(t.relationships))this.relationships[e]=this.relationships[e]||{},Object.assign(this.relationships[e],s),Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),e)||Object.defineProperty(this,e,{configurable:!0,get:()=>this.getRelationship(e)});"links"in t&&(this.links=t.links),"meta"in t&&(this.meta=t.meta)}}function e(t){return encodeURIComponent(t).replace(/[!'()*]/g,(function(t){return"%"+t.charCodeAt(0).toString(16).toUpperCase()}))}exports.Model=t,exports.Query=class{constructor(t={}){this.query=Object.assign({},t)}append(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.append.apply(this,t))):this.query[t]=(this.query[t]?this.query[t]+",":"")+e,this}set(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.set.apply(this,t))):this.query[t]=e,this}delete(t){return Array.isArray(t)?t.forEach((t=>this.delete(t))):delete this.query[t],this}toString(){return Object.entries(this.query).sort(((t,e)=>t[0].localeCompare(e[0]))).map((([t,s])=>e(t)+"="+e(s))).join("&")}},exports.Store=class{constructor(t={}){this.models=t,this.graph={}}model(t,e){this.models[t]=e}find(t,e){return null===t?null:Array.isArray(t)?t.map((t=>this.find(t))):"object"==typeof t?this.find(t.type,t.id):this.graph[t]&&this.graph[t][e]||null}findAll(t){return this.graph[t]?Object.keys(this.graph[t]).map((e=>this.graph[t][e])):[]}sync(t){const e=this.syncResource.bind(this);return"included"in t&&t.included.map(e),Array.isArray(t.data)?t.data.map(e):e(t.data)}syncResource(t){const{type:e,id:s}=t;return this.graph[e]=this.graph[e]||{},this.graph[e][s]?this.graph[e][s].merge(t):this.graph[e][s]=this.createModel(t),this.graph[e][s]}createModel(e){return new(this.models[e.type]||this.models["*"]||t)(e,this)}forget(t){delete this.graph[t.type][t.id]}reset(){this.graph={}}};
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});class t{constructor(t,e){this.store=e,this.attributes={},this.relationships={},this.meta={},this.links={},this.casts={},this.merge(t)}getAttribute(t){const e=this.attributes[t],s=this.casts[t];return s&&null!=e?s!==String&&s!==Number&&s!==Boolean&&((r=s).prototype&&r.prototype.constructor.name)?new s(e):s(e):e;var r}getRelationship(t){const e=this.relationships[t].data;return Array.isArray(e),this.store.find(e)}identifier(){return{id:this.id,type:this.type}}merge(t){"type"in t&&(this.type=t.type),"id"in t&&(this.id=t.id),"attributes"in t&&(Object.assign(this.attributes,t.attributes),Object.keys(t.attributes).forEach((t=>{Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),t)||Object.getOwnPropertyDescriptor(this,t)||(this[t]=null,Object.defineProperty(this,t,{get:()=>this.getAttribute(t),configurable:!0,enumerable:!0}))}))),"relationships"in t&&Object.entries(t.relationships).forEach((([t,e])=>{this.relationships[t]=this.relationships[t]||{},Object.assign(this.relationships[t],e),Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),t)||Object.getOwnPropertyDescriptor(this,t)||(this[t]=null,Object.defineProperty(this,t,{get:()=>this.getRelationship(t),configurable:!0,enumerable:!0}))})),"links"in t&&(this.links=t.links),"meta"in t&&(this.meta=t.meta)}}function e(t){return encodeURIComponent(t).replace(/[!'()*]/g,(function(t){return"%"+t.charCodeAt(0).toString(16).toUpperCase()}))}exports.Model=t,exports.Query=class{constructor(t={}){this.query=Object.assign({},t)}append(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.append.apply(this,t))):this.query[t]=(this.query[t]?this.query[t]+",":"")+e,this}set(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.set.apply(this,t))):this.query[t]=e,this}delete(t){return Array.isArray(t)?t.forEach((t=>this.delete(t))):delete this.query[t],this}toString(){return Object.entries(this.query).sort(((t,e)=>t[0].localeCompare(e[0]))).map((([t,s])=>e(t)+"="+e(s))).join("&")}},exports.Store=class{constructor(t={}){this.models=t,this.graph={}}find(t,e){return null===t?null:Array.isArray(t)?t.map((t=>this.find(t))):"object"==typeof t?this.find(t.type,t.id):this.graph[t]&&this.graph[t][e]||null}findAll(t){return this.graph[t]?Object.keys(this.graph[t]).map((e=>this.graph[t][e])):[]}sync(t){const e=this.syncResource.bind(this);return"included"in t&&t.included.map(e),Array.isArray(t.data)?t.data.map(e):e(t.data)}syncResource(t){const{type:e,id:s}=t;return this.graph[e]=this.graph[e]||{},this.graph[e][s]?this.graph[e][s].merge(t):this.graph[e][s]=this.createModel(t),this.graph[e][s]}createModel(e){return new(this.models[e.type]||this.models["*"]||t)(e,this)}forget(t){delete this.graph[t.type][t.id]}reset(){this.graph={}}};
export * from './types';
export { Store } from './store';
export { Model } from './model';
export { Query } from './query';
export * from './store';
export * from './model';
export * from './query';

@@ -1,1 +0,1 @@

class t{constructor(t,e){this.store=e,this.attributes={},this.relationships={},this.meta={},this.links={},this.casts={},this.merge(t)}getAttribute(t){const e=this.attributes[t],i=this.casts[t];return i&&null!=e?i!==String&&i!==Number&&i!==Boolean&&((s=i).prototype&&s.prototype.constructor.name)?new i(e):i(e):e;var s}getRelationship(t){return this.store.find(this.relationships[t].data)}identifier(){return{id:this.id,type:this.type}}merge(t){if("type"in t&&(this.type=t.type),"id"in t&&(this.id=t.id),"attributes"in t&&(Object.assign(this.attributes,t.attributes),Object.keys(t.attributes).forEach((t=>{Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),t)||Object.defineProperty(this,t,{configurable:!0,get:()=>this.getAttribute(t)})}))),"relationships"in t)for(const[e,i]of Object.entries(t.relationships))this.relationships[e]=this.relationships[e]||{},Object.assign(this.relationships[e],i),Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),e)||Object.defineProperty(this,e,{configurable:!0,get:()=>this.getRelationship(e)});"links"in t&&(this.links=t.links),"meta"in t&&(this.meta=t.meta)}}class e{constructor(t={}){this.models=t,this.graph={}}model(t,e){this.models[t]=e}find(t,e){return null===t?null:Array.isArray(t)?t.map((t=>this.find(t))):"object"==typeof t?this.find(t.type,t.id):this.graph[t]&&this.graph[t][e]||null}findAll(t){return this.graph[t]?Object.keys(this.graph[t]).map((e=>this.graph[t][e])):[]}sync(t){const e=this.syncResource.bind(this);return"included"in t&&t.included.map(e),Array.isArray(t.data)?t.data.map(e):e(t.data)}syncResource(t){const{type:e,id:i}=t;return this.graph[e]=this.graph[e]||{},this.graph[e][i]?this.graph[e][i].merge(t):this.graph[e][i]=this.createModel(t),this.graph[e][i]}createModel(e){return new(this.models[e.type]||this.models["*"]||t)(e,this)}forget(t){delete this.graph[t.type][t.id]}reset(){this.graph={}}}function i(t){return encodeURIComponent(t).replace(/[!'()*]/g,(function(t){return"%"+t.charCodeAt(0).toString(16).toUpperCase()}))}class s{constructor(t={}){this.query=Object.assign({},t)}append(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.append.apply(this,t))):this.query[t]=(this.query[t]?this.query[t]+",":"")+e,this}set(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.set.apply(this,t))):this.query[t]=e,this}delete(t){return Array.isArray(t)?t.forEach((t=>this.delete(t))):delete this.query[t],this}toString(){return Object.entries(this.query).sort(((t,e)=>t[0].localeCompare(e[0]))).map((([t,e])=>i(t)+"="+i(e))).join("&")}}export{t as Model,s as Query,e as Store};
class t{constructor(t,e){this.store=e,this.attributes={},this.relationships={},this.meta={},this.links={},this.casts={},this.merge(t)}getAttribute(t){const e=this.attributes[t],i=this.casts[t];return i&&null!=e?i!==String&&i!==Number&&i!==Boolean&&((s=i).prototype&&s.prototype.constructor.name)?new i(e):i(e):e;var s}getRelationship(t){const e=this.relationships[t].data;return Array.isArray(e),this.store.find(e)}identifier(){return{id:this.id,type:this.type}}merge(t){"type"in t&&(this.type=t.type),"id"in t&&(this.id=t.id),"attributes"in t&&(Object.assign(this.attributes,t.attributes),Object.keys(t.attributes).forEach((t=>{Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),t)||Object.getOwnPropertyDescriptor(this,t)||(this[t]=null,Object.defineProperty(this,t,{get:()=>this.getAttribute(t),configurable:!0,enumerable:!0}))}))),"relationships"in t&&Object.entries(t.relationships).forEach((([t,e])=>{this.relationships[t]=this.relationships[t]||{},Object.assign(this.relationships[t],e),Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),t)||Object.getOwnPropertyDescriptor(this,t)||(this[t]=null,Object.defineProperty(this,t,{get:()=>this.getRelationship(t),configurable:!0,enumerable:!0}))})),"links"in t&&(this.links=t.links),"meta"in t&&(this.meta=t.meta)}}class e{constructor(t={}){this.models=t,this.graph={}}find(t,e){return null===t?null:Array.isArray(t)?t.map((t=>this.find(t))):"object"==typeof t?this.find(t.type,t.id):this.graph[t]&&this.graph[t][e]||null}findAll(t){return this.graph[t]?Object.keys(this.graph[t]).map((e=>this.graph[t][e])):[]}sync(t){const e=this.syncResource.bind(this);return"included"in t&&t.included.map(e),Array.isArray(t.data)?t.data.map(e):e(t.data)}syncResource(t){const{type:e,id:i}=t;return this.graph[e]=this.graph[e]||{},this.graph[e][i]?this.graph[e][i].merge(t):this.graph[e][i]=this.createModel(t),this.graph[e][i]}createModel(e){return new(this.models[e.type]||this.models["*"]||t)(e,this)}forget(t){delete this.graph[t.type][t.id]}reset(){this.graph={}}}function i(t){return encodeURIComponent(t).replace(/[!'()*]/g,(function(t){return"%"+t.charCodeAt(0).toString(16).toUpperCase()}))}class s{constructor(t={}){this.query=Object.assign({},t)}append(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.append.apply(this,t))):this.query[t]=(this.query[t]?this.query[t]+",":"")+e,this}set(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.set.apply(this,t))):this.query[t]=e,this}delete(t){return Array.isArray(t)?t.forEach((t=>this.delete(t))):delete this.query[t],this}toString(){return Object.entries(this.query).sort(((t,e)=>t[0].localeCompare(e[0]))).map((([t,e])=>i(t)+"="+i(e))).join("&")}}export{t as Model,s as Query,e as Store};

@@ -1,1 +0,1 @@

var JsonApiModels=function(t){"use strict";class e{constructor(t,e){this.store=e,this.attributes={},this.relationships={},this.meta={},this.links={},this.casts={},this.merge(t)}getAttribute(t){const e=this.attributes[t],i=this.casts[t];return i&&null!=e?i!==String&&i!==Number&&i!==Boolean&&((s=i).prototype&&s.prototype.constructor.name)?new i(e):i(e):e;var s}getRelationship(t){return this.store.find(this.relationships[t].data)}identifier(){return{id:this.id,type:this.type}}merge(t){if("type"in t&&(this.type=t.type),"id"in t&&(this.id=t.id),"attributes"in t&&(Object.assign(this.attributes,t.attributes),Object.keys(t.attributes).forEach((t=>{Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),t)||Object.defineProperty(this,t,{configurable:!0,get:()=>this.getAttribute(t)})}))),"relationships"in t)for(const[e,i]of Object.entries(t.relationships))this.relationships[e]=this.relationships[e]||{},Object.assign(this.relationships[e],i),Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),e)||Object.defineProperty(this,e,{configurable:!0,get:()=>this.getRelationship(e)});"links"in t&&(this.links=t.links),"meta"in t&&(this.meta=t.meta)}}function i(t){return encodeURIComponent(t).replace(/[!'()*]/g,(function(t){return"%"+t.charCodeAt(0).toString(16).toUpperCase()}))}return t.Model=e,t.Query=class{constructor(t={}){this.query=Object.assign({},t)}append(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.append.apply(this,t))):this.query[t]=(this.query[t]?this.query[t]+",":"")+e,this}set(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.set.apply(this,t))):this.query[t]=e,this}delete(t){return Array.isArray(t)?t.forEach((t=>this.delete(t))):delete this.query[t],this}toString(){return Object.entries(this.query).sort(((t,e)=>t[0].localeCompare(e[0]))).map((([t,e])=>i(t)+"="+i(e))).join("&")}},t.Store=class{constructor(t={}){this.models=t,this.graph={}}model(t,e){this.models[t]=e}find(t,e){return null===t?null:Array.isArray(t)?t.map((t=>this.find(t))):"object"==typeof t?this.find(t.type,t.id):this.graph[t]&&this.graph[t][e]||null}findAll(t){return this.graph[t]?Object.keys(this.graph[t]).map((e=>this.graph[t][e])):[]}sync(t){const e=this.syncResource.bind(this);return"included"in t&&t.included.map(e),Array.isArray(t.data)?t.data.map(e):e(t.data)}syncResource(t){const{type:e,id:i}=t;return this.graph[e]=this.graph[e]||{},this.graph[e][i]?this.graph[e][i].merge(t):this.graph[e][i]=this.createModel(t),this.graph[e][i]}createModel(t){return new(this.models[t.type]||this.models["*"]||e)(t,this)}forget(t){delete this.graph[t.type][t.id]}reset(){this.graph={}}},Object.defineProperty(t,"__esModule",{value:!0}),t}({});
var JsonApiModels=function(t){"use strict";class e{constructor(t,e){this.store=e,this.attributes={},this.relationships={},this.meta={},this.links={},this.casts={},this.merge(t)}getAttribute(t){const e=this.attributes[t],i=this.casts[t];return i&&null!=e?i!==String&&i!==Number&&i!==Boolean&&((r=i).prototype&&r.prototype.constructor.name)?new i(e):i(e):e;var r}getRelationship(t){const e=this.relationships[t].data;return Array.isArray(e),this.store.find(e)}identifier(){return{id:this.id,type:this.type}}merge(t){"type"in t&&(this.type=t.type),"id"in t&&(this.id=t.id),"attributes"in t&&(Object.assign(this.attributes,t.attributes),Object.keys(t.attributes).forEach((t=>{Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),t)||Object.getOwnPropertyDescriptor(this,t)||(this[t]=null,Object.defineProperty(this,t,{get:()=>this.getAttribute(t),configurable:!0,enumerable:!0}))}))),"relationships"in t&&Object.entries(t.relationships).forEach((([t,e])=>{this.relationships[t]=this.relationships[t]||{},Object.assign(this.relationships[t],e),Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this),t)||Object.getOwnPropertyDescriptor(this,t)||(this[t]=null,Object.defineProperty(this,t,{get:()=>this.getRelationship(t),configurable:!0,enumerable:!0}))})),"links"in t&&(this.links=t.links),"meta"in t&&(this.meta=t.meta)}}function i(t){return encodeURIComponent(t).replace(/[!'()*]/g,(function(t){return"%"+t.charCodeAt(0).toString(16).toUpperCase()}))}return t.Model=e,t.Query=class{constructor(t={}){this.query=Object.assign({},t)}append(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.append.apply(this,t))):this.query[t]=(this.query[t]?this.query[t]+",":"")+e,this}set(t,e){return"object"==typeof t?Object.entries(t).map((t=>this.set.apply(this,t))):this.query[t]=e,this}delete(t){return Array.isArray(t)?t.forEach((t=>this.delete(t))):delete this.query[t],this}toString(){return Object.entries(this.query).sort(((t,e)=>t[0].localeCompare(e[0]))).map((([t,e])=>i(t)+"="+i(e))).join("&")}},t.Store=class{constructor(t={}){this.models=t,this.graph={}}find(t,e){return null===t?null:Array.isArray(t)?t.map((t=>this.find(t))):"object"==typeof t?this.find(t.type,t.id):this.graph[t]&&this.graph[t][e]||null}findAll(t){return this.graph[t]?Object.keys(this.graph[t]).map((e=>this.graph[t][e])):[]}sync(t){const e=this.syncResource.bind(this);return"included"in t&&t.included.map(e),Array.isArray(t.data)?t.data.map(e):e(t.data)}syncResource(t){const{type:e,id:i}=t;return this.graph[e]=this.graph[e]||{},this.graph[e][i]?this.graph[e][i].merge(t):this.graph[e][i]=this.createModel(t),this.graph[e][i]}createModel(t){return new(this.models[t.type]||this.models["*"]||e)(t,this)}forget(t){delete this.graph[t.type][t.id]}reset(){this.graph={}}},Object.defineProperty(t,"__esModule",{value:!0}),t}({});

@@ -6,5 +6,5 @@ import { Store } from './store';

};
export declare class Model implements JsonApiResource {
export declare class Model<Type extends string = any> implements JsonApiResource<Type> {
protected store: Store;
type: string;
type: Type;
id: string;

@@ -17,3 +17,3 @@ attributes: KeyValueObject;

[field: string]: any;
constructor(data: JsonApiResource, store: Store);
constructor(data: JsonApiResource<Type>, store: Store);
getAttribute(name: string): any;

@@ -24,7 +24,7 @@ getRelationship(name: string): any;

*/
identifier(): JsonApiIdentifier;
identifier(): JsonApiIdentifier<Type>;
/**
* Merge new JSON:API resource data into the model.
*/
merge(data: JsonApiResource): void;
merge(data: Partial<JsonApiResource<Type>>): void;
}
import { Model } from './model';
import { JsonApiDocument, JsonApiIdentifier, JsonApiResource } from './types';
interface Graph {
declare type Graph = {
[type: string]: {
[id: string]: Model;
[id: string]: any;
};
}
declare type ModelConstructor = {
new (data: JsonApiResource, store?: Store): Model;
};
interface ModelCollection {
[type: string]: ModelConstructor;
}
export declare class Store {
models: ModelCollection;
export declare type ModelConstructor<Type extends string> = {
new (data: JsonApiResource<Type>, store: Store): Model<Type>;
};
export declare type ModelCollection<Models> = {
[Type in keyof Models & string]: ModelConstructor<Type>;
} & {
'*'?: ModelConstructor<any>;
};
export declare type ModelForType<Type extends string, Models extends ModelCollection<Models>> = Type extends keyof Models ? InstanceType<Models[Type]> : Model;
export declare class Store<Models extends ModelCollection<Models> = any> {
models: Models;
protected graph: Graph;
constructor(models?: ModelCollection);
model(type: string, model: ModelConstructor): void;
find(identifier: JsonApiIdentifier): Model;
find(identifiers: JsonApiIdentifier[]): Model[];
find(type: string, id: string): Model;
findAll(type: string): Model[];
sync(document: JsonApiDocument): Model | Model[];
syncResource(data: JsonApiIdentifier): Model;
private createModel;
constructor(models?: Models);
find<Type extends string>(identifier: JsonApiIdentifier<Type>): ModelForType<Type, Models> | null;
find<Type extends string>(identifiers: JsonApiIdentifier<Type>[]): ModelForType<Type, Models>[];
find<Type extends string>(type: Type, id: string): ModelForType<Type, Models> | null;
findAll<Type extends string>(type: Type): ModelForType<Type, Models>[];
sync<Type extends string>(document: JsonApiDocument<Type>): ModelForType<Type, Models> | ModelForType<Type, Models>[] | null;
syncResource<Type extends string>(data: JsonApiResource<Type>): ModelForType<Type, Models>;
protected createModel<Type extends string>(data: JsonApiResource<Type>): ModelForType<Type, Models>;
forget(data: JsonApiIdentifier): void;

@@ -27,0 +29,0 @@ reset(): void;

export declare type KeyValueObject = {
[key: string]: any;
};
export interface JsonApiDocument {
data: JsonApiResource | JsonApiResource[];
export interface JsonApiDocument<Type extends string = string> {
data: JsonApiResource<Type> | JsonApiResource<Type>[];
included?: JsonApiResource[];

@@ -10,7 +10,7 @@ meta?: KeyValueObject;

}
export interface JsonApiIdentifier {
type: string;
export interface JsonApiIdentifier<Type extends string = string> {
type: Type;
id: string;
}
export interface JsonApiResource extends JsonApiIdentifier {
export interface JsonApiResource<Type extends string = string> extends JsonApiIdentifier<Type> {
attributes?: KeyValueObject;

@@ -24,6 +24,12 @@ relationships?: JsonApiRelationships;

}
export interface JsonApiRelationship {
data?: JsonApiIdentifier | JsonApiIdentifier[];
export interface JsonApiRelationship<Type extends string = string> {
data?: JsonApiIdentifier<Type> | JsonApiIdentifier<Type>[] | null;
meta?: KeyValueObject;
links?: KeyValueObject;
}
export interface JsonApiRelationshipToOne<Type extends string = string> extends JsonApiRelationship<Type> {
data?: JsonApiIdentifier<Type> | null;
}
export interface JsonApiRelationshipToMany<Type extends string = string> extends JsonApiRelationship<Type> {
data?: JsonApiIdentifier<Type>[];
}
{
"name": "json-api-models",
"description": "A lightweight layer for working with JSON:API data.",
"version": "0.1.0-beta.7",
"version": "0.1.0-beta.8",
"author": "Toby Zerner",

@@ -33,3 +33,3 @@ "license": "MIT",

"tslib": "^2.3.1",
"typescript": "4.3.5"
"typescript": "^4.6.3"
},

@@ -36,0 +36,0 @@ "release-it": {

@@ -112,5 +112,5 @@ # json-api-models

class User extends Model {
public name: string;
public age: number;
class User extends Model<'users'> {
public declare name: string;
public declare age: number;

@@ -123,11 +123,8 @@ get firstName() {

Register your custom models with the store either during construction, or with the `model` method:
Register your custom models with the store during construction:
```ts
const models = new Store({
'users': User
users: User,
});
// or
models.model('users', User);
```

@@ -140,8 +137,8 @@

```ts
class User extends Model {
public name: string;
public createdAt: Date;
class User extends Model<'users'> {
declare public name: string;
declare public createdAt: Date;
protected casts = {
createdAt: Date
createdAt: Date,
};

@@ -168,3 +165,3 @@ }

return fetch('http://example.org/api/' + url, options)
.then(response => {
.then(async response => {
if (response.status === 204) {

@@ -171,0 +168,0 @@ return { response };

export * from './types';
export { Store } from './store';
export { Model } from './model';
export { Query } from './query';
export * from './store';
export * from './model';
export * from './query';
import { Store } from './store';
import {
JsonApiIdentifier,
JsonApiRelationships,
JsonApiResource, KeyValueObject
} from './types';
import { JsonApiIdentifier, JsonApiRelationships, JsonApiResource, KeyValueObject } from './types';

@@ -16,4 +12,4 @@ export type CastAttributes = {

export class Model implements JsonApiResource {
public type: string;
export class Model<Type extends string = any> implements JsonApiResource<Type> {
public type: Type;
public id: string;

@@ -29,3 +25,3 @@ public attributes: KeyValueObject = {};

constructor(data: JsonApiResource, protected store: Store) {
constructor(data: JsonApiResource<Type>, protected store: Store) {
this.merge(data);

@@ -50,3 +46,5 @@ }

public getRelationship(name: string): any {
return this.store.find(this.relationships[name].data as JsonApiIdentifier);
const data = this.relationships[name].data;
// https://github.com/microsoft/TypeScript/issues/14107
return Array.isArray(data) ? this.store.find(data) : this.store.find(data);
}

@@ -57,3 +55,3 @@

*/
identifier(): JsonApiIdentifier {
identifier(): JsonApiIdentifier<Type> {
return {

@@ -68,5 +66,5 @@ id: this.id,

*/
merge(data: JsonApiResource): void {
merge(data: Partial<JsonApiResource<Type>>): void {
if ('type' in data) {
this.type = data.type;
this.type = data.type as Type;
}

@@ -82,8 +80,14 @@

Object.keys(data.attributes).forEach(name => {
if (! Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this), name)) {
Object.defineProperty(this, name, {
configurable: true,
get: () => this.getAttribute(name),
});
}
if (
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this), name)
|| Object.getOwnPropertyDescriptor(this, name)
) return;
this[name] = null;
Object.defineProperty(this, name, {
get: () => this.getAttribute(name),
configurable: true,
enumerable: true,
});
});

@@ -93,3 +97,3 @@ }

if ('relationships' in data) {
for (const [name, relationship] of Object.entries(data.relationships)) {
Object.entries(data.relationships).forEach(([name, relationship]) => {
this.relationships[name] = this.relationships[name] || {};

@@ -99,9 +103,15 @@

if (! Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this), name)) {
Object.defineProperty(this, name, {
configurable: true,
get: () => this.getRelationship(name),
});
}
}
if (
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this), name)
|| Object.getOwnPropertyDescriptor(this, name)
) return;
this[name] = null;
Object.defineProperty(this, name, {
get: () => this.getRelationship(name),
configurable: true,
enumerable: true,
});
});
}

@@ -108,0 +118,0 @@

import { Model } from './model';
import {
JsonApiDocument,
JsonApiIdentifier,
JsonApiResource,
} from './types';
import { JsonApiDocument, JsonApiIdentifier, JsonApiResource } from './types';
interface Graph {
type Graph = {
[type: string]: {
[id: string]: Model;
[id: string]: any;
};
}
};
type ModelConstructor = { new(data: JsonApiResource, store?: Store): Model };
export type ModelConstructor<Type extends string> = {
new(data: JsonApiResource<Type>, store: Store): Model<Type>;
};
interface ModelCollection {
[type: string]: ModelConstructor;
}
export type ModelCollection<Models> = { [Type in keyof Models & string]: ModelConstructor<Type> } & { '*'?: ModelConstructor<any> };
export class Store {
export type ModelForType<Type extends string, Models extends ModelCollection<Models>> = Type extends keyof Models ? InstanceType<Models[Type]> : Model;
export class Store<Models extends ModelCollection<Models> = any> {
protected graph: Graph = {};
public constructor(public models: ModelCollection = {}) {}
public constructor(public models: Models = {} as Models) {}
public model(type: string, model: ModelConstructor): void {
this.models[type] = model;
}
public find(identifier: JsonApiIdentifier): Model;
public find(identifiers: JsonApiIdentifier[]): Model[];
public find(type: string, id: string): Model;
public find(a: JsonApiIdentifier | JsonApiIdentifier[] | string, b?: string) {
public find<Type extends string>(identifier: JsonApiIdentifier<Type>): ModelForType<Type, Models> | null;
public find<Type extends string>(identifiers: JsonApiIdentifier<Type>[]): ModelForType<Type, Models>[];
public find<Type extends string>(type: Type, id: string): ModelForType<Type, Models> | null;
public find<Type extends string>(a: JsonApiIdentifier<Type> | JsonApiIdentifier<Type>[] | string, b?: string) {
if (a === null) {

@@ -38,3 +32,3 @@ return null;

if (Array.isArray(a)) {
return a.map((identifier: JsonApiIdentifier) => this.find(identifier));
return a.map((identifier: JsonApiIdentifier<Type>) => this.find(identifier));
}

@@ -49,3 +43,3 @@

public findAll(type: string): Model[] {
public findAll<Type extends string>(type: Type): ModelForType<Type, Models>[] {
if (! this.graph[type]) {

@@ -59,3 +53,3 @@ return [];

public sync(document: JsonApiDocument): Model | Model[] {
public sync<Type extends string>(document: JsonApiDocument<Type>): ModelForType<Type, Models> | ModelForType<Type, Models>[] | null {
const syncResource = this.syncResource.bind(this);

@@ -67,6 +61,8 @@

return Array.isArray(document.data) ? document.data.map(syncResource) : syncResource(document.data);
return Array.isArray(document.data)
? document.data.map(syncResource)
: syncResource(document.data);
}
public syncResource(data: JsonApiIdentifier): Model {
public syncResource<Type extends string>(data: JsonApiResource<Type>): ModelForType<Type, Models> {
const { type, id } = data;

@@ -85,6 +81,6 @@

private createModel(data: JsonApiIdentifier): Model {
const ModelClass = this.models[data.type] || this.models['*'] || Model;
protected createModel<Type extends string>(data: JsonApiResource<Type>): ModelForType<Type, Models> {
const ModelClass = this.models[data.type as keyof Models] || this.models['*'] || Model;
return new ModelClass(data, this);
return new ModelClass(data, this) as ModelForType<Type, Models>;
}

@@ -91,0 +87,0 @@

@@ -5,4 +5,4 @@ export type KeyValueObject = {

export interface JsonApiDocument {
data: JsonApiResource | JsonApiResource[];
export interface JsonApiDocument<Type extends string = string> {
data: JsonApiResource<Type> | JsonApiResource<Type>[];
included?: JsonApiResource[];

@@ -13,8 +13,8 @@ meta?: KeyValueObject;

export interface JsonApiIdentifier {
type: string;
export interface JsonApiIdentifier<Type extends string = string> {
type: Type;
id: string;
}
export interface JsonApiResource extends JsonApiIdentifier {
export interface JsonApiResource<Type extends string = string> extends JsonApiIdentifier<Type> {
attributes?: KeyValueObject;

@@ -30,6 +30,14 @@ relationships?: JsonApiRelationships;

export interface JsonApiRelationship {
data?: JsonApiIdentifier | JsonApiIdentifier[];
export interface JsonApiRelationship<Type extends string = string> {
data?: JsonApiIdentifier<Type> | JsonApiIdentifier<Type>[] | null;
meta?: KeyValueObject;
links?: KeyValueObject;
}
export interface JsonApiRelationshipToOne<Type extends string = string> extends JsonApiRelationship<Type> {
data?: JsonApiIdentifier<Type> | null;
}
export interface JsonApiRelationshipToMany<Type extends string = string> extends JsonApiRelationship<Type> {
data?: JsonApiIdentifier<Type>[];
}