Join our webinar on Wednesday, June 26, at 1pm EDTHow Chia Mitigates Risk in the Crypto Industry.Register
Socket
Socket
Sign inDemoInstall

ts-japi

Package Overview
Dependencies
0
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.5.1 to 1.6.0

.prettierrc

64

benchmarks/playground.benchmark.ts

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

import Benchmark from "benchmark";
import Benchmark from 'benchmark';

@@ -6,6 +6,6 @@ const suite = new Benchmark.Suite();

const a: any = new Map();
a.set("test", "test");
a.set('test', 'test');
const b: any = {};
b.test = "test";
b.test = 'test';

@@ -18,4 +18,4 @@ var length = 100; // user defined length

for (var i = 0; i < length; i++) {
array.push(i);
map.set(i, 0);
array.push(i);
map.set(i, 0);
}

@@ -26,28 +26,28 @@ const tobepushed = [1, 2, 3];

suite
.add("Array#ForOf", async function () {
const g = [];
for (const test of array) {
g.push(test);
}
})
.add("Array#index", async function () {
const g = [];
for (let i = 0, len = array.length; i < len; i++) {
g.push(array[i]);
}
})
.add("Array#indexWithTemp", async function () {
const g = [];
for (let i = 0, temp = array[i]; i < array.length; temp = array[++i]) {
g.push(temp);
}
})
// add listeners
.on("cycle", function (event: any) {
console.log(String(event.target));
})
.on("complete", function (this: any) {
console.log("Fastest is " + this.filter("fastest").map("name"));
})
// run async
.run({ async: true });
.add('Array#ForOf', async function () {
const g = [];
for (const test of array) {
g.push(test);
}
})
.add('Array#index', async function () {
const g = [];
for (let i = 0, len = array.length; i < len; i++) {
g.push(array[i]);
}
})
.add('Array#indexWithTemp', async function () {
const g = [];
for (let i = 0, temp = array[i]; i < array.length; temp = array[++i]) {
g.push(temp);
}
})
// add listeners
.on('cycle', function (event: any) {
console.log(String(event.target));
})
.on('complete', function (this: any) {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
// run async
.run({ async: true });

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

import Benchmark from "benchmark";
import { Relator, Serializer } from "../src";
import { Article, Comment, User } from "../test/models";
import Benchmark from 'benchmark';
import { Relator, Serializer } from '../src';
import { Article, Comment, User } from '../test/models';

@@ -8,27 +8,27 @@ const suite = new Benchmark.Suite();

for (let i = 0; i < 5; i++) {
User.save(new User(String(i)));
User.save(new User(String(i)));
}
for (let i = 0; i < 5; i++) {
Article.save(new Article(String(i), User.storage[0]));
Article.save(new Article(String(i), User.storage[0]));
}
for (let i = 0; i < 10; i++) {
Comment.save(new Comment(String(i), User.storage[0], Article.storage[0]));
Comment.save(new Comment(String(i), User.storage[0], Article.storage[0]));
}
let UserSerializer = new Serializer<User>("users", {
depth: 0, // Change to 2 to see the difference
cache: true
let UserSerializer = new Serializer<User>('users', {
depth: 0, // Change to 2 to see the difference
cache: true,
});
let CommentSerializer = new Serializer<Comment>("comments");
let ArticleSerializer = new Serializer<Article>("articles");
let CommentSerializer = new Serializer<Comment>('comments');
let ArticleSerializer = new Serializer<Article>('articles');
const UserArticleRelator = new Relator<User, Article>(
async (user: User) => user.getArticles(),
ArticleSerializer
async (user: User) => user.getArticles(),
ArticleSerializer
);
const ArticleCommentRelator = new Relator<Article, Comment>(
async (article: Article) => article.getComments(),
CommentSerializer
async (article: Article) => article.getComments(),
CommentSerializer
);
const CommentUserRelator = new Relator<Comment, User>(
async (comment: Comment) => comment.getAuthor(),
UserSerializer
async (comment: Comment) => comment.getAuthor(),
UserSerializer
);

@@ -43,13 +43,13 @@ CommentSerializer.setRelators(CommentUserRelator);

suite
.add("Serializer#Test", async function () {
await UserSerializer.serialize(user);
})
// add listeners
.on("cycle", function (event: any) {
console.log(String(event.target));
})
.on("complete", function (this: any) {
console.log("Fastest is " + this.filter("fastest").map("name"));
})
// run async
.run({ async: true });
.add('Serializer#Test', async function () {
await UserSerializer.serialize(user);
})
// add listeners
.on('cycle', function (event: any) {
console.log(String(event.target));
})
.on('complete', function (this: any) {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
// run async
.run({ async: true });
# Changelog
## 1.6.0
### Minor Changes
- bd4c358: Add `relatorDataCache` in serialize method to avoid duplicate lookups during
`recurseRelators` call
## 1.5.1

@@ -26,4 +33,8 @@

- Added an `isErrorDocument` function to detect JSON:API Error documents. This function allows you to treat the argument _as if it were an error document_ (there is obviously no way to know if it really is a JSON:API error document at runtime).
- Added an `isLikeJapiError` function to detect JSON:API Error. This function allows you to treat the argument _as if it were an JSON:API error_ (there is obviously no way to know if it really is a JSON:API error at runtime).
- Added an `isErrorDocument` function to detect JSON:API Error documents. This function allows you
to treat the argument _as if it were an error document_ (there is obviously no way to know if it
really is a JSON:API error document at runtime).
- Added an `isLikeJapiError` function to detect JSON:API Error. This function allows you to treat
the argument _as if it were an JSON:API error_ (there is obviously no way to know if it really is
a JSON:API error at runtime).

@@ -51,3 +62,4 @@ ### Changed

- Exported interfaces related to JSON:API.
- The Error and Data document interfaces now require the "errors" and "data" properties respectively.
- The Error and Data document interfaces now require the "errors" and "data" properties
respectively.
- The Base document interface has been abstracted further by removing the "meta" property.

@@ -73,4 +85,6 @@ - A _new_ Meta document interface is now available for type-checking.

- A new `Cache` class is now available to use for caching. You can set this in the `cache` option for a `Serializer` (use `true` if you want the built in cache).
- With caching, there is a ~586% speed improvement (412,768 ops/sec over the previous 70,435 ops/sec). Without-caching rates have stayed the same.
- A new `Cache` class is now available to use for caching. You can set this in the `cache` option
for a `Serializer` (use `true` if you want the built in cache).
- With caching, there is a ~586% speed improvement (412,768 ops/sec over the previous 70,435
ops/sec). Without-caching rates have stayed the same.

@@ -85,7 +99,11 @@ ## [1.2.1] - 2020-05-27

So, `ts-japi` has only been released a few days, but after some significant use in my APIs, I have realized a few things:
So, `ts-japi` has only been released a few days, but after some significant use in my APIs, I have
realized a few things:
1. Linkers and certain classes should be allowed to parse `nullish` data (`nullish` meaning `undefined` or `null`).
2. The `relationships object` should be allowed to have custom keys, not dependent on the `relators` options
- `Relator`s should always have a `Serializer`; otherwise, they wouldn't relate to any `resource` per se.
1. Linkers and certain classes should be allowed to parse `nullish` data (`nullish` meaning
`undefined` or `null`).
2. The `relationships object` should be allowed to have custom keys, not dependent on the `relators`
options
- `Relator`s should always have a `Serializer`; otherwise, they wouldn't relate to any `resource`
per se.
3. Projections should be "choose included" or "choose excluded" similar to MongoDB's.

@@ -98,5 +116,10 @@ 4. The code can be faster.

- **[Breaking Change]** Every relator must define a `Serializer` as the second argument in its constructor (as opposed to the relator's options. Options can go in the third argument.
- It may be subtle, but the reason for this lies in the fact `relationships object` must be keyed by the related object. If the relator has no serializer, then the relator has no related name, hence there is no canonical way to key the relationship.
- We will now allow objects of relators to be defined as an option for `relators` on `Serializer`s. By using objects, the key for the relationship generated by the relator will correspond to the same key for that of the relator's.
- **[Breaking Change]** Every relator must define a `Serializer` as the second argument in its
constructor (as opposed to the relator's options. Options can go in the third argument.
- It may be subtle, but the reason for this lies in the fact `relationships object` must be keyed
by the related object. If the relator has no serializer, then the relator has no related name,
hence there is no canonical way to key the relationship.
- We will now allow objects of relators to be defined as an option for `relators` on
`Serializer`s. By using objects, the key for the relationship generated by the relator will
correspond to the same key for that of the relator's.
- Several functional options now allow for `nullish` (`null` or `undefined`) arguments:

@@ -106,4 +129,6 @@ - Resource Linkers can now type-safely use `nullish` arguments.

- Several plain options now allow for `nullish` (`null` or `undefined`):
- Serializer `projection` option has changed significantly (see the option itself) with `nullish` values.
- There is a ~33% speed improvement. (70,435 ops/sec over 52,843 ops/sec on a low-end Macbook Pro 15")
- Serializer `projection` option has changed significantly (see the option itself) with `nullish`
values.
- There is a ~33% speed improvement. (70,435 ops/sec over 52,843 ops/sec on a low-end Macbook Pro
15")

@@ -116,2 +141,5 @@ ### Added

I want to say this IS unusual to have a breaking change without depreciation, but given the fact this package is only a few days old, I want to apologize if you are bothered by the above break. However, I will guarantee that API changes will go through depreciation before removal, so happy coding :)
I want to say this IS unusual to have a breaking change without depreciation, but given the fact
this package is only a few days old, I want to apologize if you are bothered by the above break.
However, I will guarantee that API changes will go through depreciation before removal, so happy
coding :)

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

import { SerializerOptions } from "../interfaces/serializer.interface";
import { DataDocument } from "../interfaces/json-api.interface";
import { SingleOrArray, nullish } from "../types/global.types";
import { CacheOptions } from "../interfaces/cache.interface";
import { SerializerOptions } from '../interfaces/serializer.interface';
import { DataDocument } from '../interfaces/json-api.interface';
import { SingleOrArray, nullish } from '../types/global.types';
import { CacheOptions } from '../interfaces/cache.interface';
export default class Cache<PrimaryType> {

@@ -6,0 +6,0 @@ /**

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

import { ErrorSerializerOptions } from "../interfaces/error-serializer.interface";
import { ErrorDocument } from "../interfaces/json-api.interface";
import { SingleOrArray } from "../types/global.types";
import { ErrorSerializerOptions } from '../interfaces/error-serializer.interface';
import { ErrorDocument } from '../interfaces/json-api.interface';
import { SingleOrArray } from '../types/global.types';
/**

@@ -5,0 +5,0 @@ * The {@linkcode ErrorSerializer} class is used to serialize errors.

@@ -182,11 +182,11 @@ "use strict";

ErrorSerializer.defaultOptions = {
version: "1.0",
version: '1.0',
attributes: {
id: "id",
status: "code",
code: "name",
title: "reason",
detail: "message",
id: 'id',
status: 'code',
code: 'name',
title: 'reason',
detail: 'message',
source: {
pointer: "location",
pointer: 'location',
parameter: undefined

@@ -193,0 +193,0 @@ }

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

import { LinkerOptions } from "../interfaces/linker.interface";
import Link from "../models/link.model";
import { VariadicFunction } from "../types/global.types";
import { LinkerOptions } from '../interfaces/linker.interface';
import Link from '../models/link.model';
import { VariadicFunction } from '../types/global.types';
/**

@@ -5,0 +5,0 @@ * The {@linkcode Linker} class is used to construct a [link](https://jsonapi.org/format/#document-links).

@@ -18,5 +18,6 @@ "use strict";

};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};

@@ -52,4 +53,4 @@ var __importDefault = (this && this.__importDefault) || function (mod) {

return options.metaizer
? new link_model_1["default"](link.apply(void 0, __spread(datas)), (_a = options.metaizer).metaize.apply(_a, __spread(datas)))
: new link_model_1["default"](link.apply(void 0, __spread(datas)));
? new link_model_1["default"](link.apply(void 0, __spreadArray([], __read(datas))), (_a = options.metaizer).metaize.apply(_a, __spreadArray([], __read(datas))))
: new link_model_1["default"](link.apply(void 0, __spreadArray([], __read(datas))));
};

@@ -56,0 +57,0 @@ }

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

import Meta from "../models/meta.model";
import { Dictionary, VariadicFunction } from "../types/global.types";
import Meta from '../models/meta.model';
import { Dictionary, VariadicFunction } from '../types/global.types';
/**

@@ -4,0 +4,0 @@ * The {@linkcode Metaizer} class is used to construct [meta information](https://jsonapi.org/format/#document-meta).

@@ -18,5 +18,6 @@ "use strict";

};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};

@@ -49,3 +50,3 @@ var __importDefault = (this && this.__importDefault) || function (mod) {

}
return new meta_model_1["default"](metaize.apply(void 0, __spread(datas)));
return new meta_model_1["default"](metaize.apply(void 0, __spreadArray([], __read(datas))));
};

@@ -52,0 +53,0 @@ }

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

import { PaginationOf } from "../interfaces/paginator.interface";
import Link from "../models/link.model";
import { SingleOrArray } from "../types/global.types";
import { PaginationOf } from '../interfaces/paginator.interface';
import Link from '../models/link.model';
import { SingleOrArray } from '../types/global.types';
/**

@@ -5,0 +5,0 @@ * The {@linkcode Paginator} class is used to construct [pagination links](https://jsonapi.org/format/#fetching-pagination).

@@ -27,6 +27,6 @@ "use strict";

return {
first: typeof links.first === "string" ? new link_model_1["default"](links.first) : links.first,
last: typeof links.last === "string" ? new link_model_1["default"](links.last) : links.last,
prev: typeof links.prev === "string" ? new link_model_1["default"](links.prev) : links.prev,
next: typeof links.next === "string" ? new link_model_1["default"](links.next) : links.next
first: typeof links.first === 'string' ? new link_model_1["default"](links.first) : links.first,
last: typeof links.last === 'string' ? new link_model_1["default"](links.last) : links.last,
prev: typeof links.prev === 'string' ? new link_model_1["default"](links.prev) : links.prev,
next: typeof links.next === 'string' ? new link_model_1["default"](links.next) : links.next
};

@@ -33,0 +33,0 @@ };

@@ -1,10 +0,11 @@

import { RelatorOptions } from "../interfaces/relator.interface";
import { SerializerOptions } from "../interfaces/serializer.interface";
import Link from "../models/link.model";
import Meta from "../models/meta.model";
import Relationship from "../models/relationship.model";
import ResourceIdentifier from "../models/resource-identifier.model";
import Resource from "../models/resource.model";
import { Dictionary, nullish } from "../types/global.types";
import Serializer from "./serializer";
import { RelatorOptions } from '../interfaces/relator.interface';
import { SerializerOptions } from '../interfaces/serializer.interface';
import Link from '../models/link.model';
import Meta from '../models/meta.model';
import Relationship from '../models/relationship.model';
import ResourceIdentifier from '../models/resource-identifier.model';
import Resource from '../models/resource.model';
import { Dictionary, nullish } from '../types/global.types';
import { Helpers } from '../utils/serializer.utils';
import Serializer from './serializer';
/**

@@ -46,10 +47,10 @@ * The {@linkcode Relator} class is used to generate top-level [included data](https://jsonapi.org/format/#document-top-level)

/** @internal Creates related resources */
getRelatedResource: (data: RelatedType, options?: SerializerOptions<RelatedType>) => Promise<Resource<RelatedType>>;
getRelatedResource: (data: RelatedType, options?: SerializerOptions<RelatedType>, helpers?: Helpers<RelatedType>, relatorDataCache?: Map<Relator<any>, Dictionary<any>[]>) => Promise<Resource<RelatedType>>;
/** @internal Gets related links from primary data and related data */
getRelatedLinks(data: PrimaryType, relatedData: RelatedType | RelatedType[] | nullish): Record<string | number | symbol, Link | null | undefined> | undefined;
getRelatedLinks(data: PrimaryType, relatedData: RelatedType | RelatedType[] | nullish): Dictionary<nullish | Link> | undefined;
/** @internal Gets related meta from primary data and related data */
getRelatedMeta(data: PrimaryType, relatedData: RelatedType | RelatedType[] | nullish): Meta | undefined;
/** @internal Creates a {@linkcode Relationship}. */
getRelationship(data: PrimaryType): Promise<Relationship>;
getRelationship(data: PrimaryType, relatedDataCache?: Dictionary<any>[]): Promise<Relationship>;
}
//# sourceMappingURL=relator.d.ts.map

@@ -49,2 +49,23 @@ "use strict";

};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -103,3 +124,3 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

/** @internal Creates a {@linkcode Relationship}. */
Relator.prototype.getRelationship = function (data) {
Relator.prototype.getRelationship = function (data, relatedDataCache) {
return __awaiter(this, void 0, void 0, function () {

@@ -115,2 +136,5 @@ var relationshipOptions, relatedData, links, meta;

relatedData = _a.sent();
if (relatedData && relatedDataCache) {
relatedDataCache.push.apply(relatedDataCache, __spreadArray([], __read((Array.isArray(relatedData) ? relatedData : [relatedData]))));
}
links = this.getRelatedLinks(data, relatedData);

@@ -117,0 +141,0 @@ if (links)

@@ -1,8 +0,9 @@

import { DataDocument } from "../interfaces/json-api.interface";
import { SerializerOptions } from "../interfaces/serializer.interface";
import ResourceIdentifier from "../models/resource-identifier.model";
import Resource from "../models/resource.model";
import { Dictionary, nullish, SingleOrArray } from "../types/global.types";
import { Helpers } from "../utils/serializer.utils";
import Cache from "./cache";
import { DataDocument } from '../interfaces/json-api.interface';
import { SerializerOptions } from '../interfaces/serializer.interface';
import ResourceIdentifier from '../models/resource-identifier.model';
import Resource from '../models/resource.model';
import { Dictionary, nullish, SingleOrArray } from '../types/global.types';
import { Helpers } from '../utils/serializer.utils';
import Cache from './cache';
import Relator from './relator';
/**

@@ -60,11 +61,11 @@ * The {@linkcode Serializer} class is the main class used to serializer data

*/
getRelators(): Record<string, import("./relator").default<PrimaryType, any>> | undefined;
getRelators(): Record<string, Relator<PrimaryType, any>> | undefined;
/**
* Sets the {@linkcode Relator}s associated with this serializer
*/
setRelators(relators: SerializerOptions<PrimaryType>["relators"]): void;
setRelators(relators: SerializerOptions<PrimaryType>['relators']): void;
/** @internal Generates a `ResourceIdentifier`. */
createIdentifier(data: PrimaryType, options?: SerializerOptions<PrimaryType>): ResourceIdentifier;
/** @internal Generates a `Resource`. */
createResource(data: PrimaryType, options?: SerializerOptions<PrimaryType>, helpers?: Helpers<PrimaryType>): Promise<Resource<PrimaryType>>;
createResource(data: PrimaryType, options?: SerializerOptions<PrimaryType>, helpers?: Helpers<PrimaryType>, relatorDataCache?: Map<Relator<any>, Dictionary<any>[]>): Promise<Resource<PrimaryType>>;
/**

@@ -71,0 +72,0 @@ * The actual serialization function.

@@ -130,3 +130,3 @@ "use strict";

/** @internal Generates a `Resource`. */
Serializer.prototype.createResource = function (data, options, helpers) {
Serializer.prototype.createResource = function (data, options, helpers, relatorDataCache) {
return __awaiter(this, void 0, void 0, function () {

@@ -153,9 +153,13 @@ var resourceOptions, id, type, relationships_1;

return __awaiter(_this, void 0, void 0, function () {
var _c, _d;
var relatedDataCache, _c, _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
if (relatorDataCache) {
relatedDataCache = relatorDataCache.get(relator) || [];
relatorDataCache.set(relator, relatedDataCache);
}
_c = relationships_1;
_d = name;
return [4 /*yield*/, relator.getRelationship(data)];
return [4 /*yield*/, relator.getRelationship(data, relatedDataCache)];
case 1:

@@ -193,3 +197,3 @@ _c[_d] = _e.sent();

return __awaiter(this, void 0, void 0, function () {
var o, h, cache, storedDocument, document, keys, wasSingle, dto, createIdentifier, createResource, relators, relator_1, relatedData, links, meta, pagination, _a, _b, _c, _d, _e;
var o, h, cache, storedDocument, document, relatorDataCache, keys, wasSingle, dto, createIdentifier, createResource, relators, relator_1, relatedData, links, meta, pagination, _a, _b, _c, _d, _e;
var _this = this;

@@ -220,2 +224,3 @@ return __generator(this, function (_f) {

}
relatorDataCache = new Map();
keys = [];

@@ -281,3 +286,3 @@ wasSingle = false;

switch (_a.label) {
case 0: return [4 /*yield*/, this.createResource(datum, o, h)];
case 0: return [4 /*yield*/, this.createResource(datum, o, h, relatorDataCache)];
case 1:

@@ -327,3 +332,3 @@ resource = _a.sent();

_e = (_d = (document.included || [])).concat;
return [4 /*yield*/, serializer_utils_1.recurseRelators(dto, relators, o.depth, keys)];
return [4 /*yield*/, serializer_utils_1.recurseRelators(dto, relators, o.depth, keys, relatorDataCache)];
case 8:

@@ -345,4 +350,4 @@ _c.included = _e.apply(_d, [_f.sent()]);

Serializer.defaultOptions = {
idKey: "id",
version: "1.0",
idKey: 'id',
version: '1.0',
onlyIdentifier: false,

@@ -349,0 +354,0 @@ nullData: false,

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

export { default as Cache } from "./classes/cache";
export { default as Linker } from "./classes/linker";
export { default as Metaizer } from "./classes/metaizer";
export { default as Paginator } from "./classes/paginator";
export { default as Relator } from "./classes/relator";
export { default as JapiError } from "./models/error.model";
export { default as ErrorSerializer } from "./classes/error-serializer";
export { default as Serializer } from "./classes/serializer";
export * from "./interfaces/cache.interface";
export * from "./interfaces/error-serializer.interface";
export * from "./interfaces/error.interface";
export * from "./interfaces/json-api.interface";
export * from "./interfaces/linker.interface";
export * from "./interfaces/paginator.interface";
export * from "./interfaces/relator.interface";
export * from "./interfaces/serializer.interface";
export * from "./types/global.types";
export * from "./utils/is-error-document";
export * from "./utils/is-plain-object";
export * from "./utils/is-object";
export { default as Cache } from './classes/cache';
export { default as Linker } from './classes/linker';
export { default as Metaizer } from './classes/metaizer';
export { default as Paginator } from './classes/paginator';
export { default as Relator } from './classes/relator';
export { default as JapiError } from './models/error.model';
export { default as ErrorSerializer } from './classes/error-serializer';
export { default as Serializer } from './classes/serializer';
export * from './interfaces/cache.interface';
export * from './interfaces/error-serializer.interface';
export * from './interfaces/error.interface';
export * from './interfaces/json-api.interface';
export * from './interfaces/linker.interface';
export * from './interfaces/paginator.interface';
export * from './interfaces/relator.interface';
export * from './interfaces/serializer.interface';
export * from './types/global.types';
export * from './utils/is-error-document';
export * from './utils/is-plain-object';
export * from './utils/is-object';
//# sourceMappingURL=index.d.ts.map

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

import { SingleOrArray, nullish } from "../types/global.types";
import { SingleOrArray, nullish } from '../types/global.types';
export interface CacheOptions<DataType> {

@@ -3,0 +3,0 @@ /**

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

import Linker from "../classes/linker";
import Metaizer from "../classes/metaizer";
import JapiError from "../models/error.model";
import { Dictionary } from "../types/global.types";
import Linker from '../classes/linker';
import Metaizer from '../classes/metaizer';
import JapiError from '../models/error.model';
import { Dictionary } from '../types/global.types';
export interface ErrorAttributeOption<T> {

@@ -6,0 +6,0 @@ /**

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

import JapiError from "../models/error.model";
import Link from "../models/link.model";
import Meta from "../models/meta.model";
import ResourceIdentifier from "../models/resource-identifier.model";
import Resource from "../models/resource.model";
import { Dictionary, SingleOrArray, nullish } from "../types/global.types";
import { PaginationOf } from "./paginator.interface";
import JapiError from '../models/error.model';
import Link from '../models/link.model';
import Meta from '../models/meta.model';
import ResourceIdentifier from '../models/resource-identifier.model';
import Resource from '../models/resource.model';
import { Dictionary, SingleOrArray, nullish } from '../types/global.types';
import { PaginationOf } from './paginator.interface';
export interface DataDocument<PrimaryType extends Dictionary<any>> extends Partial<MetaDocument> {

@@ -9,0 +9,0 @@ links?: Dictionary<Link | nullish> | PaginationOf<Link>;

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

import Metaizer from "../classes/metaizer";
import Metaizer from '../classes/metaizer';
export interface LinkerOptions<Dependencies extends any[]> {

@@ -3,0 +3,0 @@ /**

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

import { nullish } from "../types/global.types";
import { nullish } from '../types/global.types';
export interface PaginationOf<T> {

@@ -3,0 +3,0 @@ first: T | nullish;

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

import Linker from "../classes/linker";
import Metaizer from "../classes/metaizer";
import { Dictionary, nullish, SingleOrArray } from "../types/global.types";
import Linker from '../classes/linker';
import Metaizer from '../classes/metaizer';
import { Dictionary, nullish, SingleOrArray } from '../types/global.types';
export interface RelatorOptions<PrimaryType, RelatedType extends Dictionary<any> = any> {

@@ -5,0 +5,0 @@ /**

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

import Linker from "../classes/linker";
import Metaizer from "../classes/metaizer";
import Paginator from "../classes/paginator";
import Relator from "../classes/relator";
import { Dictionary, SingleOrArray, nullish } from "../types/global.types";
import Cache from "../classes/cache";
import Linker from '../classes/linker';
import Metaizer from '../classes/metaizer';
import Paginator from '../classes/paginator';
import Relator from '../classes/relator';
import { Dictionary, SingleOrArray, nullish } from '../types/global.types';
import Cache from '../classes/cache';
export interface SerializerOptions<PrimaryType extends Dictionary<any> = any> {

@@ -8,0 +8,0 @@ /**

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

import { Dictionary, nullish } from "..";
import { ErrorOptions } from "../interfaces/error.interface";
import Link from "./link.model";
import Meta from "./meta.model";
import { Dictionary, nullish } from '..';
import { ErrorOptions } from '../interfaces/error.interface';
import Link from './link.model';
import Meta from './meta.model';
export default class JapiError {

@@ -6,0 +6,0 @@ /**

@@ -29,6 +29,6 @@ "use strict";

return false;
return (["id", "status", "code", "title", "detail", "source", "links", "meta"].some(function (attrName) { return attrName in error; }) &&
return (['id', 'status', 'code', 'title', 'detail', 'source', 'links', 'meta'].some(function (attrName) { return attrName in error; }) &&
[
["id", "status", "code", "title", "detail"].every(function (attrName) { return !(attrName in error) || typeof error[attrName] === "string"; }),
["source", "links", "meta"].every(function (attrName) { return !(attrName in error) || is_object_1.isObject(error[attrName]); }),
['id', 'status', 'code', 'title', 'detail'].every(function (attrName) { return !(attrName in error) || typeof error[attrName] === 'string'; }),
['source', 'links', 'meta'].every(function (attrName) { return !(attrName in error) || is_object_1.isObject(error[attrName]); }),
].every(function (v) { return v; }));

@@ -35,0 +35,0 @@ };

/// <reference types="node" />
import { URL } from "url";
import Meta from "./meta.model";
import { URL } from 'url';
import Meta from './meta.model';
export default class Link {

@@ -5,0 +5,0 @@ url: URL;

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

import { Dictionary, nullish } from "..";
import { ResourceLinkage } from "../interfaces/json-api.interface";
import Link from "./link.model";
import Meta from "./meta.model";
import { Dictionary, nullish } from '..';
import { ResourceLinkage } from '../interfaces/json-api.interface';
import Link from './link.model';
import Meta from './meta.model';
/** @internal */

@@ -6,0 +6,0 @@ export interface RelationshipOptions {

@@ -6,3 +6,3 @@ "use strict";

// data can be explicitly set to null for empty to-one relationships
if (typeof options.data !== "undefined")
if (typeof options.data !== 'undefined')
this.data = options.data;

@@ -13,4 +13,4 @@ if (options.links)

this.meta = options.meta;
if (typeof options.data === "undefined" && !this.links && !this.meta) {
throw new Error("Relationships must contain at least a link, data, or meta. See https://jsonapi.org/format/#document-resource-object-relationships for more information.");
if (typeof options.data === 'undefined' && !this.links && !this.meta) {
throw new Error('Relationships must contain at least a link, data, or meta. See https://jsonapi.org/format/#document-resource-object-relationships for more information.');
}

@@ -17,0 +17,0 @@ }

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

import Meta from "./meta.model";
import Meta from './meta.model';
/** @internal */

@@ -3,0 +3,0 @@ export interface ResourceIdentifierOptions {

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

import Link from "../models/link.model";
import { Dictionary, nullish } from "../types/global.types";
import Relationship from "./relationship.model";
import ResourceIdentifier, { ResourceIdentifierOptions } from "./resource-identifier.model";
import Link from '../models/link.model';
import { Dictionary, nullish } from '../types/global.types';
import Relationship from './relationship.model';
import ResourceIdentifier, { ResourceIdentifierOptions } from './resource-identifier.model';
/** @internal */

@@ -6,0 +6,0 @@ export interface ResourceOptions<T> extends ResourceIdentifierOptions {

@@ -10,2 +10,4 @@ "use strict";

return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);

@@ -12,0 +14,0 @@ function __() { this.constructor = d; }

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

import { ErrorDocument } from "../interfaces/json-api.interface";
import { ErrorDocument } from '../interfaces/json-api.interface';
/**

@@ -3,0 +3,0 @@ * Detects an `ErrorDocument` like object

@@ -17,3 +17,3 @@ "use strict";

Array.isArray(document.errors) &&
("jsonapi" in document ||
('jsonapi' in document ||
document.errors.every(function (error) {

@@ -20,0 +20,0 @@ return error instanceof error_model_1["default"] ? true : error_model_1["default"].isLikeJapiError(error);

@@ -5,5 +5,5 @@ "use strict";

function isObject(o) {
return typeof o === "object" && Object.prototype.toString.call(o) === "[object Object]";
return typeof o === 'object' && Object.prototype.toString.call(o) === '[object Object]';
}
exports.isObject = isObject;
//# sourceMappingURL=is-object.js.map

@@ -9,3 +9,3 @@ "use strict";

// If constructor was modified
if (typeof o.constructor !== "function")
if (typeof o.constructor !== 'function')
return false;

@@ -16,3 +16,3 @@ // If prototype was modified

// eslint-disable-next-line no-prototype-builtins
if (!o.constructor.prototype.hasOwnProperty("isPrototypeOf"))
if (!o.constructor.prototype.hasOwnProperty('isPrototypeOf'))
return false;

@@ -19,0 +19,0 @@ return true;

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

import { Dictionary, UnionToIntersection } from "../types/global.types";
import { Dictionary, UnionToIntersection } from '../types/global.types';
/**

@@ -3,0 +3,0 @@ * Deep merge two objects over their enumerable properties.

@@ -29,5 +29,6 @@ "use strict";

};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};

@@ -73,5 +74,5 @@ exports.__esModule = true;

}
return merge.apply(void 0, __spread([target], sources));
return merge.apply(void 0, __spreadArray([target], __read(sources)));
}
exports["default"] = merge;
//# sourceMappingURL=merge.js.map

@@ -1,5 +0,6 @@

import Relator from "../classes/relator";
import { SerializerOptions } from "../interfaces/serializer.interface";
export declare function recurseRelators(data: any[], relators: Record<string, Relator<any>>, depth: number, keys: string[]): Promise<any[]>;
export declare function normalizeRelators<T>(relators: SerializerOptions<T>["relators"]): Record<string, Relator<T, any>> | undefined;
import Relator from '../classes/relator';
import { SerializerOptions } from '../interfaces/serializer.interface';
import { Dictionary } from '../types/global.types';
export declare function recurseRelators(data: any[], relators: Record<string, Relator<any>>, depth: number, keys: string[], relatorDataCache?: Map<Relator<any>, Dictionary<any>[]>): Promise<any[]>;
export declare function normalizeRelators<T>(relators: SerializerOptions<T>['relators']): Record<string, Relator<T, any>> | undefined;
export declare class Helpers<PrimaryType> {

@@ -6,0 +7,0 @@ projectAttributes: (data: PrimaryType) => Partial<PrimaryType> | undefined;

@@ -38,2 +38,13 @@ "use strict";

};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __read = (this && this.__read) || function (o, n) {

@@ -55,12 +66,6 @@ var m = typeof Symbol === "function" && o[Symbol.iterator];

};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};

@@ -73,69 +78,99 @@ var __importDefault = (this && this.__importDefault) || function (mod) {

var relator_1 = __importDefault(require("../classes/relator"));
function recurseRelators(data, relators, depth, keys) {
function recurseRelators(data, relators, depth, keys, relatorDataCache) {
return __awaiter(this, void 0, void 0, function () {
var included, queue, _a, data_1, relators_1, _loop_1, i, len;
var _this = this;
return __generator(this, function (_b) {
switch (_b.label) {
var included, curRelatorDataCache, _a, _b, _i, name_1, cache, data_1, data_1_1, datum, relatedData, e_1_1, newRelatorDataCache, curRelatorDataCache_1, curRelatorDataCache_1_1, _c, relator, cache, i, resource, key, e_2_1;
var e_1, _d, e_2, _e;
return __generator(this, function (_f) {
switch (_f.label) {
case 0:
included = [];
queue = [[data, Object.values(relators)]];
console.log(data);
_b.label = 1;
curRelatorDataCache = relatorDataCache || new Map();
if (!(!relatorDataCache && depth > 0)) return [3 /*break*/, 10];
_a = [];
for (_b in relators)
_a.push(_b);
_i = 0;
_f.label = 1;
case 1:
if (!(queue.length > 0 && depth-- > 0)) return [3 /*break*/, 6];
_a = __read(queue.shift(), 2), data_1 = _a[0], relators_1 = _a[1];
_loop_1 = function (i, len) {
var relator, relatedData, newRelators, newData;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
relator = relators_1[i];
return [4 /*yield*/, Promise.all(data_1.map(relator.getRelatedData))];
case 1:
relatedData = _a.sent();
newRelators = relator.getRelatedRelators();
newData = [];
return [4 /*yield*/, Promise.all(relatedData
.flat()
.filter(function (d) { return d !== null; })
.map(function (datum) { return __awaiter(_this, void 0, void 0, function () {
var resource, key;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, relator.getRelatedResource(datum)];
case 1:
resource = _a.sent();
key = resource.getKey();
if (!keys.includes(key)) {
keys.push(key);
included.push(resource);
newData.push(datum);
}
return [2 /*return*/];
}
});
}); }))];
case 2:
_a.sent();
if (newData.length > 0 && newRelators) {
queue.push([newData, Object.values(newRelators)]);
}
return [2 /*return*/];
}
});
};
i = 0, len = relators_1.length;
_b.label = 2;
if (!(_i < _a.length)) return [3 /*break*/, 10];
name_1 = _a[_i];
cache = curRelatorDataCache.get(relators[name_1]) || [];
curRelatorDataCache.set(relators[name_1], cache);
_f.label = 2;
case 2:
if (!(i < len)) return [3 /*break*/, 5];
return [5 /*yield**/, _loop_1(i, len)];
_f.trys.push([2, 7, 8, 9]);
data_1 = (e_1 = void 0, __values(data)), data_1_1 = data_1.next();
_f.label = 3;
case 3:
_b.sent();
_b.label = 4;
if (!!data_1_1.done) return [3 /*break*/, 6];
datum = data_1_1.value;
return [4 /*yield*/, relators[name_1].getRelatedData(datum)];
case 4:
relatedData = _f.sent();
if (relatedData !== null) {
cache.push.apply(cache, __spreadArray([], __read((Array.isArray(relatedData) ? relatedData : [relatedData]))));
}
_f.label = 5;
case 5:
data_1_1 = data_1.next();
return [3 /*break*/, 3];
case 6: return [3 /*break*/, 9];
case 7:
e_1_1 = _f.sent();
e_1 = { error: e_1_1 };
return [3 /*break*/, 9];
case 8:
try {
if (data_1_1 && !data_1_1.done && (_d = data_1["return"])) _d.call(data_1);
}
finally { if (e_1) throw e_1.error; }
return [7 /*endfinally*/];
case 9:
_i++;
return [3 /*break*/, 1];
case 10:
if (!(depth-- > 0 && curRelatorDataCache.size > 0)) return [3 /*break*/, 21];
newRelatorDataCache = new Map();
_f.label = 11;
case 11:
_f.trys.push([11, 18, 19, 20]);
curRelatorDataCache_1 = (e_2 = void 0, __values(curRelatorDataCache)), curRelatorDataCache_1_1 = curRelatorDataCache_1.next();
_f.label = 12;
case 12:
if (!!curRelatorDataCache_1_1.done) return [3 /*break*/, 17];
_c = __read(curRelatorDataCache_1_1.value, 2), relator = _c[0], cache = _c[1];
i = 0;
_f.label = 13;
case 13:
if (!(i < cache.length)) return [3 /*break*/, 16];
return [4 /*yield*/, relator.getRelatedResource(cache[i], undefined, undefined, newRelatorDataCache)];
case 14:
resource = _f.sent();
key = resource.getKey();
if (!keys.includes(key)) {
keys.push(key);
included.push(resource);
}
_f.label = 15;
case 15:
i++;
return [3 /*break*/, 2];
case 5: return [3 /*break*/, 1];
case 6: return [2 /*return*/, included];
return [3 /*break*/, 13];
case 16:
curRelatorDataCache_1_1 = curRelatorDataCache_1.next();
return [3 /*break*/, 12];
case 17: return [3 /*break*/, 20];
case 18:
e_2_1 = _f.sent();
e_2 = { error: e_2_1 };
return [3 /*break*/, 20];
case 19:
try {
if (curRelatorDataCache_1_1 && !curRelatorDataCache_1_1.done && (_e = curRelatorDataCache_1["return"])) _e.call(curRelatorDataCache_1);
}
finally { if (e_2) throw e_2.error; }
return [7 /*endfinally*/];
case 20:
curRelatorDataCache = newRelatorDataCache;
return [3 /*break*/, 10];
case 21: return [2 /*return*/, included];
}

@@ -147,3 +182,3 @@ });

function normalizeRelators(relators) {
var e_1, _a;
var e_3, _a;
var normalizedRelators = {};

@@ -157,13 +192,13 @@ if (relators) {

try {
for (var relators_2 = __values(relators), relators_2_1 = relators_2.next(); !relators_2_1.done; relators_2_1 = relators_2.next()) {
var relator = relators_2_1.value;
for (var relators_1 = __values(relators), relators_1_1 = relators_1.next(); !relators_1_1.done; relators_1_1 = relators_1.next()) {
var relator = relators_1_1.value;
normalizedRelators[relator.relatedName] = relator;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (relators_2_1 && !relators_2_1.done && (_a = relators_2["return"])) _a.call(relators_2);
if (relators_1_1 && !relators_1_1.done && (_a = relators_1["return"])) _a.call(relators_1);
}
finally { if (e_1) throw e_1.error; }
finally { if (e_3) throw e_3.error; }
}

@@ -170,0 +205,0 @@ return normalizedRelators;

{
"name": "ts-japi",
"version": "1.5.1",
"version": "1.6.0",
"description": "A highly-modular (typescript-friendly)-framework agnostic library for serializing data to the JSON:API specification",

@@ -10,15 +10,5 @@ "main": "lib/index.js",

"playground": "ts-node ./benchmarks/playground.benchmark",
"build-docs": "npm run clean-docs && typedoc && rsync -a ./src/docs/assets ./docs",
"build-readme": "npm run clean-readme && typedoc --plugin typedoc-plugin-markdown --out ./md-docs --theme markdown && mv md-docs/README.md README.md && rm -R md-docs && ts-node scripts/readme.script.ts",
"clean-docs": "rm -f -r ./docs",
"clean-readme": "rm -f ./README.md",
"clean-lib": "rm -f -r ./lib",
"clean-test": "rm -f -r ./coverage",
"docs": "npm run build-docs && npm run build-readme",
"all": "npm run setup && npm run build && npm run test && npm run docs",
"setup": "npm i -g npm && npm install && npm audit fix",
"build": "npm run clean-lib && tsc",
"test": " npm run clean-test && jest --runInBand --verbose --coverage",
"snyk-protect": "snyk protect",
"prepare": "npm run snyk-protect"
"clean": "make clean",
"build": "make -j3",
"test": " jest --runInBand --verbose --coverage"
},

@@ -29,3 +19,3 @@ "publishConfig": {

},
"author": "mu.io <dev@mathematic.io>",
"author": "jun-sheaf <rjung@mathematic.io>",
"license": "MIT",

@@ -50,9 +40,9 @@ "keywords": [

"devDependencies": {
"@babel/cli": "^7.12.17",
"@babel/core": "^7.12.17",
"@babel/plugin-proposal-class-properties": "^7.12.13",
"@babel/cli": "^7.13.0",
"@babel/core": "^7.13.8",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-proposal-export-namespace-from": "^7.12.13",
"@babel/plugin-proposal-object-rest-spread": "^7.12.13",
"@babel/preset-env": "^7.12.17",
"@babel/preset-typescript": "^7.12.17",
"@babel/plugin-proposal-object-rest-spread": "^7.13.8",
"@babel/preset-env": "^7.13.9",
"@babel/preset-typescript": "^7.13.0",
"@changesets/cli": "^2.14.1",

@@ -63,29 +53,20 @@ "@types/benchmark": "^2.1.0",

"@types/uuid": "^8.3.0",
"@typescript-eslint/eslint-plugin": "^4.15.1",
"@typescript-eslint/parser": "^4.15.1",
"@typescript-eslint/eslint-plugin": "^4.16.1",
"@typescript-eslint/parser": "^4.16.1",
"babel-jest": "^26.6.3",
"benchmark": "^2.1.4",
"core-js": "^3.9.0",
"eslint": "^7.20.0",
"eslint-config-prettier": "^7.2.0",
"core-js": "^3.9.1",
"eslint": "^7.21.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-prettier": "^3.3.1",
"jest": "^26.6.3",
"lodash": "^4.17.20",
"lodash": "^4.17.21",
"prettier": "^2.2.1",
"regenerator-runtime": "^0.13.7",
"snyk": "^1.458.0",
"ts-node": "^9.1.1",
"typedoc": "^0.20.25",
"typedoc-plugin-markdown": "^3.5.0",
"typescript": "^4.1.5",
"typedoc": "^0.20.29",
"typedoc-plugin-markdown": "^3.6.0",
"typescript": "^4.2.3",
"uuid": "^8.3.2"
},
"snyk": true,
"prettier": {
"tabWidth": 1,
"printWidth": 100,
"parser": "typescript",
"semi": true,
"quoteProps": "consistent"
},
"babel": {

@@ -92,0 +73,0 @@ "presets": [

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

ts-japi / [Exports](modules.html)
<br />

@@ -5,3 +7,2 @@ <img src="https://raw.githubusercontent.com/mu-io/ts-japi/master/docs/assets/images/logo.svg" alt="{ts:japi}" width="350"/>

[![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/mu-io/ts-japi)](https://snyk.io/test/github/mu-io/ts-japi)
![node-current](https://img.shields.io/node/v/ts-japi)

@@ -27,2 +28,3 @@ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

- [FAQ](#faq)
- [For Developers](#for-developers)
- [Contributing](#contributing)

@@ -33,3 +35,3 @@ - [License](#license)

- This is the **only** typescript-compatible library that fully types the JSON:API specification and performs *proper* serialization.
- This is the **only** typescript-compatible library that fully types the JSON:API specification and performs *proper* serialization.
- [**Zero dependencies**](#zdg).

@@ -79,25 +81,25 @@ - This is the **only** library with [resource recursion](#wirr).

```typescript
import { Serializer } from "../src";
import { User } from "../test/models";
import { getJSON } from "../test/utils/get-json";
import { Serializer } from '../src';
import { User } from '../test/models';
import { getJSON } from '../test/utils/get-json';
const UserSerializer = new Serializer("users");
const UserSerializer = new Serializer('users');
(async () => {
const user = new User("sample_user_id");
console.log("Output:", getJSON(await UserSerializer.serialize(user)));
const user = new User('sample_user_id');
// Output: {
// jsonapi: { version: '1.0' },
// data: {
// type: 'users',
// id: 'sample_user_id',
// attributes: {
// createdAt: '2020-05-20T15:44:37.650Z',
// articles: [],
// comments: []
// }
// }
// }
console.log('Output:', getJSON(await UserSerializer.serialize(user)));
// Output: {
// jsonapi: { version: '1.0' },
// data: {
// type: 'users',
// id: 'sample_user_id',
// attributes: {
// createdAt: '2020-05-20T15:44:37.650Z',
// articles: [],
// comments: []
// }
// }
// }
})();

@@ -114,5 +116,5 @@

```typescript
import { Linker } from "../src";
import { User, Article } from "../test/models";
import { getJSON } from "../test/utils/get-json";
import { Linker } from '../src';
import { User, Article } from '../test/models';
import { getJSON } from '../test/utils/get-json';

@@ -122,5 +124,5 @@ // The last argument should almost always be an array or a single object type.

const UserArticleLinker = new Linker((user: User, articles: Article | Article[]) => {
return Array.isArray(articles)
? `https://www.example.com/users/${user.id}/articles/`
: `https://www.example.com/users/${user.id}/articles/${articles.id}`;
return Array.isArray(articles)
? `https://www.example.com/users/${user.id}/articles/`
: `https://www.example.com/users/${user.id}/articles/${articles.id}`;
});

@@ -130,8 +132,8 @@

(async () => {
const user = new User("sample_user_id");
const article = new Article("same_article_id", user);
const user = new User('sample_user_id');
const article = new Article('same_article_id', user);
console.log("Output:", getJSON(UserArticleLinker.link(user, article)));
console.log('Output:', getJSON(UserArticleLinker.link(user, article)));
// Output: https://www.example.com/users/sample_user_id/articles/same_article_id
// Output: https://www.example.com/users/sample_user_id/articles/same_article_id
})();

@@ -148,18 +150,18 @@

```typescript
import { Paginator } from "../src";
import { User, Article } from "../test/models";
import { getJSON } from "../test/utils/get-json";
import { Paginator } from '../src';
import { User, Article } from '../test/models';
import { getJSON } from '../test/utils/get-json';
const ArticlePaginator = new Paginator((articles: Article | Article[]) => {
if (Array.isArray(articles)) {
const nextPage = Number(articles[0].id) + 1;
const prevPage = Number(articles[articles.length - 1].id) - 1;
return {
first: `https://www.example.com/articles/0`,
last: `https://www.example.com/articles/10`,
next: nextPage <= 10 ? `https://www.example.com/articles/${nextPage}` : null,
prev: prevPage >= 0 ? `https://www.example.com/articles/${prevPage}` : null,
};
}
return;
if (Array.isArray(articles)) {
const nextPage = Number(articles[0].id) + 1;
const prevPage = Number(articles[articles.length - 1].id) - 1;
return {
first: `https://www.example.com/articles/0`,
last: `https://www.example.com/articles/10`,
next: nextPage <= 10 ? `https://www.example.com/articles/${nextPage}` : null,
prev: prevPage >= 0 ? `https://www.example.com/articles/${prevPage}` : null,
};
}
return;
});

@@ -169,13 +171,13 @@

(async () => {
const user = new User("sample_user_id");
const article = new Article("same_article_id", user);
const user = new User('sample_user_id');
const article = new Article('same_article_id', user);
console.log("Output:", getJSON(ArticlePaginator.paginate([article])));
console.log('Output:', getJSON(ArticlePaginator.paginate([article])));
// Output: {
// first: 'https://www.example.com/articles/0',
// last: 'https://www.example.com/articles/10',
// prev: null,
// next: null
// }
// Output: {
// first: 'https://www.example.com/articles/0',
// last: 'https://www.example.com/articles/10',
// prev: null,
// next: null
// }
})();

@@ -194,10 +196,10 @@

```typescript
import { Serializer, Relator } from "../src";
import { User, Article } from "../test/models";
import { getJSON } from "../test/utils/get-json";
import { Serializer, Relator } from '../src';
import { User, Article } from '../test/models';
import { getJSON } from '../test/utils/get-json';
const ArticleSerializer = new Serializer<Article>("articles");
const ArticleSerializer = new Serializer<Article>('articles');
const UserArticleRelator = new Relator<User, Article>(
async (user) => user.getArticles(),
ArticleSerializer
async (user) => user.getArticles(),
ArticleSerializer
);

@@ -207,10 +209,10 @@

(async () => {
const user = new User("sample_user_id");
const article = new Article("same_article_id", user);
User.save(user);
Article.save(article);
const user = new User('sample_user_id');
const article = new Article('same_article_id', user);
User.save(user);
Article.save(article);
console.log("Output:", getJSON(await UserArticleRelator.getRelationship(user)));
console.log('Output:', getJSON(await UserArticleRelator.getRelationship(user)));
// Output: { data: [ { type: 'articles', id: 'same_article_id' } ] }
// Output: { data: [ { type: 'articles', id: 'same_article_id' } ] }
})();

@@ -225,5 +227,5 @@

- [`ErrorSerializerOptions.metaizers`](https://mu-io.github.io/ts-japi/interfaces/errorserializeroptions.html#metaizers)
- [`RelatorOptions.metaizer`](https://mu-io.github.io/ts-japi/interfaces/relatoroptions.html#optional-metaizer)
- [`RelatorOptions.metaizer`](https://mu-io.github.io/ts-japi/interfaces/relatoroptions.html#metaizer)
- [`SerializerOptions.metaizers`](https://mu-io.github.io/ts-japi/interfaces/serializeroptions.html#metaizers)
- [`LinkerOptions.metaizer`](https://mu-io.github.io/ts-japi/interfaces/linkeroptions.html#optional-metaizer)
- [`LinkerOptions.metaizer`](https://mu-io.github.io/ts-japi/interfaces/linkeroptions.html#metaizer)

@@ -235,5 +237,5 @@ Like [`Linker`](https://mu-io.github.io/ts-japi/classes/linker.html), its methods are not meant to be called.

```typescript
import { User, Article } from "../test/models";
import { Metaizer } from "../src";
import { getJSON } from "../test/utils/get-json";
import { User, Article } from '../test/models';
import { Metaizer } from '../src';
import { getJSON } from '../test/utils/get-json';

@@ -243,5 +245,5 @@ // The last argument should almost always be an array or a single object type.

const UserArticleMetaizer = new Metaizer((user: User, articles: Article | Article[]) => {
return Array.isArray(articles)
? { user_created: user.createdAt, article_created: articles.map((a) => a.createdAt) }
: { user_created: user.createdAt, article_created: articles.createdAt };
return Array.isArray(articles)
? { user_created: user.createdAt, article_created: articles.map((a) => a.createdAt) }
: { user_created: user.createdAt, article_created: articles.createdAt };
});

@@ -251,11 +253,11 @@

(async () => {
const user = new User("sample_user_id");
const article = new Article("same_article_id", user);
const user = new User('sample_user_id');
const article = new Article('same_article_id', user);
console.log("Output:", getJSON(UserArticleMetaizer.metaize(user, article)));
console.log('Output:', getJSON(UserArticleMetaizer.metaize(user, article)));
// Output: {
// user_created: '2020-05-20T15:39:43.277Z',
// article_created: '2020-05-20T15:39:43.277Z'
// }
// Output: {
// user_created: '2020-05-20T15:39:43.277Z',
// article_created: '2020-05-20T15:39:43.277Z'
// }
})();

@@ -274,4 +276,4 @@

```typescript
import { ErrorSerializer } from "../src";
import { getJSON } from "../test/utils/get-json";
import { ErrorSerializer } from '../src';
import { getJSON } from '../test/utils/get-json';

@@ -281,10 +283,10 @@ const PrimitiveErrorSerializer = new ErrorSerializer();

(async () => {
const error = new Error("badness");
const error = new Error('badness');
console.log("Output:", getJSON(PrimitiveErrorSerializer.serialize(error)));
console.log('Output:', getJSON(PrimitiveErrorSerializer.serialize(error)));
// Output: {
// errors: [ { code: 'Error', detail: 'badness' } ],
// jsonapi: { version: '1.0' }
// }
// Output: {
// errors: [ { code: 'Error', detail: 'badness' } ],
// jsonapi: { version: '1.0' }
// }
})();

@@ -302,3 +304,3 @@

We stress the following: There are many clients readily built to consume JSON:API endpoints (see [here](https://jsonapi.org/implementations/)). It is **highly recommended** to use them and only use this for serialization.
We stress the following: Given that there are many clients readily built to consume JSON:API endpoints (see [here](https://jsonapi.org/implementations/)), we do not provide deserialization. In particular, since unmarshalling data is strongly related to the code it will be used in (e.g. React), tighter integration is recommended over an unnecessary abstraction.

@@ -321,4 +323,8 @@ ## Remarks

Due to [compound documents](https://jsonapi.org/format/#document-compound-documents), it is possible to recurse through related resources via their [resource linkages](https://jsonapi.org/format/#document-resource-object-linkage) and obtain [included resources](https://jsonapi.org/format/#document-top-level) beyond what the primary data gives. This is not preferable and should be done with caution (see [`SerializerOptions.depth`](https://mu-io.github.io/ts-japi/interfaces/serializeroptions.html#depth) and [this example](https://github.com/mu-io/ts-japi/blob/master/examples/resource-recursion.example.ts))
Due to [compound documents](https://jsonapi.org/format/#document-compound-documents), it is possible to recurse through related resources via their [resource linkages](https://jsonapi.org/format/#document-resource-object-linkage) and obtain [included resources](https://jsonapi.org/format/#document-top-level) beyond primary data relations. This is should be done with caution (see [`SerializerOptions.depth`](https://mu-io.github.io/ts-japi/interfaces/serializeroptions.html#depth) and [this example](https://github.com/mu-io/ts-japi/blob/master/examples/resource-recursion.example.ts))
## For Developers
To get started in developing this library, run `yarn install`, `yarn build` and `yarn test` (in this precise order) to assure everything is in working order.
## Contributing

@@ -325,0 +331,0 @@

@@ -68,5 +68,4 @@ {

"typedocOptions": {
"mode": "library",
"out": "docs",
"inputFiles": [
"entryPoints": [
"./src/index.ts"

@@ -77,8 +76,5 @@ ],

],
"gaID": "UA-99757611-3",
"plugin": "none",
"theme": "../typedoc-classic-theme/bin/default",
"exclude": "**/*+(.spec|.e2e|.test).ts",
"readme": "src/docs/README.md",
"stripInternal": true,
"categorizeByGroup": true,

@@ -85,0 +81,0 @@ "gitRevision": "master"

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

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc