yayson 4.1.0 → 4.3.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 +43 -0
- package/build/legacy.cjs +27 -23
- package/build/legacy.d.cts +35 -7
- package/build/legacy.d.cts.map +1 -1
- package/build/legacy.d.mts +35 -7
- package/build/legacy.d.mts.map +1 -1
- package/build/legacy.mjs +27 -23
- package/build/legacy.mjs.map +1 -1
- package/build/{symbols-nFs99aEX.cjs → symbols-B--FS78o.cjs} +3 -0
- package/build/{symbols-DSjKJ8vh.mjs → symbols-BfU4k1el.mjs} +4 -1
- package/build/symbols-BfU4k1el.mjs.map +1 -0
- package/build/{types-NiKV-lj-.d.cts → types-KZiF6x7A.d.mts} +14 -2
- package/build/types-KZiF6x7A.d.mts.map +1 -0
- package/build/{types-Do2flKZX.d.mts → types-iC38_iCI.d.cts} +14 -2
- package/build/types-iC38_iCI.d.cts.map +1 -0
- package/build/utils.cjs +1 -1
- package/build/utils.d.cts +1 -1
- package/build/utils.d.mts +1 -1
- package/build/utils.mjs +1 -1
- package/build/{yayson-l2JKseMH.cjs → yayson-B51EJfRP.cjs} +97 -27
- package/build/{yayson-3UYKq2H5.d.cts → yayson-BvwMr4Ad.d.mts} +6 -4
- package/build/yayson-BvwMr4Ad.d.mts.map +1 -0
- package/build/{yayson-Ce5uGpgU.d.mts → yayson-DTMLeA5k.d.cts} +6 -4
- package/build/yayson-DTMLeA5k.d.cts.map +1 -0
- package/build/{yayson-CwZg5FNt.mjs → yayson-RzT9zsdx.mjs} +81 -29
- package/build/yayson-RzT9zsdx.mjs.map +1 -0
- package/build/yayson.cjs +1 -1
- package/build/yayson.d.cts +2 -2
- package/build/yayson.d.mts +2 -2
- package/build/yayson.mjs +1 -1
- package/package.json +1 -1
- package/skill/yayson/SKILL.md +20 -0
- package/skill/yayson/references/api.md +27 -2
- package/build/symbols-DSjKJ8vh.mjs.map +0 -1
- package/build/types-Do2flKZX.d.mts.map +0 -1
- package/build/types-NiKV-lj-.d.cts.map +0 -1
- package/build/yayson-3UYKq2H5.d.cts.map +0 -1
- package/build/yayson-Ce5uGpgU.d.mts.map +0 -1
- package/build/yayson-CwZg5FNt.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -81,6 +81,49 @@ class BikePresenter extends Presenter {
|
|
|
81
81
|
}
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
+
### Declaring cardinality and optional relationships
|
|
85
|
+
|
|
86
|
+
By default a missing relationship renders as `data: null`. This isn't valid JSON:API for to-many relationships (the spec requires `[]`) and can mislead clients when a relationship simply wasn't loaded. Use the config form to declare cardinality and optional semantics:
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
class BikePresenter extends Presenter {
|
|
90
|
+
static type = 'bikes'
|
|
91
|
+
|
|
92
|
+
relationships() {
|
|
93
|
+
return {
|
|
94
|
+
wheels: { presenter: WheelPresenter, hasMany: true },
|
|
95
|
+
manufacturer: { presenter: ManufacturerPresenter, optional: true },
|
|
96
|
+
accessories: { presenter: AccessoryPresenter, hasMany: true, optional: true },
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
BikePresenter.render({ id: 1 })
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This produces:
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
{
|
|
108
|
+
data: {
|
|
109
|
+
id: '1',
|
|
110
|
+
type: 'bikes',
|
|
111
|
+
attributes: {},
|
|
112
|
+
relationships: {
|
|
113
|
+
wheels: { data: [] } // hasMany + no data → empty array, not null
|
|
114
|
+
// manufacturer and accessories omitted entirely — they weren't loaded
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
- **`hasMany: true`** — declares a to-many relationship. Empty or missing data renders as `data: []` instead of `data: null`.
|
|
121
|
+
- **`optional: true`** — when the relationship key is absent from the instance, the relationship is omitted from the output (or rendered with just `links` if `links()` configures one for that key). An explicit `null` on the instance still renders as `data: null` — `optional` distinguishes "not loaded" from "explicitly empty".
|
|
122
|
+
|
|
123
|
+
In `payload()` output, `optional` omission is disabled (a write request asserts state, so dropping a relationship would be misleading), but `hasMany` still applies so a client can correctly clear a to-many with `data: []`.
|
|
124
|
+
|
|
125
|
+
The bare-class form (`relationships() { return { wheels: WheelPresenter } }`) is unchanged.
|
|
126
|
+
|
|
84
127
|
### Filtering attributes with fields
|
|
85
128
|
|
|
86
129
|
Use the static `fields` property to limit which attributes are included in the output:
|
package/build/legacy.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const require_symbols = require('./symbols-
|
|
2
|
-
const require_yayson = require('./yayson-
|
|
1
|
+
const require_symbols = require('./symbols-B--FS78o.cjs');
|
|
2
|
+
const require_yayson = require('./yayson-B51EJfRP.cjs');
|
|
3
3
|
|
|
4
4
|
//#region src/yayson/legacy-presenter.ts
|
|
5
5
|
function hasId$1(value) {
|
|
@@ -39,9 +39,9 @@ function createLegacyPresenter(Presenter) {
|
|
|
39
39
|
const result = [];
|
|
40
40
|
if (!relationships) return result;
|
|
41
41
|
for (const key in relationships) {
|
|
42
|
-
const
|
|
43
|
-
if (!
|
|
44
|
-
const presenter = new
|
|
42
|
+
const entry = relationships[key];
|
|
43
|
+
if (!entry) throw new Error(`Presenter for ${key} in ${this.constructor.type} is not defined`);
|
|
44
|
+
const presenter = new (typeof entry === "function" ? entry : entry.presenter)(scope);
|
|
45
45
|
const data = this.constructor.adapter.get(instance, key);
|
|
46
46
|
if (data != null) presenter.toJSON(data, { defaultPlural: true });
|
|
47
47
|
const type = scope[this.pluralType()] != null ? this.pluralType() : this.constructor.type;
|
|
@@ -122,19 +122,20 @@ var LegacyStore = class LegacyStore {
|
|
|
122
122
|
validationErrors;
|
|
123
123
|
models;
|
|
124
124
|
constructor(options) {
|
|
125
|
-
this.types =
|
|
125
|
+
this.types = require_yayson.safeObject();
|
|
126
|
+
Object.assign(this.types, options?.types);
|
|
126
127
|
this.schemas = options?.schemas;
|
|
127
128
|
this.strict = options?.strict ?? false;
|
|
128
129
|
this.records = [];
|
|
129
|
-
this.relations =
|
|
130
|
+
this.relations = require_yayson.safeObject();
|
|
130
131
|
this.validationErrors = [];
|
|
131
|
-
this.models =
|
|
132
|
+
this.models = require_yayson.safeObject();
|
|
132
133
|
}
|
|
133
134
|
reset() {
|
|
134
135
|
this.records = [];
|
|
135
|
-
this.relations =
|
|
136
|
+
this.relations = require_yayson.safeObject();
|
|
136
137
|
this.validationErrors = [];
|
|
137
|
-
this.models =
|
|
138
|
+
this.models = require_yayson.safeObject();
|
|
138
139
|
}
|
|
139
140
|
#createStub(type, id) {
|
|
140
141
|
const stub = { id };
|
|
@@ -144,7 +145,8 @@ var LegacyStore = class LegacyStore {
|
|
|
144
145
|
#resolveRelationships(model, type, resolver) {
|
|
145
146
|
const relations = this.relations[type];
|
|
146
147
|
if (!relations) return;
|
|
147
|
-
for (const attribute
|
|
148
|
+
for (const attribute of Object.keys(relations)) {
|
|
149
|
+
if (require_yayson.isUnsafeKey(attribute)) continue;
|
|
148
150
|
const relationType = relations[attribute];
|
|
149
151
|
const value = model[attribute];
|
|
150
152
|
if (Array.isArray(value)) model[attribute] = value.filter((id) => id != null).map((id) => resolver(relationType, String(id)));
|
|
@@ -161,18 +163,19 @@ var LegacyStore = class LegacyStore {
|
|
|
161
163
|
if (rec.data.links != null) model[require_symbols.LINKS] = rec.data.links;
|
|
162
164
|
if (models && hasId(model)) {
|
|
163
165
|
const idStr = String(model.id);
|
|
164
|
-
if (!models[type]) models[type] =
|
|
166
|
+
if (!models[type]) models[type] = require_yayson.safeObject();
|
|
165
167
|
models[type][idStr] = model;
|
|
166
168
|
}
|
|
167
169
|
const resolver = (relationType, id) => {
|
|
168
|
-
return this.#findModel(relationType, id, models ??
|
|
170
|
+
return this.#findModel(relationType, id, models ?? require_yayson.safeObject()) ?? this.#createStub(relationType, id);
|
|
169
171
|
};
|
|
170
172
|
this.#resolveRelationships(model, type, resolver);
|
|
171
173
|
return model;
|
|
172
174
|
}
|
|
173
|
-
toModel(rec, type,
|
|
175
|
+
toModel(rec, type, modelsArg) {
|
|
174
176
|
const idStr = String(rec.data.id);
|
|
175
|
-
|
|
177
|
+
const models = require_yayson.safeCache(modelsArg);
|
|
178
|
+
if (!models[type]) models[type] = require_yayson.safeObject();
|
|
176
179
|
if (models[type][idStr]) return models[type][idStr];
|
|
177
180
|
const result = this.#createModel(rec, type, { models });
|
|
178
181
|
if (!hasId(result)) throw new Error(`Expected model of type ${type} to have an id`);
|
|
@@ -195,13 +198,14 @@ var LegacyStore = class LegacyStore {
|
|
|
195
198
|
return model;
|
|
196
199
|
}
|
|
197
200
|
setupRelations(links) {
|
|
198
|
-
for (const key
|
|
201
|
+
for (const key of Object.keys(links)) {
|
|
199
202
|
const value = links[key];
|
|
200
203
|
const parts = key.split(".");
|
|
201
204
|
const typeRaw = parts[0];
|
|
202
205
|
const attribute = parts[1];
|
|
206
|
+
if (require_yayson.isUnsafeKey(attribute)) continue;
|
|
203
207
|
const type = this.types[typeRaw] || typeRaw;
|
|
204
|
-
if (!this.relations[type]) this.relations[type] =
|
|
208
|
+
if (!this.relations[type]) this.relations[type] = require_yayson.safeObject();
|
|
205
209
|
this.relations[type][attribute] = this.types[value.type] || value.type;
|
|
206
210
|
}
|
|
207
211
|
}
|
|
@@ -222,7 +226,7 @@ var LegacyStore = class LegacyStore {
|
|
|
222
226
|
build(data) {
|
|
223
227
|
if (data.links) this.setupRelations(data.links);
|
|
224
228
|
let name;
|
|
225
|
-
for (const key
|
|
229
|
+
for (const key of Object.keys(data)) if (key !== "meta" && key !== "links") {
|
|
226
230
|
name = key;
|
|
227
231
|
break;
|
|
228
232
|
}
|
|
@@ -248,14 +252,14 @@ var LegacyStore = class LegacyStore {
|
|
|
248
252
|
return model;
|
|
249
253
|
}
|
|
250
254
|
find(type, id, models) {
|
|
251
|
-
return this.#findModel(type, String(id), models ?? this.models);
|
|
255
|
+
return this.#findModel(type, String(id), require_yayson.safeCache(models ?? this.models));
|
|
252
256
|
}
|
|
253
257
|
findAll(type, models) {
|
|
254
|
-
const modelsObj = models ?? this.models;
|
|
258
|
+
const modelsObj = require_yayson.safeCache(models ?? this.models);
|
|
255
259
|
const recs = this.findRecords(type);
|
|
256
260
|
if (recs.length === 0) return [];
|
|
257
261
|
recs.forEach((rec) => {
|
|
258
|
-
if (!modelsObj[type]) modelsObj[type] =
|
|
262
|
+
if (!modelsObj[type]) modelsObj[type] = require_yayson.safeObject();
|
|
259
263
|
return this.toModel(rec, type, modelsObj);
|
|
260
264
|
});
|
|
261
265
|
return Object.values(modelsObj[type] || {});
|
|
@@ -274,10 +278,10 @@ var LegacyStore = class LegacyStore {
|
|
|
274
278
|
}
|
|
275
279
|
syncAll(data) {
|
|
276
280
|
this.validationErrors = [];
|
|
277
|
-
this.models =
|
|
281
|
+
this.models = require_yayson.safeObject();
|
|
278
282
|
if (data.links) this.setupRelations(data.links);
|
|
279
283
|
const syncedRecords = [];
|
|
280
|
-
for (const name
|
|
284
|
+
for (const name of Object.keys(data)) {
|
|
281
285
|
if (name === "meta" || name === "links") continue;
|
|
282
286
|
const value = data[name];
|
|
283
287
|
const type = this.types[name] || name;
|
package/build/legacy.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as Presenter, r as yayson$1, t as YaysonOptions } from "./yayson-
|
|
1
|
+
import { D as ModelLike, E as Adapter, a as JsonApiRelationship, c as LegacyPresenterOptions, d as RelationshipConfig, f as SchemaRegistry, h as StoreModels, i as JsonApiLinks, l as LegacyStoreOptions, m as StoreModelWithOptionalId, n as JsonApiDocument, o as JsonApiRelationships, p as StoreModel, r as JsonApiLink, s as JsonApiResource, t as InferModelType, u as PresenterOptions, v as StoreResult, y as ValidationError } from "./types-iC38_iCI.cjs";
|
|
2
|
+
import { i as Presenter, r as yayson$1, t as YaysonOptions } from "./yayson-DTMLeA5k.cjs";
|
|
3
3
|
|
|
4
4
|
//#region src/yayson/legacy-presenter.d.ts
|
|
5
5
|
interface LegacyJsonApiDocument extends JsonApiDocument {
|
|
@@ -25,10 +25,12 @@ declare function createLegacyPresenter(Presenter: Presenter): {
|
|
|
25
25
|
id(instance: ModelLike): string | undefined;
|
|
26
26
|
selfLinks(_instance: ModelLike): JsonApiLink | string | undefined;
|
|
27
27
|
links(_instance?: ModelLike): JsonApiLinks | undefined;
|
|
28
|
-
relationships(): Record<string, /*elided*/any
|
|
28
|
+
relationships(): Record<string, /*elided*/any | RelationshipConfig< /*elided*/any>>;
|
|
29
29
|
attributes(instance: ModelLike | null): Record<string, unknown>;
|
|
30
30
|
includeRelationships(scope: JsonApiDocument, instance: ModelLike): unknown[];
|
|
31
|
-
buildRelationships(instance: ModelLike | null
|
|
31
|
+
buildRelationships(instance: ModelLike | null, options?: {
|
|
32
|
+
payload?: boolean;
|
|
33
|
+
}): JsonApiRelationships | null;
|
|
32
34
|
buildSelfLink(instance: ModelLike): JsonApiLink | undefined;
|
|
33
35
|
toJSON(instanceOrCollection: ModelLike | ModelLike[] | null | undefined, options?: PresenterOptions): JsonApiDocument;
|
|
34
36
|
payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument;
|
|
@@ -40,8 +42,34 @@ declare function createLegacyPresenter(Presenter: Presenter): {
|
|
|
40
42
|
toJSON(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
41
43
|
render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
42
44
|
payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
+
} | RelationshipConfig<{
|
|
46
|
+
new (scope?: JsonApiDocument): {
|
|
47
|
+
constructor: /*elided*/any;
|
|
48
|
+
scope: JsonApiDocument;
|
|
49
|
+
id(instance: ModelLike): string | undefined;
|
|
50
|
+
selfLinks(_instance: ModelLike): JsonApiLink | string | undefined;
|
|
51
|
+
links(_instance?: ModelLike): JsonApiLinks | undefined;
|
|
52
|
+
relationships(): Record<string, /*elided*/any | RelationshipConfig< /*elided*/any>>;
|
|
53
|
+
attributes(instance: ModelLike | null): Record<string, unknown>;
|
|
54
|
+
includeRelationships(scope: JsonApiDocument, instance: ModelLike): unknown[];
|
|
55
|
+
buildRelationships(instance: ModelLike | null, options?: {
|
|
56
|
+
payload?: boolean;
|
|
57
|
+
}): JsonApiRelationships | null;
|
|
58
|
+
buildSelfLink(instance: ModelLike): JsonApiLink | undefined;
|
|
59
|
+
toJSON(instanceOrCollection: ModelLike | ModelLike[] | null | undefined, options?: PresenterOptions): JsonApiDocument;
|
|
60
|
+
payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument;
|
|
61
|
+
render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
62
|
+
};
|
|
63
|
+
adapter: typeof Adapter;
|
|
64
|
+
type: string;
|
|
65
|
+
fields?: string[];
|
|
66
|
+
toJSON(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
67
|
+
render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
68
|
+
payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument;
|
|
69
|
+
}>>;
|
|
70
|
+
buildRelationships(instance: ModelLike | null, options?: {
|
|
71
|
+
payload?: boolean;
|
|
72
|
+
}): JsonApiRelationships | null;
|
|
45
73
|
buildSelfLink(instance: ModelLike): JsonApiLink | undefined;
|
|
46
74
|
};
|
|
47
75
|
type: string;
|
|
@@ -84,7 +112,7 @@ declare class LegacyStore<S extends SchemaRegistry = SchemaRegistry> {
|
|
|
84
112
|
models: StoreModels;
|
|
85
113
|
constructor(options?: LegacyStoreOptions<S>);
|
|
86
114
|
reset(): void;
|
|
87
|
-
toModel(rec: LegacyStoreRecordType, type: string,
|
|
115
|
+
toModel(rec: LegacyStoreRecordType, type: string, modelsArg: StoreModels): StoreModel;
|
|
88
116
|
setupRelations(links: LegacyLinks): void;
|
|
89
117
|
findRecord(type: string, id: string): LegacyStoreRecordType | undefined;
|
|
90
118
|
findRecords(type: string): LegacyStoreRecordType[];
|
package/build/legacy.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legacy.d.cts","names":[],"sources":["../../../../../../yayson/legacy-presenter.ts","../../../../../../yayson/legacy-store.ts","../../../../../../legacy.ts"],"mappings":";;;;UASU,qBAAA,SAA8B,eAAA;EAAA,CACrC,GAAA;AAAA;AAAA,iBAIqB,qBAAA,CAAsB,SAAA,EAAW,SAAA;EAAA,aASjC,eAAA;iBAbV;WAOK,qBAAA;;yBAqBM,SAAA,UAAmB,MAAA;gCA8BZ,qBAAA,EAAqB,QAAA,EAAY,SAAA;
|
|
1
|
+
{"version":3,"file":"legacy.d.cts","names":[],"sources":["../../../../../../yayson/legacy-presenter.ts","../../../../../../yayson/legacy-store.ts","../../../../../../legacy.ts"],"mappings":";;;;UASU,qBAAA,SAA8B,eAAA;EAAA,CACrC,GAAA;AAAA;AAAA,iBAIqB,qBAAA,CAAsB,SAAA,EAAW,SAAA;EAAA,aASjC,eAAA;iBAbV;WAOK,qBAAA;;yBAqBM,SAAA,UAAmB,MAAA;gCA8BZ,qBAAA,EAAqB,QAAA,EAAY,SAAA;iCAsCrC,SAAA,GAAY,SAAA,uBAA8B,OAAA,GACtD,sBAAA,GACT,qBAAA;sBA6De,SAAA,GAAY,qBAAA;iCAWD,SAAA,GAAY,SAAA,YAAqB,qBAAA;;;;;;qBAzElD;;;;;wCAyE6B,oCAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAKjB,SAAA,GAAY,SAAA,WAAkB,OAAA,GAC1C,sBAAA,GACT,qBAAA;+BAKqB,SAAA,GAAY,SAAA,WAAkB,QAAA,GACzC,sBAAA,GACV,qBAAA;oBAIsB,SAAA,GAAY,qBAAA;kBAAqB,OAAA;AAAA;;;UCxLpD,qBAAA;EACR,IAAA;EACA,IAAA,EAAM,MAAA;IACJ,EAAA;IACA,IAAA,GAAO,MAAA;IACP,KAAA,GAAQ,MAAA;EAAA;AAAA;AAAA,UAIF,WAAA;EAAA,CACP,GAAA;IACC,IAAA;EAAA;AAAA;AAAA,KAIC,eAAA,GAAkB,MAAA,oBAA0B,KAAA,CAAM,MAAA;AAAA,UAEtC,UAAA;EACf,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,MAAA;EAAA,CACN,GAAA,WAAc,eAAA,GAAkB,WAAA,GAAc,MAAA;AAAA;AAAA,cAO5B,WAAA,WAAsB,cAAA,GAAiB,cAAA;EAAA;EAC1D,KAAA,EAAO,MAAA;EACP,OAAA,EAAS,qBAAA;EACT,SAAA,EAAW,MAAA,SAAe,MAAA;EAC1B,OAAA,GAAU,CAAA;EACV,MAAA;EACA,gBAAA,EAAkB,eAAA;EAClB,MAAA,EAAQ,WAAA;cAEI,OAAA,GAAU,kBAAA,CAAmB,CAAA;EAazC,KAAA,CAAA;EAwEA,OAAA,CAAQ,GAAA,EAAK,qBAAA,EAAuB,IAAA,UAAc,SAAA,EAAW,WAAA,GAAc,UAAA;EA6C3E,cAAA,CAAe,KAAA,EAAO,WAAA;EAiBtB,UAAA,CAAW,IAAA,UAAc,EAAA,WAAa,qBAAA;EAItC,WAAA,CAAY,IAAA,WAAe,qBAAA;EAAA,OAYpB,KAAA,CAAM,IAAA,EAAM,UAAA,GAAa,wBAAA;EAIhC,KAAA,CAAM,IAAA,EAAM,UAAA,GAAa,wBAAA;;EA2BzB,OAAA,kBAAA,CAA0B,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,UAAA,GAAa,cAAA,CAAe,CAAA,EAAG,CAAA;EAIxE,QAAA,kBAAA,CAA2B,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,UAAA,GAAa,cAAA,CAAe,CAAA,EAAG,CAAA;EAYzE,IAAA,kBAAA,CAAuB,IAAA,EAAM,CAAA,EAAG,EAAA,mBAAqB,MAAA,GAAS,WAAA,GAAc,cAAA,CAAe,CAAA,EAAG,CAAA;EAM9F,OAAA,kBAAA,CAA0B,IAAA,EAAM,CAAA,EAAG,MAAA,GAAS,WAAA,GAAc,cAAA,CAAe,CAAA,EAAG,CAAA;EAgB5E,MAAA,CAAO,IAAA,UAAc,EAAA;EAsBrB,OAAA,CAAQ,IAAA,EAAM,UAAA,GAAa,WAAA;EA4C3B,IAAA,CAAK,IAAA,EAAM,UAAA,GAAa,UAAA,GAAa,WAAA;EAYrC,WAAA,kBAAA,CAA8B,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,UAAA,GAAa,WAAA,CAAY,cAAA,CAAe,CAAA,EAAG,CAAA;AAAA;;;UC9UhF,kBAAA;EACR,KAAA,SAAc,WAAA;EACd,SAAA,EAAW,UAAA,QAAkB,qBAAA;EAC7B,OAAA,EAAS,UAAA,QAAkB,QAAA;AAAA;AAAA,iBAGL,MAAA,CAAO,OAAA,GAAU,aAAA,GAAgB,kBAAA"}
|
package/build/legacy.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as Presenter, r as yayson$1, t as YaysonOptions } from "./yayson-
|
|
1
|
+
import { D as ModelLike, E as Adapter, a as JsonApiRelationship, c as LegacyPresenterOptions, d as RelationshipConfig, f as SchemaRegistry, h as StoreModels, i as JsonApiLinks, l as LegacyStoreOptions, m as StoreModelWithOptionalId, n as JsonApiDocument, o as JsonApiRelationships, p as StoreModel, r as JsonApiLink, s as JsonApiResource, t as InferModelType, u as PresenterOptions, v as StoreResult, y as ValidationError } from "./types-KZiF6x7A.mjs";
|
|
2
|
+
import { i as Presenter, r as yayson$1, t as YaysonOptions } from "./yayson-BvwMr4Ad.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/yayson/legacy-presenter.d.ts
|
|
5
5
|
interface LegacyJsonApiDocument extends JsonApiDocument {
|
|
@@ -25,10 +25,12 @@ declare function createLegacyPresenter(Presenter: Presenter): {
|
|
|
25
25
|
id(instance: ModelLike): string | undefined;
|
|
26
26
|
selfLinks(_instance: ModelLike): JsonApiLink | string | undefined;
|
|
27
27
|
links(_instance?: ModelLike): JsonApiLinks | undefined;
|
|
28
|
-
relationships(): Record<string, /*elided*/any
|
|
28
|
+
relationships(): Record<string, /*elided*/any | RelationshipConfig< /*elided*/any>>;
|
|
29
29
|
attributes(instance: ModelLike | null): Record<string, unknown>;
|
|
30
30
|
includeRelationships(scope: JsonApiDocument, instance: ModelLike): unknown[];
|
|
31
|
-
buildRelationships(instance: ModelLike | null
|
|
31
|
+
buildRelationships(instance: ModelLike | null, options?: {
|
|
32
|
+
payload?: boolean;
|
|
33
|
+
}): JsonApiRelationships | null;
|
|
32
34
|
buildSelfLink(instance: ModelLike): JsonApiLink | undefined;
|
|
33
35
|
toJSON(instanceOrCollection: ModelLike | ModelLike[] | null | undefined, options?: PresenterOptions): JsonApiDocument;
|
|
34
36
|
payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument;
|
|
@@ -40,8 +42,34 @@ declare function createLegacyPresenter(Presenter: Presenter): {
|
|
|
40
42
|
toJSON(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
41
43
|
render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
42
44
|
payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
+
} | RelationshipConfig<{
|
|
46
|
+
new (scope?: JsonApiDocument): {
|
|
47
|
+
constructor: /*elided*/any;
|
|
48
|
+
scope: JsonApiDocument;
|
|
49
|
+
id(instance: ModelLike): string | undefined;
|
|
50
|
+
selfLinks(_instance: ModelLike): JsonApiLink | string | undefined;
|
|
51
|
+
links(_instance?: ModelLike): JsonApiLinks | undefined;
|
|
52
|
+
relationships(): Record<string, /*elided*/any | RelationshipConfig< /*elided*/any>>;
|
|
53
|
+
attributes(instance: ModelLike | null): Record<string, unknown>;
|
|
54
|
+
includeRelationships(scope: JsonApiDocument, instance: ModelLike): unknown[];
|
|
55
|
+
buildRelationships(instance: ModelLike | null, options?: {
|
|
56
|
+
payload?: boolean;
|
|
57
|
+
}): JsonApiRelationships | null;
|
|
58
|
+
buildSelfLink(instance: ModelLike): JsonApiLink | undefined;
|
|
59
|
+
toJSON(instanceOrCollection: ModelLike | ModelLike[] | null | undefined, options?: PresenterOptions): JsonApiDocument;
|
|
60
|
+
payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument;
|
|
61
|
+
render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
62
|
+
};
|
|
63
|
+
adapter: typeof Adapter;
|
|
64
|
+
type: string;
|
|
65
|
+
fields?: string[];
|
|
66
|
+
toJSON(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
67
|
+
render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument;
|
|
68
|
+
payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument;
|
|
69
|
+
}>>;
|
|
70
|
+
buildRelationships(instance: ModelLike | null, options?: {
|
|
71
|
+
payload?: boolean;
|
|
72
|
+
}): JsonApiRelationships | null;
|
|
45
73
|
buildSelfLink(instance: ModelLike): JsonApiLink | undefined;
|
|
46
74
|
};
|
|
47
75
|
type: string;
|
|
@@ -84,7 +112,7 @@ declare class LegacyStore<S extends SchemaRegistry = SchemaRegistry> {
|
|
|
84
112
|
models: StoreModels;
|
|
85
113
|
constructor(options?: LegacyStoreOptions<S>);
|
|
86
114
|
reset(): void;
|
|
87
|
-
toModel(rec: LegacyStoreRecordType, type: string,
|
|
115
|
+
toModel(rec: LegacyStoreRecordType, type: string, modelsArg: StoreModels): StoreModel;
|
|
88
116
|
setupRelations(links: LegacyLinks): void;
|
|
89
117
|
findRecord(type: string, id: string): LegacyStoreRecordType | undefined;
|
|
90
118
|
findRecords(type: string): LegacyStoreRecordType[];
|
package/build/legacy.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legacy.d.mts","names":[],"sources":["../../../../../../yayson/legacy-presenter.ts","../../../../../../yayson/legacy-store.ts","../../../../../../legacy.ts"],"mappings":";;;;UASU,qBAAA,SAA8B,eAAA;EAAA,CACrC,GAAA;AAAA;AAAA,iBAIqB,qBAAA,CAAsB,SAAA,EAAW,SAAA;EAAA,aASjC,eAAA;iBAbV;WAOK,qBAAA;;yBAqBM,SAAA,UAAmB,MAAA;gCA8BZ,qBAAA,EAAqB,QAAA,EAAY,SAAA;
|
|
1
|
+
{"version":3,"file":"legacy.d.mts","names":[],"sources":["../../../../../../yayson/legacy-presenter.ts","../../../../../../yayson/legacy-store.ts","../../../../../../legacy.ts"],"mappings":"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"}
|
package/build/legacy.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as TYPE, n as META, t as LINKS } from "./symbols-
|
|
2
|
-
import {
|
|
1
|
+
import { a as TYPE, n as META, t as LINKS } from "./symbols-BfU4k1el.mjs";
|
|
2
|
+
import { a as validate, i as safeObject, n as isUnsafeKey, o as filterByFields, r as safeCache, t as yayson_default } from "./yayson-RzT9zsdx.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/yayson/legacy-presenter.ts
|
|
5
5
|
function hasId$1(value) {
|
|
@@ -39,9 +39,9 @@ function createLegacyPresenter(Presenter) {
|
|
|
39
39
|
const result = [];
|
|
40
40
|
if (!relationships) return result;
|
|
41
41
|
for (const key in relationships) {
|
|
42
|
-
const
|
|
43
|
-
if (!
|
|
44
|
-
const presenter = new
|
|
42
|
+
const entry = relationships[key];
|
|
43
|
+
if (!entry) throw new Error(`Presenter for ${key} in ${this.constructor.type} is not defined`);
|
|
44
|
+
const presenter = new (typeof entry === "function" ? entry : entry.presenter)(scope);
|
|
45
45
|
const data = this.constructor.adapter.get(instance, key);
|
|
46
46
|
if (data != null) presenter.toJSON(data, { defaultPlural: true });
|
|
47
47
|
const type = scope[this.pluralType()] != null ? this.pluralType() : this.constructor.type;
|
|
@@ -122,19 +122,20 @@ var LegacyStore = class LegacyStore {
|
|
|
122
122
|
validationErrors;
|
|
123
123
|
models;
|
|
124
124
|
constructor(options) {
|
|
125
|
-
this.types =
|
|
125
|
+
this.types = safeObject();
|
|
126
|
+
Object.assign(this.types, options?.types);
|
|
126
127
|
this.schemas = options?.schemas;
|
|
127
128
|
this.strict = options?.strict ?? false;
|
|
128
129
|
this.records = [];
|
|
129
|
-
this.relations =
|
|
130
|
+
this.relations = safeObject();
|
|
130
131
|
this.validationErrors = [];
|
|
131
|
-
this.models =
|
|
132
|
+
this.models = safeObject();
|
|
132
133
|
}
|
|
133
134
|
reset() {
|
|
134
135
|
this.records = [];
|
|
135
|
-
this.relations =
|
|
136
|
+
this.relations = safeObject();
|
|
136
137
|
this.validationErrors = [];
|
|
137
|
-
this.models =
|
|
138
|
+
this.models = safeObject();
|
|
138
139
|
}
|
|
139
140
|
#createStub(type, id) {
|
|
140
141
|
const stub = { id };
|
|
@@ -144,7 +145,8 @@ var LegacyStore = class LegacyStore {
|
|
|
144
145
|
#resolveRelationships(model, type, resolver) {
|
|
145
146
|
const relations = this.relations[type];
|
|
146
147
|
if (!relations) return;
|
|
147
|
-
for (const attribute
|
|
148
|
+
for (const attribute of Object.keys(relations)) {
|
|
149
|
+
if (isUnsafeKey(attribute)) continue;
|
|
148
150
|
const relationType = relations[attribute];
|
|
149
151
|
const value = model[attribute];
|
|
150
152
|
if (Array.isArray(value)) model[attribute] = value.filter((id) => id != null).map((id) => resolver(relationType, String(id)));
|
|
@@ -161,18 +163,19 @@ var LegacyStore = class LegacyStore {
|
|
|
161
163
|
if (rec.data.links != null) model[LINKS] = rec.data.links;
|
|
162
164
|
if (models && hasId(model)) {
|
|
163
165
|
const idStr = String(model.id);
|
|
164
|
-
if (!models[type]) models[type] =
|
|
166
|
+
if (!models[type]) models[type] = safeObject();
|
|
165
167
|
models[type][idStr] = model;
|
|
166
168
|
}
|
|
167
169
|
const resolver = (relationType, id) => {
|
|
168
|
-
return this.#findModel(relationType, id, models ??
|
|
170
|
+
return this.#findModel(relationType, id, models ?? safeObject()) ?? this.#createStub(relationType, id);
|
|
169
171
|
};
|
|
170
172
|
this.#resolveRelationships(model, type, resolver);
|
|
171
173
|
return model;
|
|
172
174
|
}
|
|
173
|
-
toModel(rec, type,
|
|
175
|
+
toModel(rec, type, modelsArg) {
|
|
174
176
|
const idStr = String(rec.data.id);
|
|
175
|
-
|
|
177
|
+
const models = safeCache(modelsArg);
|
|
178
|
+
if (!models[type]) models[type] = safeObject();
|
|
176
179
|
if (models[type][idStr]) return models[type][idStr];
|
|
177
180
|
const result = this.#createModel(rec, type, { models });
|
|
178
181
|
if (!hasId(result)) throw new Error(`Expected model of type ${type} to have an id`);
|
|
@@ -195,13 +198,14 @@ var LegacyStore = class LegacyStore {
|
|
|
195
198
|
return model;
|
|
196
199
|
}
|
|
197
200
|
setupRelations(links) {
|
|
198
|
-
for (const key
|
|
201
|
+
for (const key of Object.keys(links)) {
|
|
199
202
|
const value = links[key];
|
|
200
203
|
const parts = key.split(".");
|
|
201
204
|
const typeRaw = parts[0];
|
|
202
205
|
const attribute = parts[1];
|
|
206
|
+
if (isUnsafeKey(attribute)) continue;
|
|
203
207
|
const type = this.types[typeRaw] || typeRaw;
|
|
204
|
-
if (!this.relations[type]) this.relations[type] =
|
|
208
|
+
if (!this.relations[type]) this.relations[type] = safeObject();
|
|
205
209
|
this.relations[type][attribute] = this.types[value.type] || value.type;
|
|
206
210
|
}
|
|
207
211
|
}
|
|
@@ -222,7 +226,7 @@ var LegacyStore = class LegacyStore {
|
|
|
222
226
|
build(data) {
|
|
223
227
|
if (data.links) this.setupRelations(data.links);
|
|
224
228
|
let name;
|
|
225
|
-
for (const key
|
|
229
|
+
for (const key of Object.keys(data)) if (key !== "meta" && key !== "links") {
|
|
226
230
|
name = key;
|
|
227
231
|
break;
|
|
228
232
|
}
|
|
@@ -248,14 +252,14 @@ var LegacyStore = class LegacyStore {
|
|
|
248
252
|
return model;
|
|
249
253
|
}
|
|
250
254
|
find(type, id, models) {
|
|
251
|
-
return this.#findModel(type, String(id), models ?? this.models);
|
|
255
|
+
return this.#findModel(type, String(id), safeCache(models ?? this.models));
|
|
252
256
|
}
|
|
253
257
|
findAll(type, models) {
|
|
254
|
-
const modelsObj = models ?? this.models;
|
|
258
|
+
const modelsObj = safeCache(models ?? this.models);
|
|
255
259
|
const recs = this.findRecords(type);
|
|
256
260
|
if (recs.length === 0) return [];
|
|
257
261
|
recs.forEach((rec) => {
|
|
258
|
-
if (!modelsObj[type]) modelsObj[type] =
|
|
262
|
+
if (!modelsObj[type]) modelsObj[type] = safeObject();
|
|
259
263
|
return this.toModel(rec, type, modelsObj);
|
|
260
264
|
});
|
|
261
265
|
return Object.values(modelsObj[type] || {});
|
|
@@ -274,10 +278,10 @@ var LegacyStore = class LegacyStore {
|
|
|
274
278
|
}
|
|
275
279
|
syncAll(data) {
|
|
276
280
|
this.validationErrors = [];
|
|
277
|
-
this.models =
|
|
281
|
+
this.models = safeObject();
|
|
278
282
|
if (data.links) this.setupRelations(data.links);
|
|
279
283
|
const syncedRecords = [];
|
|
280
|
-
for (const name
|
|
284
|
+
for (const name of Object.keys(data)) {
|
|
281
285
|
if (name === "meta" || name === "links") continue;
|
|
282
286
|
const value = data[name];
|
|
283
287
|
const type = this.types[name] || name;
|
package/build/legacy.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legacy.mjs","names":["hasId","#findModel","#createStub","#resolveRelationships","#createModel","result","yaysonFactory"],"sources":["../src/yayson/legacy-presenter.ts","../src/yayson/legacy-store.ts","../src/legacy.ts"],"sourcesContent":["import type { ModelLike } from './adapter.js'\nimport type { Presenter } from './presenter.js'\nimport type { JsonApiDocument, JsonApiLinks, LegacyPresenterOptions } from './types.js'\nimport { filterByFields } from './utils.js'\n\nfunction hasId(value: unknown): value is { id: unknown } {\n return typeof value === 'object' && value !== null && 'id' in value\n}\n\ninterface LegacyJsonApiDocument extends JsonApiDocument {\n [key: string]: unknown\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is inferred from class\nexport default function createLegacyPresenter(Presenter: Presenter) {\n return class LegacyPresenter extends Presenter {\n declare ['constructor']: typeof LegacyPresenter\n declare scope: LegacyJsonApiDocument\n\n static type = 'object'\n static plural?: string\n static fields?: string[]\n\n constructor(scope?: JsonApiDocument) {\n // LegacyPresenter doesn't use the 'data' property, so pass an empty scope\n const emptyScope: JsonApiDocument = { data: null }\n super(scope || emptyScope)\n // Remove the 'data' property that the parent constructor adds\n if (!scope) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Need Partial to allow delete\n delete (this.scope as Partial<JsonApiDocument>).data\n }\n }\n\n pluralType(): string {\n return this.constructor.plural || this.constructor.type + 's'\n }\n\n attributes(instance: ModelLike | null): Record<string, unknown> {\n if (!instance) {\n return {}\n }\n const attributes = { ...this.constructor.adapter.get(instance) }\n const relationships = this.relationships()\n if (relationships) {\n for (const key in relationships) {\n let id: unknown\n const data = attributes[key]\n if (data == null) {\n id = attributes[key + 'Id']\n if (id != null) {\n attributes[key] = id\n }\n } else if (Array.isArray(data)) {\n attributes[key] = data.map((obj: unknown) => (hasId(obj) ? obj.id : obj))\n } else if (hasId(data)) {\n attributes[key] = data.id\n }\n }\n }\n\n // Include relationship keys in allowed fields (so users don't need to list them twice)\n const relationshipKeys = relationships ? Object.keys(relationships) : []\n const allowedFields = this.constructor.fields ? [...this.constructor.fields, ...relationshipKeys] : undefined\n\n return filterByFields(attributes, allowedFields)\n }\n\n includeRelationships(scope: LegacyJsonApiDocument, instance: ModelLike): unknown[] {\n if (!scope.links) {\n scope.links = {}\n }\n const relationships = this.relationships()\n const result: unknown[] = []\n\n if (!relationships) {\n return result\n }\n\n for (const key in relationships) {\n const factory = relationships[key]\n if (!factory) throw new Error(`Presenter for ${key} in ${this.constructor.type} is not defined`)\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Factory returns PresenterInstance, we know it's LegacyPresenter\n const presenter = new factory(scope) as LegacyPresenter\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- unknown from adapter.get\n const data = this.constructor.adapter.get(instance, key) as ModelLike | ModelLike[] | null\n if (data != null) {\n presenter.toJSON(data, { defaultPlural: true })\n }\n\n const type = scope[this.pluralType()] != null ? this.pluralType() : this.constructor.type\n const presenterType = presenter.constructor.type\n const keyName = scope[presenter.pluralType()] != null ? presenter.pluralType() : presenterType\n const link = { type: keyName }\n if (scope.links) {\n scope.links[`${type}.${key}`] = link\n }\n result.push(link)\n }\n return result\n }\n\n toJSON(\n instanceOrCollection: ModelLike | ModelLike[] | null | undefined,\n options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n const opts = options ?? {}\n if (!this.scope.links) {\n this.scope.links = {}\n }\n if (Array.isArray(instanceOrCollection)) {\n const collection = instanceOrCollection\n const type = this.pluralType()\n if (!this.scope[type]) {\n this.scope[type] = []\n }\n collection.forEach((instance: ModelLike) => {\n return this.toJSON(instance)\n })\n } else {\n let links: JsonApiLinks | undefined\n const instance = instanceOrCollection\n let added = true\n const attrs = instance ? this.attributes(instance) : null\n if ((links = this.links())) {\n if (attrs) {\n attrs.links = links\n }\n }\n // If eg x.image already exists\n if (this.scope[this.constructor.type] && !this.scope[this.pluralType()]) {\n const existingValue = this.scope[this.constructor.type]\n if (attrs && hasId(existingValue) && existingValue.id !== attrs.id) {\n this.scope[this.pluralType()] = [this.scope[this.constructor.type]]\n delete this.scope[this.constructor.type]\n const pluralArray = this.scope[this.pluralType()]\n if (Array.isArray(pluralArray)) {\n pluralArray.push(attrs)\n }\n } else {\n added = false\n }\n\n // If eg x.images already exists\n } else if (this.scope[this.pluralType()]) {\n const existing = this.scope[this.pluralType()]\n if (Array.isArray(existing)) {\n if (attrs && !existing.some((i) => hasId(i) && i.id === attrs.id)) {\n existing.push(attrs)\n } else {\n added = false\n }\n }\n } else if (opts.defaultPlural) {\n this.scope[this.pluralType()] = attrs ? [attrs] : []\n } else {\n this.scope[this.constructor.type] = attrs\n }\n\n if (added && instance) {\n this.includeRelationships(this.scope, instance)\n }\n }\n return this.scope\n }\n\n payload(instance: ModelLike): LegacyJsonApiDocument {\n if (Array.isArray(instance)) {\n throw new Error('payload() expects a single resource, not an array')\n }\n if (instance == null) {\n throw new Error('payload() requires a resource, got null')\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Legacy payload intentionally omits `data`\n return { [this.constructor.type]: this.attributes(instance) } as LegacyJsonApiDocument\n }\n\n render(instanceOrCollection: ModelLike | ModelLike[] | null): LegacyJsonApiDocument {\n return this.toJSON(instanceOrCollection)\n }\n\n static toJSON(\n instanceOrCollection: ModelLike | ModelLike[] | null,\n options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n return new this().toJSON(instanceOrCollection, options)\n }\n\n static render(\n instanceOrCollection: ModelLike | ModelLike[] | null,\n _options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n return new this().render(instanceOrCollection)\n }\n\n static payload(instance: ModelLike): LegacyJsonApiDocument {\n return new this().payload(instance)\n }\n }\n}\n","import type {\n StoreModel,\n StoreModelWithOptionalId,\n StoreModels,\n StoreResult,\n SchemaRegistry,\n ValidationError,\n InferModelType,\n LegacyStoreOptions,\n} from './types.js'\nimport { TYPE, LINKS, META } from './symbols.js'\nimport { validate } from './schema.js'\n\ninterface LegacyStoreRecordType {\n type: string\n data: Record<string, unknown> & {\n id?: string | number\n meta?: Record<string, unknown>\n links?: Record<string, unknown>\n }\n}\n\ninterface LegacyLinks {\n [key: string]: {\n type: string\n }\n}\n\ntype LegacyDataValue = Record<string, unknown> | Array<Record<string, unknown>>\n\nexport interface LegacyData {\n links?: LegacyLinks\n meta?: Record<string, unknown>\n [key: string]: LegacyDataValue | LegacyLinks | Record<string, unknown> | undefined\n}\n\nfunction hasId<T extends StoreModelWithOptionalId>(model: T): model is T & { id: string | number } {\n return model.id != null\n}\n\nexport default class LegacyStore<S extends SchemaRegistry = SchemaRegistry> {\n types: Record<string, string>\n records: LegacyStoreRecordType[]\n relations: Record<string, Record<string, string>>\n schemas?: S\n strict: boolean\n validationErrors: ValidationError[]\n models: StoreModels\n\n constructor(options?: LegacyStoreOptions<S>) {\n this.types = options?.types || {}\n this.schemas = options?.schemas\n this.strict = options?.strict ?? false\n this.records = []\n this.relations = {}\n this.validationErrors = []\n this.models = {}\n }\n\n reset(): void {\n this.records = []\n this.relations = {}\n this.validationErrors = []\n this.models = {}\n }\n\n #createStub(type: string, id: string): StoreModel {\n const stub: StoreModel = { id }\n stub[TYPE] = type\n return stub\n }\n\n #resolveRelationships(\n model: StoreModel | StoreModelWithOptionalId,\n type: string,\n resolver: (relationType: string, id: string) => StoreModel,\n ): void {\n const relations = this.relations[type]\n if (!relations) return\n\n for (const attribute in relations) {\n const relationType = relations[attribute]!\n const value = model[attribute]\n if (Array.isArray(value)) {\n model[attribute] = value\n .filter((id: unknown) => id != null)\n .map((id: unknown) => resolver(relationType, String(id)))\n } else if (value != null) {\n model[attribute] = resolver(relationType, String(value))\n } else {\n model[attribute] = null\n }\n }\n }\n\n #createModel(rec: LegacyStoreRecordType, type: string, options?: { models?: StoreModels }): StoreModelWithOptionalId {\n const models = options?.models\n\n const model: StoreModelWithOptionalId = { ...rec.data }\n if (rec.data.id != null) {\n model.id = rec.data.id\n }\n model[TYPE] = type\n if (rec.data.meta != null) {\n model[META] = rec.data.meta\n }\n if (rec.data.links != null) {\n model[LINKS] = rec.data.links\n }\n\n if (models && hasId(model)) {\n const idStr = String(model.id)\n if (!models[type]) {\n models[type] = {}\n }\n models[type]![idStr] = model\n }\n\n const resolver = (relationType: string, id: string): StoreModel => {\n return this.#findModel(relationType, id, models ?? {}) ?? this.#createStub(relationType, id)\n }\n this.#resolveRelationships(model, type, resolver)\n\n return model\n }\n\n toModel(rec: LegacyStoreRecordType, type: string, models: StoreModels): StoreModel {\n const idStr = String(rec.data.id)\n\n if (!models[type]) {\n models[type] = {}\n }\n\n if (models[type]![idStr]) {\n return models[type]![idStr]!\n }\n\n const result = this.#createModel(rec, type, { models })\n if (!hasId(result)) {\n throw new Error(`Expected model of type ${type} to have an id`)\n }\n const model = result\n\n if (this.schemas && this.schemas[type]) {\n const schema = this.schemas[type]\n const result = validate(schema, model, this.strict)\n\n if (!result.valid) {\n this.validationErrors.push({\n type,\n id: idStr,\n error: result.error,\n })\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Schema validation returns unknown, cast to StoreModel after validation\n const validatedModel = result.data as StoreModel\n\n // Preserve symbol keys from original model (schema validation may not preserve them)\n validatedModel[TYPE] = model[TYPE]\n validatedModel[LINKS] = model[LINKS]\n validatedModel[META] = model[META]\n\n models[type]![idStr] = validatedModel\n return validatedModel\n }\n\n return model\n }\n\n setupRelations(links: LegacyLinks): void {\n for (const key in links) {\n const value = links[key]!\n const parts = key.split('.')\n const typeRaw = parts[0]!\n const attribute = parts[1]!\n const type = this.types[typeRaw] || typeRaw\n if (!this.relations[type]) {\n this.relations[type] = {}\n }\n this.relations[type]![attribute] = this.types[value.type] || value.type\n }\n }\n\n findRecord(type: string, id: string): LegacyStoreRecordType | undefined {\n return this.records.find((r) => r.type === type && String(r.data.id) === id)\n }\n\n findRecords(type: string): LegacyStoreRecordType[] {\n return this.records.filter((r) => r.type === type)\n }\n\n #findModel(type: string, id: string, models: StoreModels): StoreModel | null {\n const rec = this.findRecord(type, id)\n if (rec == null) {\n return null\n }\n return models[type]?.[id] ?? this.toModel(rec, type, models)\n }\n\n static build(data: LegacyData): StoreModelWithOptionalId {\n return new LegacyStore().build(data)\n }\n\n build(data: LegacyData): StoreModelWithOptionalId {\n if (data.links) {\n this.setupRelations(data.links)\n }\n\n let name: string | undefined\n for (const key in data) {\n if (key !== 'meta' && key !== 'links') {\n name = key\n break\n }\n }\n\n if (name == null) {\n throw new Error('build() expects a single resource, not an array')\n }\n\n const value = data[name]\n if (value == null || Array.isArray(value)) {\n throw new Error('build() expects a single resource, not an array')\n }\n\n const type = this.types[name] || name\n return this.#createModel({ type, data: value }, type)\n }\n\n /** @deprecated Use retrieve() instead. */\n retrive<T extends string>(type: T, data: LegacyData): InferModelType<S, T> | null {\n return this.retrieve(type, data)\n }\n\n retrieve<T extends string>(type: T, data: LegacyData): InferModelType<S, T> | null {\n const synced = this.syncAll(data)\n const normalizedType = this.types[type] || type\n const model = synced.find((m) => m[TYPE] === normalizedType)\n if (!model) return null\n if (synced[META]) {\n model[META] = synced[META]\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n return model as InferModelType<S, T>\n }\n\n find<T extends string>(type: T, id: string | number, models?: StoreModels): InferModelType<S, T> | null {\n const result = this.#findModel(type, String(id), models ?? this.models)\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type inference: maps string literal type parameter to schema type\n return result as InferModelType<S, T> | null\n }\n\n findAll<T extends string>(type: T, models?: StoreModels): InferModelType<S, T>[] {\n const modelsObj = models ?? this.models\n const recs = this.findRecords(type)\n if (recs.length === 0) {\n return []\n }\n recs.forEach((rec) => {\n if (!modelsObj[type]) {\n modelsObj[type] = {}\n }\n return this.toModel(rec, type, modelsObj)\n })\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type inference: maps string literal type parameter to schema type\n return Object.values(modelsObj[type] || {}) as InferModelType<S, T>[]\n }\n\n remove(type: string, id?: string | number): void {\n const normalizedType = this.types[type] || type\n\n const removeOne = (record: LegacyStoreRecordType): void => {\n const index = this.records.indexOf(record)\n if (!(index < 0)) {\n this.records.splice(index, 1)\n }\n }\n\n if (id != null) {\n const idStr = String(id)\n const record = this.findRecord(normalizedType, idStr)\n if (record) {\n removeOne(record)\n }\n } else {\n const records = this.findRecords(normalizedType)\n records.forEach(removeOne)\n }\n }\n\n syncAll(data: LegacyData): StoreResult {\n // Clear validation errors and models cache from previous sync\n this.validationErrors = []\n this.models = {}\n\n if (data.links) {\n this.setupRelations(data.links)\n }\n\n const syncedRecords: LegacyStoreRecordType[] = []\n\n for (const name in data) {\n if (name === 'meta' || name === 'links') {\n continue\n }\n\n const value = data[name]!\n const type = this.types[name] || name\n\n const add = (d: Record<string, unknown>): void => {\n this.remove(type, String(d.id))\n const rec: LegacyStoreRecordType = { type, data: d }\n this.records.push(rec)\n syncedRecords.push(rec)\n }\n\n if (Array.isArray(value)) {\n value.forEach(add)\n } else if (typeof value === 'object' && value !== null) {\n add(value)\n }\n }\n\n for (const rec of syncedRecords) {\n this.toModel(rec, rec.type, this.models)\n }\n\n const result: StoreResult = syncedRecords.map((rec) => this.models[rec.type]![String(rec.data.id)]!)\n if (data.meta != null) {\n result[META] = data.meta\n }\n return result\n }\n\n sync(data: LegacyData): StoreModel | StoreResult {\n const result = this.syncAll(data)\n if (result.length === 1) {\n const model = result[0]\n if (result[META]) {\n model[META] = result[META]\n }\n return model\n }\n return result\n }\n\n retrieveAll<T extends string>(type: T, data: LegacyData): StoreResult<InferModelType<S, T>> {\n const normalizedType = this.types[type] || type\n const synced = this.syncAll(data)\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n const result: StoreResult<InferModelType<S, T>> = synced.filter(\n (model) => model[TYPE] === normalizedType,\n ) as StoreResult<InferModelType<S, T>>\n result[META] = synced[META]\n return result\n }\n}\n","import yaysonFactory from './yayson.js'\nimport createLegacyPresenter from './yayson/legacy-presenter.js'\nimport LegacyStore from './yayson/legacy-store.js'\nimport type { LegacyData } from './yayson/legacy-store.js'\nimport Adapter from './yayson/adapter.js'\nimport type {\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n} from './yayson/types.js'\nimport type { YaysonOptions } from './yayson.js'\n\nexport type {\n Adapter,\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n LegacyData,\n}\n\ninterface LegacyYaysonResult {\n Store: typeof LegacyStore\n Presenter: ReturnType<typeof createLegacyPresenter>\n Adapter: ReturnType<typeof yaysonFactory>['Adapter']\n}\n\nexport default function yayson(options?: YaysonOptions): LegacyYaysonResult {\n const { Presenter, Adapter } = yaysonFactory(options)\n return {\n Store: LegacyStore,\n Presenter: createLegacyPresenter(Presenter),\n Adapter,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"legacy.mjs","names":["hasId","#findModel","#createStub","#resolveRelationships","#createModel","result","yaysonFactory"],"sources":["../src/yayson/legacy-presenter.ts","../src/yayson/legacy-store.ts","../src/legacy.ts"],"sourcesContent":["import type { ModelLike } from './adapter.js'\nimport type { Presenter } from './presenter.js'\nimport type { JsonApiDocument, JsonApiLinks, LegacyPresenterOptions } from './types.js'\nimport { filterByFields } from './utils.js'\n\nfunction hasId(value: unknown): value is { id: unknown } {\n return typeof value === 'object' && value !== null && 'id' in value\n}\n\ninterface LegacyJsonApiDocument extends JsonApiDocument {\n [key: string]: unknown\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is inferred from class\nexport default function createLegacyPresenter(Presenter: Presenter) {\n return class LegacyPresenter extends Presenter {\n declare ['constructor']: typeof LegacyPresenter\n declare scope: LegacyJsonApiDocument\n\n static type = 'object'\n static plural?: string\n static fields?: string[]\n\n constructor(scope?: JsonApiDocument) {\n // LegacyPresenter doesn't use the 'data' property, so pass an empty scope\n const emptyScope: JsonApiDocument = { data: null }\n super(scope || emptyScope)\n // Remove the 'data' property that the parent constructor adds\n if (!scope) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Need Partial to allow delete\n delete (this.scope as Partial<JsonApiDocument>).data\n }\n }\n\n pluralType(): string {\n return this.constructor.plural || this.constructor.type + 's'\n }\n\n attributes(instance: ModelLike | null): Record<string, unknown> {\n if (!instance) {\n return {}\n }\n const attributes = { ...this.constructor.adapter.get(instance) }\n const relationships = this.relationships()\n if (relationships) {\n for (const key in relationships) {\n let id: unknown\n const data = attributes[key]\n if (data == null) {\n id = attributes[key + 'Id']\n if (id != null) {\n attributes[key] = id\n }\n } else if (Array.isArray(data)) {\n attributes[key] = data.map((obj: unknown) => (hasId(obj) ? obj.id : obj))\n } else if (hasId(data)) {\n attributes[key] = data.id\n }\n }\n }\n\n // Include relationship keys in allowed fields (so users don't need to list them twice)\n const relationshipKeys = relationships ? Object.keys(relationships) : []\n const allowedFields = this.constructor.fields ? [...this.constructor.fields, ...relationshipKeys] : undefined\n\n return filterByFields(attributes, allowedFields)\n }\n\n includeRelationships(scope: LegacyJsonApiDocument, instance: ModelLike): unknown[] {\n if (!scope.links) {\n scope.links = {}\n }\n const relationships = this.relationships()\n const result: unknown[] = []\n\n if (!relationships) {\n return result\n }\n\n for (const key in relationships) {\n const entry = relationships[key]\n if (!entry) throw new Error(`Presenter for ${key} in ${this.constructor.type} is not defined`)\n const factory = typeof entry === 'function' ? entry : entry.presenter\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Factory returns PresenterInstance, we know it's LegacyPresenter\n const presenter = new factory(scope) as LegacyPresenter\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- unknown from adapter.get\n const data = this.constructor.adapter.get(instance, key) as ModelLike | ModelLike[] | null\n if (data != null) {\n presenter.toJSON(data, { defaultPlural: true })\n }\n\n const type = scope[this.pluralType()] != null ? this.pluralType() : this.constructor.type\n const presenterType = presenter.constructor.type\n const keyName = scope[presenter.pluralType()] != null ? presenter.pluralType() : presenterType\n const link = { type: keyName }\n if (scope.links) {\n scope.links[`${type}.${key}`] = link\n }\n result.push(link)\n }\n return result\n }\n\n toJSON(\n instanceOrCollection: ModelLike | ModelLike[] | null | undefined,\n options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n const opts = options ?? {}\n if (!this.scope.links) {\n this.scope.links = {}\n }\n if (Array.isArray(instanceOrCollection)) {\n const collection = instanceOrCollection\n const type = this.pluralType()\n if (!this.scope[type]) {\n this.scope[type] = []\n }\n collection.forEach((instance: ModelLike) => {\n return this.toJSON(instance)\n })\n } else {\n let links: JsonApiLinks | undefined\n const instance = instanceOrCollection\n let added = true\n const attrs = instance ? this.attributes(instance) : null\n if ((links = this.links())) {\n if (attrs) {\n attrs.links = links\n }\n }\n // If eg x.image already exists\n if (this.scope[this.constructor.type] && !this.scope[this.pluralType()]) {\n const existingValue = this.scope[this.constructor.type]\n if (attrs && hasId(existingValue) && existingValue.id !== attrs.id) {\n this.scope[this.pluralType()] = [this.scope[this.constructor.type]]\n delete this.scope[this.constructor.type]\n const pluralArray = this.scope[this.pluralType()]\n if (Array.isArray(pluralArray)) {\n pluralArray.push(attrs)\n }\n } else {\n added = false\n }\n\n // If eg x.images already exists\n } else if (this.scope[this.pluralType()]) {\n const existing = this.scope[this.pluralType()]\n if (Array.isArray(existing)) {\n if (attrs && !existing.some((i) => hasId(i) && i.id === attrs.id)) {\n existing.push(attrs)\n } else {\n added = false\n }\n }\n } else if (opts.defaultPlural) {\n this.scope[this.pluralType()] = attrs ? [attrs] : []\n } else {\n this.scope[this.constructor.type] = attrs\n }\n\n if (added && instance) {\n this.includeRelationships(this.scope, instance)\n }\n }\n return this.scope\n }\n\n payload(instance: ModelLike): LegacyJsonApiDocument {\n if (Array.isArray(instance)) {\n throw new Error('payload() expects a single resource, not an array')\n }\n if (instance == null) {\n throw new Error('payload() requires a resource, got null')\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Legacy payload intentionally omits `data`\n return { [this.constructor.type]: this.attributes(instance) } as LegacyJsonApiDocument\n }\n\n render(instanceOrCollection: ModelLike | ModelLike[] | null): LegacyJsonApiDocument {\n return this.toJSON(instanceOrCollection)\n }\n\n static toJSON(\n instanceOrCollection: ModelLike | ModelLike[] | null,\n options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n return new this().toJSON(instanceOrCollection, options)\n }\n\n static render(\n instanceOrCollection: ModelLike | ModelLike[] | null,\n _options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n return new this().render(instanceOrCollection)\n }\n\n static payload(instance: ModelLike): LegacyJsonApiDocument {\n return new this().payload(instance)\n }\n }\n}\n","import type {\n StoreModel,\n StoreModelWithOptionalId,\n StoreModels,\n StoreResult,\n SchemaRegistry,\n ValidationError,\n InferModelType,\n LegacyStoreOptions,\n} from './types.js'\nimport { TYPE, LINKS, META } from './symbols.js'\nimport { validate } from './schema.js'\nimport { safeObject, safeCache, isUnsafeKey } from './safe.js'\n\ninterface LegacyStoreRecordType {\n type: string\n data: Record<string, unknown> & {\n id?: string | number\n meta?: Record<string, unknown>\n links?: Record<string, unknown>\n }\n}\n\ninterface LegacyLinks {\n [key: string]: {\n type: string\n }\n}\n\ntype LegacyDataValue = Record<string, unknown> | Array<Record<string, unknown>>\n\nexport interface LegacyData {\n links?: LegacyLinks\n meta?: Record<string, unknown>\n [key: string]: LegacyDataValue | LegacyLinks | Record<string, unknown> | undefined\n}\n\nfunction hasId<T extends StoreModelWithOptionalId>(model: T): model is T & { id: string | number } {\n return model.id != null\n}\n\nexport default class LegacyStore<S extends SchemaRegistry = SchemaRegistry> {\n types: Record<string, string>\n records: LegacyStoreRecordType[]\n relations: Record<string, Record<string, string>>\n schemas?: S\n strict: boolean\n validationErrors: ValidationError[]\n models: StoreModels\n\n constructor(options?: LegacyStoreOptions<S>) {\n // Null-prototype: read with untrusted `name`/`type` values, so \"__proto__\"\n // must not resolve to Object.prototype.\n this.types = safeObject<Record<string, string>>()\n Object.assign(this.types, options?.types)\n this.schemas = options?.schemas\n this.strict = options?.strict ?? false\n this.records = []\n this.relations = safeObject<Record<string, Record<string, string>>>()\n this.validationErrors = []\n this.models = safeObject<StoreModels>()\n }\n\n reset(): void {\n this.records = []\n this.relations = safeObject<Record<string, Record<string, string>>>()\n this.validationErrors = []\n this.models = safeObject<StoreModels>()\n }\n\n #createStub(type: string, id: string): StoreModel {\n const stub: StoreModel = { id }\n stub[TYPE] = type\n return stub\n }\n\n #resolveRelationships(\n model: StoreModel | StoreModelWithOptionalId,\n type: string,\n resolver: (relationType: string, id: string) => StoreModel,\n ): void {\n const relations = this.relations[type]\n if (!relations) return\n\n for (const attribute of Object.keys(relations)) {\n if (isUnsafeKey(attribute)) {\n continue\n }\n const relationType = relations[attribute]!\n const value = model[attribute]\n if (Array.isArray(value)) {\n model[attribute] = value\n .filter((id: unknown) => id != null)\n .map((id: unknown) => resolver(relationType, String(id)))\n } else if (value != null) {\n model[attribute] = resolver(relationType, String(value))\n } else {\n model[attribute] = null\n }\n }\n }\n\n #createModel(rec: LegacyStoreRecordType, type: string, options?: { models?: StoreModels }): StoreModelWithOptionalId {\n const models = options?.models\n\n const model: StoreModelWithOptionalId = { ...rec.data }\n if (rec.data.id != null) {\n model.id = rec.data.id\n }\n model[TYPE] = type\n if (rec.data.meta != null) {\n model[META] = rec.data.meta\n }\n if (rec.data.links != null) {\n model[LINKS] = rec.data.links\n }\n\n if (models && hasId(model)) {\n const idStr = String(model.id)\n if (!models[type]) {\n models[type] = safeObject<StoreModels[string]>()\n }\n models[type]![idStr] = model\n }\n\n const resolver = (relationType: string, id: string): StoreModel => {\n return (\n this.#findModel(relationType, id, models ?? safeObject<StoreModels>()) ?? this.#createStub(relationType, id)\n )\n }\n this.#resolveRelationships(model, type, resolver)\n\n return model\n }\n\n toModel(rec: LegacyStoreRecordType, type: string, modelsArg: StoreModels): StoreModel {\n const idStr = String(rec.data.id)\n const models = safeCache(modelsArg)\n\n if (!models[type]) {\n models[type] = safeObject<StoreModels[string]>()\n }\n\n if (models[type]![idStr]) {\n return models[type]![idStr]!\n }\n\n const result = this.#createModel(rec, type, { models })\n if (!hasId(result)) {\n throw new Error(`Expected model of type ${type} to have an id`)\n }\n const model = result\n\n if (this.schemas && this.schemas[type]) {\n const schema = this.schemas[type]\n const result = validate(schema, model, this.strict)\n\n if (!result.valid) {\n this.validationErrors.push({\n type,\n id: idStr,\n error: result.error,\n })\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Schema validation returns unknown, cast to StoreModel after validation\n const validatedModel = result.data as StoreModel\n\n // Preserve symbol keys from original model (schema validation may not preserve them)\n validatedModel[TYPE] = model[TYPE]\n validatedModel[LINKS] = model[LINKS]\n validatedModel[META] = model[META]\n\n models[type]![idStr] = validatedModel\n return validatedModel\n }\n\n return model\n }\n\n setupRelations(links: LegacyLinks): void {\n for (const key of Object.keys(links)) {\n const value = links[key]!\n const parts = key.split('.')\n const typeRaw = parts[0]!\n const attribute = parts[1]!\n if (isUnsafeKey(attribute)) {\n continue\n }\n const type = this.types[typeRaw] || typeRaw\n if (!this.relations[type]) {\n this.relations[type] = safeObject<Record<string, string>>()\n }\n this.relations[type]![attribute] = this.types[value.type] || value.type\n }\n }\n\n findRecord(type: string, id: string): LegacyStoreRecordType | undefined {\n return this.records.find((r) => r.type === type && String(r.data.id) === id)\n }\n\n findRecords(type: string): LegacyStoreRecordType[] {\n return this.records.filter((r) => r.type === type)\n }\n\n #findModel(type: string, id: string, models: StoreModels): StoreModel | null {\n const rec = this.findRecord(type, id)\n if (rec == null) {\n return null\n }\n return models[type]?.[id] ?? this.toModel(rec, type, models)\n }\n\n static build(data: LegacyData): StoreModelWithOptionalId {\n return new LegacyStore().build(data)\n }\n\n build(data: LegacyData): StoreModelWithOptionalId {\n if (data.links) {\n this.setupRelations(data.links)\n }\n\n let name: string | undefined\n for (const key of Object.keys(data)) {\n if (key !== 'meta' && key !== 'links') {\n name = key\n break\n }\n }\n\n if (name == null) {\n throw new Error('build() expects a single resource, not an array')\n }\n\n const value = data[name]\n if (value == null || Array.isArray(value)) {\n throw new Error('build() expects a single resource, not an array')\n }\n\n const type = this.types[name] || name\n return this.#createModel({ type, data: value }, type)\n }\n\n /** @deprecated Use retrieve() instead. */\n retrive<T extends string>(type: T, data: LegacyData): InferModelType<S, T> | null {\n return this.retrieve(type, data)\n }\n\n retrieve<T extends string>(type: T, data: LegacyData): InferModelType<S, T> | null {\n const synced = this.syncAll(data)\n const normalizedType = this.types[type] || type\n const model = synced.find((m) => m[TYPE] === normalizedType)\n if (!model) return null\n if (synced[META]) {\n model[META] = synced[META]\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n return model as InferModelType<S, T>\n }\n\n find<T extends string>(type: T, id: string | number, models?: StoreModels): InferModelType<S, T> | null {\n const result = this.#findModel(type, String(id), safeCache(models ?? this.models))\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type inference: maps string literal type parameter to schema type\n return result as InferModelType<S, T> | null\n }\n\n findAll<T extends string>(type: T, models?: StoreModels): InferModelType<S, T>[] {\n const modelsObj = safeCache(models ?? this.models)\n const recs = this.findRecords(type)\n if (recs.length === 0) {\n return []\n }\n recs.forEach((rec) => {\n if (!modelsObj[type]) {\n modelsObj[type] = safeObject<StoreModels[string]>()\n }\n return this.toModel(rec, type, modelsObj)\n })\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type inference: maps string literal type parameter to schema type\n return Object.values(modelsObj[type] || {}) as InferModelType<S, T>[]\n }\n\n remove(type: string, id?: string | number): void {\n const normalizedType = this.types[type] || type\n\n const removeOne = (record: LegacyStoreRecordType): void => {\n const index = this.records.indexOf(record)\n if (!(index < 0)) {\n this.records.splice(index, 1)\n }\n }\n\n if (id != null) {\n const idStr = String(id)\n const record = this.findRecord(normalizedType, idStr)\n if (record) {\n removeOne(record)\n }\n } else {\n const records = this.findRecords(normalizedType)\n records.forEach(removeOne)\n }\n }\n\n syncAll(data: LegacyData): StoreResult {\n // Clear validation errors and models cache from previous sync\n this.validationErrors = []\n this.models = safeObject<StoreModels>()\n\n if (data.links) {\n this.setupRelations(data.links)\n }\n\n const syncedRecords: LegacyStoreRecordType[] = []\n\n for (const name of Object.keys(data)) {\n if (name === 'meta' || name === 'links') {\n continue\n }\n\n const value = data[name]!\n const type = this.types[name] || name\n\n const add = (d: Record<string, unknown>): void => {\n this.remove(type, String(d.id))\n const rec: LegacyStoreRecordType = { type, data: d }\n this.records.push(rec)\n syncedRecords.push(rec)\n }\n\n if (Array.isArray(value)) {\n value.forEach(add)\n } else if (typeof value === 'object' && value !== null) {\n add(value)\n }\n }\n\n for (const rec of syncedRecords) {\n this.toModel(rec, rec.type, this.models)\n }\n\n const result: StoreResult = syncedRecords.map((rec) => this.models[rec.type]![String(rec.data.id)]!)\n if (data.meta != null) {\n result[META] = data.meta\n }\n return result\n }\n\n sync(data: LegacyData): StoreModel | StoreResult {\n const result = this.syncAll(data)\n if (result.length === 1) {\n const model = result[0]\n if (result[META]) {\n model[META] = result[META]\n }\n return model\n }\n return result\n }\n\n retrieveAll<T extends string>(type: T, data: LegacyData): StoreResult<InferModelType<S, T>> {\n const normalizedType = this.types[type] || type\n const synced = this.syncAll(data)\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n const result: StoreResult<InferModelType<S, T>> = synced.filter(\n (model) => model[TYPE] === normalizedType,\n ) as StoreResult<InferModelType<S, T>>\n result[META] = synced[META]\n return result\n }\n}\n","import yaysonFactory from './yayson.js'\nimport createLegacyPresenter from './yayson/legacy-presenter.js'\nimport LegacyStore from './yayson/legacy-store.js'\nimport type { LegacyData } from './yayson/legacy-store.js'\nimport Adapter from './yayson/adapter.js'\nimport type {\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n} from './yayson/types.js'\nimport type { YaysonOptions } from './yayson.js'\n\nexport type {\n Adapter,\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n LegacyData,\n}\n\ninterface LegacyYaysonResult {\n Store: typeof LegacyStore\n Presenter: ReturnType<typeof createLegacyPresenter>\n Adapter: ReturnType<typeof yaysonFactory>['Adapter']\n}\n\nexport default function yayson(options?: YaysonOptions): LegacyYaysonResult {\n const { Presenter, Adapter } = yaysonFactory(options)\n return {\n Store: LegacyStore,\n Presenter: createLegacyPresenter(Presenter),\n Adapter,\n }\n}\n"],"mappings":"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"}
|