yayson 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +440 -68
- package/build/legacy.cjs +278 -0
- package/build/legacy.d.cts +105 -0
- package/build/legacy.d.cts.map +1 -0
- package/build/legacy.d.mts +105 -0
- package/build/legacy.d.mts.map +1 -0
- package/build/legacy.mjs +279 -0
- package/build/legacy.mjs.map +1 -0
- package/build/symbols-DSjKJ8vh.mjs +26 -0
- package/build/symbols-DSjKJ8vh.mjs.map +1 -0
- package/build/symbols-nFs99aEX.cjs +61 -0
- package/build/types-BsfPiPEw.d.mts +122 -0
- package/build/types-BsfPiPEw.d.mts.map +1 -0
- package/build/types-DbMIe8E2.d.cts +122 -0
- package/build/types-DbMIe8E2.d.cts.map +1 -0
- package/build/utils.cjs +31 -0
- package/build/utils.d.cts +11 -0
- package/build/utils.d.cts.map +1 -0
- package/build/utils.d.mts +11 -0
- package/build/utils.d.mts.map +1 -0
- package/build/utils.mjs +22 -0
- package/build/utils.mjs.map +1 -0
- package/build/yayson-BJv2Z0Z6.mjs +391 -0
- package/build/yayson-BJv2Z0Z6.mjs.map +1 -0
- package/build/yayson-BKEyEcGk.d.cts +69 -0
- package/build/yayson-BKEyEcGk.d.cts.map +1 -0
- package/build/yayson-CRbukIqr.d.mts +69 -0
- package/build/yayson-CRbukIqr.d.mts.map +1 -0
- package/build/yayson-CUfrxK9d.cjs +407 -0
- package/build/yayson.cjs +3 -0
- package/build/yayson.d.cts +3 -0
- package/build/yayson.d.mts +3 -0
- package/build/yayson.mjs +3 -0
- package/package.json +72 -28
- package/skill/yayson/SKILL.md +233 -0
- package/skill/yayson/references/api.md +266 -0
- package/.eslintrc.json +0 -28
- package/.github/workflows/node.js.yml +0 -30
- package/.mocharc.js +0 -15
- package/.nvmrc +0 -1
- package/RELEASE.md +0 -3
- package/babel.config.json +0 -4
- package/legacy.js +0 -2
- package/prettier.config.js +0 -5
- package/src/legacy.js +0 -14
- package/src/yayson/adapter.js +0 -18
- package/src/yayson/adapters/index.js +0 -1
- package/src/yayson/adapters/sequelize.js +0 -11
- package/src/yayson/legacy-presenter.js +0 -121
- package/src/yayson/legacy-store.js +0 -156
- package/src/yayson/presenter.js +0 -198
- package/src/yayson/store.js +0 -194
- package/src/yayson.js +0 -23
- package/tags +0 -59
- package/webpack.browser.js +0 -27
- package/webpack.common.js +0 -39
- package/webpack.dist.js +0 -21
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { T as ModelLike, _ as ValidationError, d as SchemaRegistry, f as StoreModel, g as StoreResult, h as StoreRecord$1, i as JsonApiLinks, m as StoreOptions, n as JsonApiDocument, o as JsonApiRelationships, p as StoreModels, r as JsonApiLink, t as InferModelType, u as PresenterOptions, w as Adapter } from "./types-BsfPiPEw.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/yayson/presenter.d.ts
|
|
4
|
+
declare function createPresenter(adapter: typeof Adapter): {
|
|
5
|
+
new (scope?: JsonApiDocument): {
|
|
6
|
+
constructor: /*elided*/any;
|
|
7
|
+
scope: JsonApiDocument;
|
|
8
|
+
id(instance: ModelLike): string | undefined;
|
|
9
|
+
selfLinks(_instance: ModelLike): JsonApiLink | string | undefined;
|
|
10
|
+
links(_instance?: ModelLike): JsonApiLinks | undefined;
|
|
11
|
+
relationships(): Record<string, /*elided*/any>;
|
|
12
|
+
attributes(instance: ModelLike | null): Record<string, unknown>;
|
|
13
|
+
includeRelationships(scope: JsonApiDocument, instance: ModelLike): unknown[];
|
|
14
|
+
buildRelationships(instance: ModelLike | null): JsonApiRelationships | null;
|
|
15
|
+
buildSelfLink(instance: ModelLike): JsonApiLink | undefined;
|
|
16
|
+
toJSON(instanceOrCollection: ModelLike | ModelLike[] | null | undefined, options?: PresenterOptions): JsonApiDocument;
|
|
17
|
+
render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
18
|
+
};
|
|
19
|
+
adapter: typeof Adapter;
|
|
20
|
+
type: string;
|
|
21
|
+
fields?: string[];
|
|
22
|
+
toJSON(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
23
|
+
render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
24
|
+
};
|
|
25
|
+
type Presenter = ReturnType<typeof createPresenter>;
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/yayson/store.d.ts
|
|
28
|
+
declare class StoreRecord implements StoreRecord$1 {
|
|
29
|
+
id: string | number;
|
|
30
|
+
type: string;
|
|
31
|
+
attributes?: Record<string, unknown>;
|
|
32
|
+
relationships?: JsonApiRelationships;
|
|
33
|
+
links?: JsonApiLink;
|
|
34
|
+
meta?: Record<string, unknown>;
|
|
35
|
+
constructor(options: StoreRecord$1);
|
|
36
|
+
}
|
|
37
|
+
declare class Store<S extends SchemaRegistry = SchemaRegistry> {
|
|
38
|
+
records: StoreRecord[];
|
|
39
|
+
schemas?: S;
|
|
40
|
+
strict: boolean;
|
|
41
|
+
validationErrors: ValidationError[];
|
|
42
|
+
constructor(options?: StoreOptions<S>);
|
|
43
|
+
reset(): void;
|
|
44
|
+
toModel(rec: StoreRecord, type: string, models: StoreModels): StoreModel;
|
|
45
|
+
findRecord(type: string, id: string | number): StoreRecord | undefined;
|
|
46
|
+
findRecords(type: string): StoreRecord[];
|
|
47
|
+
find<T extends string>(type: T, id: string | number, models?: StoreModels): InferModelType<S, T> | null;
|
|
48
|
+
findAll<T extends string>(type: T, models?: StoreModels): InferModelType<S, T>[];
|
|
49
|
+
remove(type: string, id?: string | number): void;
|
|
50
|
+
syncAll(body: JsonApiDocument): StoreResult;
|
|
51
|
+
sync(body: JsonApiDocument): StoreModel | StoreResult;
|
|
52
|
+
retrieve<T extends string>(type: T, body: JsonApiDocument): InferModelType<S, T> | null;
|
|
53
|
+
retrieveAll<T extends string>(type: T, body: JsonApiDocument): StoreResult<InferModelType<S, T>>;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/yayson.d.ts
|
|
57
|
+
type AdapterOption = string | typeof Adapter;
|
|
58
|
+
interface YaysonOptions {
|
|
59
|
+
adapter?: AdapterOption;
|
|
60
|
+
}
|
|
61
|
+
interface YaysonResult {
|
|
62
|
+
Store: typeof Store;
|
|
63
|
+
Presenter: Presenter;
|
|
64
|
+
Adapter: typeof Adapter;
|
|
65
|
+
}
|
|
66
|
+
declare function yayson(options?: YaysonOptions): YaysonResult;
|
|
67
|
+
//#endregion
|
|
68
|
+
export { Presenter as i, YaysonResult as n, yayson as r, YaysonOptions as t };
|
|
69
|
+
//# sourceMappingURL=yayson-CRbukIqr.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yayson-CRbukIqr.d.mts","names":[],"sources":["../../../../../../yayson/presenter.ts","../../../../../../yayson/store.ts","../../../../../../yayson.ts"],"mappings":";;;iBAyBwB,eAAA,CAAgB,OAAA,SAAgB,OAAA;EAAA,aAUhC,eAAA;iBAVe;WAQ5B,eAAA;iBAMM,SAAA;yBAIQ,SAAA,GAAY,WAAA;sBAIf,SAAA,GAAY,YAAA;qBAIb,MAAA,SAZJ;yBAgBQ,SAAA,UAAmB,MAAA;gCAiBZ,eAAA,EAAe,QAAA,EAAY,SAAA;iCAoB1B,SAAA,UAAmB,oBAAA;4BA0DxB,SAAA,GAAY,WAAA;iCAKZ,SAAA,GAAY,SAAA,uBAA8B,OAAA,GACtD,gBAAA,GACT,eAAA;iCA8E0B,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;EAAA;;;;+BAItD,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;+BAI7D,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;AAAA;AAAA,KAQzF,SAAA,GAAY,UAAA,QAAkB,eAAA;;;cC1OpC,WAAA,YAAuB,aAAA;EAC3B,EAAA;EACA,IAAA;EACA,UAAA,GAAa,MAAA;EACb,aAAA,GAAgB,oBAAA;EAChB,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,MAAA;cAEK,OAAA,EAAS,aAAA;AAAA;AAAA,cAUF,KAAA,WAAgB,cAAA,GAAiB,cAAA;EACpD,OAAA,EAAS,WAAA;EACT,OAAA,GAAU,CAAA;EACV,MAAA;EACA,gBAAA,EAAkB,eAAA;cAEN,OAAA,GAAU,YAAA,CAAa,CAAA;EAMnC,KAAA,CAAA;EAKA,OAAA,CAAQ,GAAA,EAAK,WAAA,EAAa,IAAA,UAAc,MAAA,EAAQ,WAAA,GAAc,UAAA;EA6E9D,UAAA,CAAW,IAAA,UAAc,EAAA,oBAAsB,WAAA;EAK/C,WAAA,CAAY,IAAA,WAAe,WAAA;EAI3B,IAAA,kBAAA,CAAuB,IAAA,EAAM,CAAA,EAAG,EAAA,mBAAqB,MAAA,GAAS,WAAA,GAAc,cAAA,CAAe,CAAA,EAAG,CAAA;EAc9F,OAAA,kBAAA,CAA0B,IAAA,EAAM,CAAA,EAAG,MAAA,GAAS,WAAA,GAAc,cAAA,CAAe,CAAA,EAAG,CAAA;EAgB5E,MAAA,CAAO,IAAA,UAAc,EAAA;EAkBrB,OAAA,CAAQ,IAAA,EAAM,eAAA,GAAkB,WAAA;EA8DhC,IAAA,CAAK,IAAA,EAAM,eAAA,GAAkB,UAAA,GAAa,WAAA;EAY1C,QAAA,kBAAA,CAA2B,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,eAAA,GAAkB,cAAA,CAAe,CAAA,EAAG,CAAA;EAW9E,WAAA,kBAAA,CAA8B,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,eAAA,GAAkB,WAAA,CAAY,cAAA,CAAe,CAAA,EAAG,CAAA;AAAA;;;KC5P1F,aAAA,mBAAgC,OAAA;AAAA,UAE3B,aAAA;EACR,OAAA,GAAU,aAAA;AAAA;AAAA,UAGF,YAAA;EACR,KAAA,SAAc,KAAA;EACd,SAAA,EAAW,SAAA;EACX,OAAA,SAAgB,OAAA;AAAA;AAAA,iBAgBT,MAAA,CAAO,OAAA,GAAU,aAAA,GAAgB,YAAA"}
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
const require_symbols = require('./symbols-nFs99aEX.cjs');
|
|
2
|
+
|
|
3
|
+
//#region src/yayson/adapters/sequelize.ts
|
|
4
|
+
function isSequelizeModel(model) {
|
|
5
|
+
return model != null && typeof model === "object" && "get" in model && typeof model.get === "function";
|
|
6
|
+
}
|
|
7
|
+
var SequelizeAdapter = class extends require_symbols.adapter_default {
|
|
8
|
+
static get(model, key) {
|
|
9
|
+
if (isSequelizeModel(model)) return model.get(key);
|
|
10
|
+
}
|
|
11
|
+
static id(model) {
|
|
12
|
+
const pkFields = model.constructor && "primaryKeys" in model.constructor ? Object.keys(model.constructor.primaryKeys) : ["id"];
|
|
13
|
+
if (pkFields.length > 1) throw new Error("YAYSON does not support Sequelize models with composite primary keys. You can only use one column for your primary key. Currently using: " + pkFields.join(","));
|
|
14
|
+
else if (pkFields.length < 1) throw new Error("YAYSON can only serialize Sequelize models which have a primary key. This is used for the JSON:API model id.");
|
|
15
|
+
const id = this.get(model, pkFields[0]);
|
|
16
|
+
if (id === void 0) return id;
|
|
17
|
+
return `${id}`;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var sequelize_default = SequelizeAdapter;
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/yayson/utils.ts
|
|
24
|
+
/**
|
|
25
|
+
* Filters an attributes object to only include keys in the fields array.
|
|
26
|
+
* Returns the original attributes if fields is undefined.
|
|
27
|
+
*/
|
|
28
|
+
function filterByFields(attributes, fields) {
|
|
29
|
+
if (!fields) return attributes;
|
|
30
|
+
const filtered = {};
|
|
31
|
+
for (const key of fields) if (key in attributes) filtered[key] = attributes[key];
|
|
32
|
+
return filtered;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/yayson/presenter.ts
|
|
37
|
+
function buildLinks(link) {
|
|
38
|
+
if (link == null) return;
|
|
39
|
+
if (typeof link === "object" && (link.self != null || link.related != null)) return link;
|
|
40
|
+
else return { self: String(link) };
|
|
41
|
+
}
|
|
42
|
+
function createPresenter(adapter) {
|
|
43
|
+
class Presenter {
|
|
44
|
+
static adapter = adapter;
|
|
45
|
+
static type = "objects";
|
|
46
|
+
static fields;
|
|
47
|
+
scope;
|
|
48
|
+
constructor(scope) {
|
|
49
|
+
this.scope = scope ?? { data: null };
|
|
50
|
+
}
|
|
51
|
+
id(instance) {
|
|
52
|
+
return this.constructor.adapter.id(instance);
|
|
53
|
+
}
|
|
54
|
+
selfLinks(_instance) {}
|
|
55
|
+
links(_instance) {}
|
|
56
|
+
relationships() {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
attributes(instance) {
|
|
60
|
+
if (instance == null) return {};
|
|
61
|
+
const attributes = { ...this.constructor.adapter.get(instance) };
|
|
62
|
+
delete attributes["id"];
|
|
63
|
+
const relationships = this.relationships();
|
|
64
|
+
if (relationships) for (const key in relationships) delete attributes[key];
|
|
65
|
+
return filterByFields(attributes, this.constructor.fields);
|
|
66
|
+
}
|
|
67
|
+
includeRelationships(scope, instance) {
|
|
68
|
+
const relationships = this.relationships();
|
|
69
|
+
const result = [];
|
|
70
|
+
if (!relationships) return result;
|
|
71
|
+
for (const key in relationships) {
|
|
72
|
+
const factory = relationships[key];
|
|
73
|
+
if (!factory) throw new Error(`Presenter for ${key} in ${this.constructor.type} is not defined`);
|
|
74
|
+
const presenter = new factory(scope);
|
|
75
|
+
const data = this.constructor.adapter.get(instance, key);
|
|
76
|
+
result.push(presenter.toJSON(data, { include: true }));
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
buildRelationships(instance) {
|
|
81
|
+
if (instance == null) return null;
|
|
82
|
+
const rels = this.relationships();
|
|
83
|
+
const links = this.links(instance) || {};
|
|
84
|
+
let relationships = null;
|
|
85
|
+
if (!rels) return null;
|
|
86
|
+
for (const key in rels) {
|
|
87
|
+
const data = this.constructor.adapter.get(instance, key);
|
|
88
|
+
const presenter = rels[key];
|
|
89
|
+
const buildData = (d) => {
|
|
90
|
+
const id = this.constructor.adapter.id(d);
|
|
91
|
+
if (!id) throw new Error(`Model of type ${presenter.type} is missing an id (relationship '${key}' of ${this.constructor.type})`);
|
|
92
|
+
return {
|
|
93
|
+
id,
|
|
94
|
+
type: presenter.type
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
const build = (d) => {
|
|
98
|
+
const rel = {};
|
|
99
|
+
if (d != null) rel.data = buildData(d);
|
|
100
|
+
if (links[key] != null) rel.links = buildLinks(links[key]);
|
|
101
|
+
else if (d == null) rel.data = null;
|
|
102
|
+
return rel;
|
|
103
|
+
};
|
|
104
|
+
if (!relationships) relationships = {};
|
|
105
|
+
if (!relationships[key]) relationships[key] = {};
|
|
106
|
+
if (Array.isArray(data)) {
|
|
107
|
+
relationships[key].data = data.map(buildData);
|
|
108
|
+
if (links[key] != null) relationships[key].links = buildLinks(links[key]);
|
|
109
|
+
} else relationships[key] = build(data);
|
|
110
|
+
}
|
|
111
|
+
return relationships;
|
|
112
|
+
}
|
|
113
|
+
buildSelfLink(instance) {
|
|
114
|
+
return buildLinks(this.selfLinks(instance));
|
|
115
|
+
}
|
|
116
|
+
toJSON(instanceOrCollection, options) {
|
|
117
|
+
const opts = options ?? {};
|
|
118
|
+
if (opts.meta != null) this.scope.meta = opts.meta;
|
|
119
|
+
if (opts.links != null) this.scope.links = opts.links;
|
|
120
|
+
if (!this.scope.data) this.scope.data = null;
|
|
121
|
+
if (instanceOrCollection == null) return this.scope;
|
|
122
|
+
if (Array.isArray(instanceOrCollection)) {
|
|
123
|
+
const collection = instanceOrCollection;
|
|
124
|
+
if (!this.scope.data) this.scope.data = [];
|
|
125
|
+
collection.forEach((instance) => {
|
|
126
|
+
return this.toJSON(instance, options);
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
const instance = instanceOrCollection;
|
|
130
|
+
let added = true;
|
|
131
|
+
const model = {
|
|
132
|
+
id: this.id(instance),
|
|
133
|
+
type: this.constructor.type,
|
|
134
|
+
attributes: this.attributes(instance)
|
|
135
|
+
};
|
|
136
|
+
if (model.id === void 0) delete model.id;
|
|
137
|
+
const relationships = this.buildRelationships(instance);
|
|
138
|
+
if (relationships != null) model.relationships = relationships;
|
|
139
|
+
const links = this.buildSelfLink(instance);
|
|
140
|
+
if (links != null) model.links = links;
|
|
141
|
+
if (opts.include) {
|
|
142
|
+
if (!this.scope.included) this.scope.included = [];
|
|
143
|
+
if (!(this.scope.included || []).concat(Array.isArray(this.scope.data) ? this.scope.data : this.scope.data ? [this.scope.data] : []).some((i) => i.id === model.id && i.type === model.type)) this.scope.included.push(model);
|
|
144
|
+
else added = false;
|
|
145
|
+
} else if (this.scope.data != null) if (Array.isArray(this.scope.data)) if (!this.scope.data.some((i) => i.id === model.id && i.type === model.type)) this.scope.data.push(model);
|
|
146
|
+
else added = false;
|
|
147
|
+
else this.scope.data = model;
|
|
148
|
+
else this.scope.data = model;
|
|
149
|
+
if (added) this.includeRelationships(this.scope, instance);
|
|
150
|
+
}
|
|
151
|
+
return this.scope;
|
|
152
|
+
}
|
|
153
|
+
render(instanceOrCollection, options) {
|
|
154
|
+
return this.toJSON(instanceOrCollection, options);
|
|
155
|
+
}
|
|
156
|
+
static toJSON(instanceOrCollection, options) {
|
|
157
|
+
return new this().toJSON(instanceOrCollection, options);
|
|
158
|
+
}
|
|
159
|
+
static render(instanceOrCollection, options) {
|
|
160
|
+
return new this().render(instanceOrCollection, options);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return Presenter;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/yayson/schema.ts
|
|
168
|
+
function isZodLikeSchema(schema) {
|
|
169
|
+
return schema != null && typeof schema === "object" && "parse" in schema && typeof schema.parse === "function" && "safeParse" in schema && typeof schema.safeParse === "function";
|
|
170
|
+
}
|
|
171
|
+
function validate(schema, data, strict) {
|
|
172
|
+
if (!isZodLikeSchema(schema)) throw new Error("Invalid schema: must have parse and safeParse methods");
|
|
173
|
+
if (strict) return {
|
|
174
|
+
valid: true,
|
|
175
|
+
data: schema.parse(data)
|
|
176
|
+
};
|
|
177
|
+
else {
|
|
178
|
+
const result = schema.safeParse(data);
|
|
179
|
+
if (result.success) return {
|
|
180
|
+
valid: true,
|
|
181
|
+
data: result.data
|
|
182
|
+
};
|
|
183
|
+
else return {
|
|
184
|
+
valid: false,
|
|
185
|
+
data,
|
|
186
|
+
error: result.error
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region src/yayson/store.ts
|
|
193
|
+
var StoreRecord = class {
|
|
194
|
+
id;
|
|
195
|
+
type;
|
|
196
|
+
attributes;
|
|
197
|
+
relationships;
|
|
198
|
+
links;
|
|
199
|
+
meta;
|
|
200
|
+
constructor(options) {
|
|
201
|
+
this.id = options.id;
|
|
202
|
+
this.type = options.type;
|
|
203
|
+
this.attributes = options.attributes;
|
|
204
|
+
this.relationships = options.relationships;
|
|
205
|
+
this.links = options.links;
|
|
206
|
+
this.meta = options.meta;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
var Store = class {
|
|
210
|
+
records = [];
|
|
211
|
+
schemas;
|
|
212
|
+
strict;
|
|
213
|
+
validationErrors = [];
|
|
214
|
+
constructor(options) {
|
|
215
|
+
this.schemas = options?.schemas;
|
|
216
|
+
this.strict = options?.strict ?? false;
|
|
217
|
+
this.reset();
|
|
218
|
+
}
|
|
219
|
+
reset() {
|
|
220
|
+
this.records = [];
|
|
221
|
+
this.validationErrors = [];
|
|
222
|
+
}
|
|
223
|
+
toModel(rec, type, models) {
|
|
224
|
+
const model = {
|
|
225
|
+
...rec.attributes || {},
|
|
226
|
+
id: rec.id
|
|
227
|
+
};
|
|
228
|
+
model[require_symbols.TYPE] = rec.type;
|
|
229
|
+
const idStr = String(rec.id);
|
|
230
|
+
if (!models[type]) models[type] = {};
|
|
231
|
+
if (!models[type][idStr]) models[type][idStr] = model;
|
|
232
|
+
if (rec.meta != null) model[require_symbols.META] = rec.meta;
|
|
233
|
+
if (rec.links != null) model[require_symbols.LINKS] = rec.links;
|
|
234
|
+
if (rec.relationships != null) for (const key in rec.relationships) {
|
|
235
|
+
const rel = rec.relationships[key];
|
|
236
|
+
const { data } = rel;
|
|
237
|
+
const { links } = rel;
|
|
238
|
+
const { meta } = rel;
|
|
239
|
+
model[key] = null;
|
|
240
|
+
if (data == null && links == null) continue;
|
|
241
|
+
const resolve = ({ type: type$1, id }) => {
|
|
242
|
+
return this.find(type$1, id, models);
|
|
243
|
+
};
|
|
244
|
+
if (Array.isArray(data)) model[key] = data.map(resolve);
|
|
245
|
+
else {
|
|
246
|
+
const relModel = data != null ? resolve(data) : { id: "" };
|
|
247
|
+
if (relModel) {
|
|
248
|
+
relModel[require_symbols.REL_LINKS] = links || {};
|
|
249
|
+
relModel[require_symbols.REL_META] = meta || {};
|
|
250
|
+
model[key] = relModel;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (this.schemas && this.schemas[rec.type]) {
|
|
255
|
+
const schema = this.schemas[rec.type];
|
|
256
|
+
const result = validate(schema, model, this.strict);
|
|
257
|
+
if (!result.valid) this.validationErrors.push({
|
|
258
|
+
type: rec.type,
|
|
259
|
+
id: rec.id,
|
|
260
|
+
error: result.error
|
|
261
|
+
});
|
|
262
|
+
const validatedModel = result.data;
|
|
263
|
+
validatedModel[require_symbols.TYPE] = model[require_symbols.TYPE];
|
|
264
|
+
validatedModel[require_symbols.LINKS] = model[require_symbols.LINKS];
|
|
265
|
+
validatedModel[require_symbols.META] = model[require_symbols.META];
|
|
266
|
+
return validatedModel;
|
|
267
|
+
}
|
|
268
|
+
return model;
|
|
269
|
+
}
|
|
270
|
+
findRecord(type, id) {
|
|
271
|
+
const idStr = String(id);
|
|
272
|
+
return this.records.find((r) => r.type === type && String(r.id) === idStr);
|
|
273
|
+
}
|
|
274
|
+
findRecords(type) {
|
|
275
|
+
return this.records.filter((r) => r.type === type);
|
|
276
|
+
}
|
|
277
|
+
find(type, id, models) {
|
|
278
|
+
const modelsObj = models ?? {};
|
|
279
|
+
const idStr = String(id);
|
|
280
|
+
const rec = this.findRecord(type, idStr);
|
|
281
|
+
if (rec == null) return null;
|
|
282
|
+
if (!modelsObj[type]) modelsObj[type] = {};
|
|
283
|
+
return modelsObj[type][idStr] || this.toModel(rec, type, modelsObj);
|
|
284
|
+
}
|
|
285
|
+
findAll(type, models) {
|
|
286
|
+
const modelsObj = models ?? {};
|
|
287
|
+
const recs = this.findRecords(type);
|
|
288
|
+
if (recs == null) return [];
|
|
289
|
+
recs.forEach((rec) => {
|
|
290
|
+
if (!modelsObj[type]) modelsObj[type] = {};
|
|
291
|
+
return this.toModel(rec, type, modelsObj);
|
|
292
|
+
});
|
|
293
|
+
return Object.values(modelsObj[type] || {});
|
|
294
|
+
}
|
|
295
|
+
remove(type, id) {
|
|
296
|
+
const removeOne = (record) => {
|
|
297
|
+
const index = this.records.indexOf(record);
|
|
298
|
+
if (!(index < 0)) this.records.splice(index, 1);
|
|
299
|
+
};
|
|
300
|
+
if (id != null) {
|
|
301
|
+
const record = this.findRecord(type, String(id));
|
|
302
|
+
if (record) removeOne(record);
|
|
303
|
+
} else this.findRecords(type).forEach(removeOne);
|
|
304
|
+
}
|
|
305
|
+
syncAll(body) {
|
|
306
|
+
this.validationErrors = [];
|
|
307
|
+
const previousRecords = [...this.records];
|
|
308
|
+
const syncData = (data) => {
|
|
309
|
+
if (data == null) return [];
|
|
310
|
+
const add = (obj) => {
|
|
311
|
+
const { type, id } = obj;
|
|
312
|
+
this.remove(type, id);
|
|
313
|
+
const rec = new StoreRecord(obj);
|
|
314
|
+
this.records.push(rec);
|
|
315
|
+
return rec;
|
|
316
|
+
};
|
|
317
|
+
if (Array.isArray(data)) return data.map((item) => {
|
|
318
|
+
if (!item.id) throw new Error(`Resource of type ${item.type} is missing an id`);
|
|
319
|
+
return add({
|
|
320
|
+
...item,
|
|
321
|
+
attributes: item.attributes ?? void 0,
|
|
322
|
+
relationships: item.relationships ?? void 0,
|
|
323
|
+
id: item.id
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
else {
|
|
327
|
+
if (!data.id) throw new Error(`Resource of type ${data.type} is missing an id`);
|
|
328
|
+
return [add({
|
|
329
|
+
...data,
|
|
330
|
+
attributes: data.attributes ?? void 0,
|
|
331
|
+
relationships: data.relationships ?? void 0,
|
|
332
|
+
id: data.id
|
|
333
|
+
})];
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
try {
|
|
337
|
+
syncData(body.included);
|
|
338
|
+
const recs = syncData(body.data);
|
|
339
|
+
const models = {};
|
|
340
|
+
const result = recs.map((rec) => this.toModel(rec, rec.type, models));
|
|
341
|
+
if (body.meta != null) result[require_symbols.META] = body.meta;
|
|
342
|
+
return result;
|
|
343
|
+
} catch (e) {
|
|
344
|
+
this.records = previousRecords;
|
|
345
|
+
throw e;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
sync(body) {
|
|
349
|
+
const result = this.syncAll(body);
|
|
350
|
+
if (!Array.isArray(body.data) && body.data != null) {
|
|
351
|
+
const model = result[0];
|
|
352
|
+
if (result[require_symbols.META]) model[require_symbols.META] = result[require_symbols.META];
|
|
353
|
+
return model;
|
|
354
|
+
}
|
|
355
|
+
return result;
|
|
356
|
+
}
|
|
357
|
+
retrieve(type, body) {
|
|
358
|
+
const synced = this.syncAll(body);
|
|
359
|
+
const model = synced.find((m) => m[require_symbols.TYPE] === type);
|
|
360
|
+
if (!model) return null;
|
|
361
|
+
if (synced[require_symbols.META]) model[require_symbols.META] = synced[require_symbols.META];
|
|
362
|
+
return model;
|
|
363
|
+
}
|
|
364
|
+
retrieveAll(type, body) {
|
|
365
|
+
const synced = this.syncAll(body);
|
|
366
|
+
const result = synced.filter((model) => model[require_symbols.TYPE] === type);
|
|
367
|
+
result[require_symbols.META] = synced[require_symbols.META];
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
//#endregion
|
|
373
|
+
//#region src/yayson.ts
|
|
374
|
+
function lookupAdapter(nameOrAdapter) {
|
|
375
|
+
if (nameOrAdapter === "default" || !nameOrAdapter) return require_symbols.adapter_default;
|
|
376
|
+
else if (typeof nameOrAdapter === "string") if (nameOrAdapter === "sequelize") return sequelize_default;
|
|
377
|
+
else throw new Error("Adapter not found: " + nameOrAdapter);
|
|
378
|
+
return nameOrAdapter;
|
|
379
|
+
}
|
|
380
|
+
function yayson(options) {
|
|
381
|
+
return {
|
|
382
|
+
Store,
|
|
383
|
+
Presenter: createPresenter(lookupAdapter(options?.adapter)),
|
|
384
|
+
Adapter: require_symbols.adapter_default
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
var yayson_default = yayson;
|
|
388
|
+
|
|
389
|
+
//#endregion
|
|
390
|
+
Object.defineProperty(exports, 'filterByFields', {
|
|
391
|
+
enumerable: true,
|
|
392
|
+
get: function () {
|
|
393
|
+
return filterByFields;
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
Object.defineProperty(exports, 'validate', {
|
|
397
|
+
enumerable: true,
|
|
398
|
+
get: function () {
|
|
399
|
+
return validate;
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
Object.defineProperty(exports, 'yayson_default', {
|
|
403
|
+
enumerable: true,
|
|
404
|
+
get: function () {
|
|
405
|
+
return yayson_default;
|
|
406
|
+
}
|
|
407
|
+
});
|
package/build/yayson.cjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { _ as ValidationError, a as JsonApiRelationship, d as SchemaRegistry, i as JsonApiLinks, l as LegacyStoreOptions, m as StoreOptions, n as JsonApiDocument, o as JsonApiRelationships, r as JsonApiLink, s as JsonApiResource, u as PresenterOptions, v as ZodLikeSchema, w as Adapter } from "./types-DbMIe8E2.cjs";
|
|
2
|
+
import { n as YaysonResult, r as yayson, t as YaysonOptions } from "./yayson-BKEyEcGk.cjs";
|
|
3
|
+
export { Adapter, JsonApiDocument, JsonApiLink, JsonApiLinks, JsonApiRelationship, JsonApiRelationships, JsonApiResource, LegacyStoreOptions, PresenterOptions, SchemaRegistry, StoreOptions, ValidationError, YaysonOptions, YaysonResult, ZodLikeSchema, yayson as default };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { _ as ValidationError, a as JsonApiRelationship, d as SchemaRegistry, i as JsonApiLinks, l as LegacyStoreOptions, m as StoreOptions, n as JsonApiDocument, o as JsonApiRelationships, r as JsonApiLink, s as JsonApiResource, u as PresenterOptions, v as ZodLikeSchema, w as Adapter } from "./types-BsfPiPEw.mjs";
|
|
2
|
+
import { n as YaysonResult, r as yayson, t as YaysonOptions } from "./yayson-CRbukIqr.mjs";
|
|
3
|
+
export { Adapter, JsonApiDocument, JsonApiLink, JsonApiLinks, JsonApiRelationship, JsonApiRelationships, JsonApiResource, LegacyStoreOptions, PresenterOptions, SchemaRegistry, StoreOptions, ValidationError, YaysonOptions, YaysonResult, ZodLikeSchema, yayson as default };
|
package/build/yayson.mjs
ADDED
package/package.json
CHANGED
|
@@ -1,19 +1,63 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yayson",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "A library for serializing and reading JSON API standardized data in JavaScript.",
|
|
5
|
-
"
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./build/yayson.cjs",
|
|
7
|
+
"module": "./build/yayson.mjs",
|
|
8
|
+
"types": "./build/yayson.d.mts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./build/yayson.d.mts",
|
|
13
|
+
"default": "./build/yayson.mjs"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./build/yayson.d.cts",
|
|
17
|
+
"default": "./build/yayson.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./legacy": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./build/legacy.d.mts",
|
|
23
|
+
"default": "./build/legacy.mjs"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./build/legacy.d.cts",
|
|
27
|
+
"default": "./build/legacy.cjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"./utils": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./build/utils.d.mts",
|
|
33
|
+
"default": "./build/utils.mjs"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./build/utils.d.cts",
|
|
37
|
+
"default": "./build/utils.cjs"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"build/**/*",
|
|
43
|
+
"skill/**/*",
|
|
44
|
+
"README.md",
|
|
45
|
+
"LICENSE"
|
|
46
|
+
],
|
|
6
47
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
8
|
-
"npm": ">=
|
|
48
|
+
"node": ">=20",
|
|
49
|
+
"npm": ">=10"
|
|
9
50
|
},
|
|
10
51
|
"scripts": {
|
|
11
|
-
"test": "mocha",
|
|
12
|
-
"build": "
|
|
13
|
-
"
|
|
14
|
-
"
|
|
52
|
+
"test": "tsx node_modules/.bin/mocha",
|
|
53
|
+
"test:build": "node test/build.test.cjs",
|
|
54
|
+
"build": "tsdown",
|
|
55
|
+
"prepublishOnly": "npm run build && npm run test:build",
|
|
56
|
+
"preversion": "npm test && npm run build && npm run test:build",
|
|
15
57
|
"postversion": "git push --follow-tags origin master",
|
|
16
|
-
"release": "npm version minor"
|
|
58
|
+
"release": "npm version minor",
|
|
59
|
+
"format": "prettier --write src test",
|
|
60
|
+
"lint": "concurrently --prefix '[{name}]' --prefix-colors '#f73fae,#00c2db,#00db8b' --names 'tsc,eslint,prettier' 'tsc --noEmit' 'eslint .' 'prettier --check .'"
|
|
17
61
|
},
|
|
18
62
|
"repository": {
|
|
19
63
|
"type": "git",
|
|
@@ -37,26 +81,26 @@
|
|
|
37
81
|
"url": "https://github.com/confetti/yayson/issues"
|
|
38
82
|
},
|
|
39
83
|
"homepage": "https://github.com/confetti/yayson",
|
|
40
|
-
"browserslist": [
|
|
41
|
-
"defaults",
|
|
42
|
-
"not IE 11"
|
|
43
|
-
],
|
|
44
84
|
"devDependencies": {
|
|
45
|
-
"@
|
|
46
|
-
"@
|
|
47
|
-
"@
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
85
|
+
"@eslint-community/eslint-plugin-eslint-comments": "4.6.0",
|
|
86
|
+
"@eslint/js": "^9.35.0",
|
|
87
|
+
"@types/mocha": "^10.0.10",
|
|
88
|
+
"@types/node": "^24.5.1",
|
|
89
|
+
"@types/sinon": "^17.0.4",
|
|
90
|
+
"@types/sinon-chai": "^4.0.0",
|
|
91
|
+
"chai": "^4.5.0",
|
|
92
|
+
"concurrently": "^9.2.1",
|
|
93
|
+
"eslint": "9.39.1",
|
|
94
|
+
"eslint-plugin-mocha": "^11.1.0",
|
|
95
|
+
"globals": "^16.4.0",
|
|
96
|
+
"mocha": "^11.7.2",
|
|
97
|
+
"prettier": "3.7.2",
|
|
98
|
+
"sinon": "^21.0.0",
|
|
56
99
|
"sinon-chai": "^3.7.0",
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
100
|
+
"tsdown": "0.20.0-beta.4",
|
|
101
|
+
"tsx": "^4.20.5",
|
|
102
|
+
"typescript": "^5.9.2",
|
|
103
|
+
"typescript-eslint": "^8.44.0",
|
|
104
|
+
"zod": "4.3.5"
|
|
61
105
|
}
|
|
62
106
|
}
|