@fjell/express-router 4.4.4 → 4.4.5
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/commit.sh +8 -0
- package/dist/CItemRouter.cjs +10 -15
- package/dist/CItemRouter.cjs.map +1 -1
- package/dist/CItemRouter.d.ts +1 -1
- package/dist/CItemRouter.js +10 -15
- package/dist/CItemRouter.js.map +1 -1
- package/dist/ItemRouter.cjs +61 -61
- package/dist/ItemRouter.cjs.map +1 -1
- package/dist/ItemRouter.d.ts +6 -6
- package/dist/ItemRouter.js +61 -61
- package/dist/ItemRouter.js.map +1 -1
- package/dist/PItemRouter.cjs +10 -15
- package/dist/PItemRouter.cjs.map +1 -1
- package/dist/PItemRouter.d.ts +1 -1
- package/dist/PItemRouter.js +10 -15
- package/dist/PItemRouter.js.map +1 -1
- package/dist/index.cjs +81 -89
- package/dist/index.cjs.map +1 -1
- package/dist/util/general.d.ts +4 -0
- package/package.json +11 -11
- package/pnpm-workspace.yaml.bak +4 -0
- package/release.sh +89 -0
- package/src/CItemRouter.ts +12 -14
- package/src/ItemRouter.ts +64 -53
- package/src/PItemRouter.ts +11 -12
- package/src/util/general.ts +65 -0
package/src/ItemRouter.ts
CHANGED
|
@@ -3,13 +3,12 @@ import {
|
|
|
3
3
|
cPK,
|
|
4
4
|
Item,
|
|
5
5
|
ItemEvent,
|
|
6
|
-
ItemProperties,
|
|
7
6
|
LocKey,
|
|
8
7
|
LocKeyArray,
|
|
9
8
|
PriKey,
|
|
10
9
|
validatePK
|
|
11
10
|
} from "@fjell/core";
|
|
12
|
-
import {
|
|
11
|
+
import { Instance, NotFoundError } from "@fjell/lib";
|
|
13
12
|
import deepmerge from "deepmerge";
|
|
14
13
|
import { Request, Response, Router } from "express";
|
|
15
14
|
import LibLogger from "./logger";
|
|
@@ -25,14 +24,14 @@ export class ItemRouter<
|
|
|
25
24
|
L5 extends string = never
|
|
26
25
|
> {
|
|
27
26
|
|
|
28
|
-
protected lib:
|
|
27
|
+
protected lib: Instance<Item<S, L1, L2, L3, L4, L5>, S, L1, L2, L3, L4, L5>;
|
|
29
28
|
private keyType: S;
|
|
30
29
|
protected options: ItemRouterOptions;
|
|
31
30
|
private childRouters: Record<string, Router> = {};
|
|
32
|
-
|
|
31
|
+
protected logger;
|
|
33
32
|
|
|
34
33
|
constructor(
|
|
35
|
-
lib:
|
|
34
|
+
lib: Instance<Item<S, L1, L2, L3, L4, L5>, S, L1, L2, L3, L4, L5>,
|
|
36
35
|
keyType: S,
|
|
37
36
|
options: ItemRouterOptions = {}
|
|
38
37
|
) {
|
|
@@ -76,21 +75,23 @@ export class ItemRouter<
|
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
protected postAllAction = async (req: Request, res: Response) => {
|
|
79
|
-
this.
|
|
78
|
+
const libOptions = this.lib.definition.options;
|
|
79
|
+
const libOperations = this.lib.operations;
|
|
80
|
+
this.logger.debug('Posting All Action', { query: req?.query, params: req?.params, locals: res?.locals });
|
|
80
81
|
const allActionKey = req.path.substring(req.path.lastIndexOf('/') + 1);
|
|
81
|
-
if (!
|
|
82
|
+
if (!libOptions.allActions) {
|
|
82
83
|
this.logger.error('Item Actions are not configured');
|
|
83
84
|
res.status(500).json({ error: 'Item Actions are not configured' });
|
|
84
85
|
return;
|
|
85
86
|
}
|
|
86
|
-
const allAction =
|
|
87
|
+
const allAction = libOptions.allActions[allActionKey];
|
|
87
88
|
if (!allAction) {
|
|
88
89
|
this.logger.error('All Action is not configured', { allActionKey });
|
|
89
90
|
res.status(500).json({ error: 'Item Action is not configured' });
|
|
90
91
|
return;
|
|
91
92
|
}
|
|
92
93
|
try {
|
|
93
|
-
res.json(await
|
|
94
|
+
res.json(await libOperations.allAction(allActionKey, req.body));
|
|
94
95
|
} catch (err: any) {
|
|
95
96
|
this.logger.error('Error in All Action', { message: err?.message, stack: err?.stack });
|
|
96
97
|
res.status(500).json(err);
|
|
@@ -98,14 +99,16 @@ export class ItemRouter<
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
protected getAllFacet = async (req: Request, res: Response) => {
|
|
101
|
-
this.
|
|
102
|
+
const libOptions = this.lib.definition.options;
|
|
103
|
+
const libOperations = this.lib.operations;
|
|
104
|
+
this.logger.debug('Getting All Facet', { query: req?.query, params: req?.params, locals: res?.locals });
|
|
102
105
|
const facetKey = req.path.substring(req.path.lastIndexOf('/') + 1);
|
|
103
|
-
if (!
|
|
106
|
+
if (!libOptions.allFacets) {
|
|
104
107
|
this.logger.error('Item Facets are not configured');
|
|
105
108
|
res.status(500).json({ error: 'Item Facets are not configured' });
|
|
106
109
|
return;
|
|
107
110
|
}
|
|
108
|
-
const facet =
|
|
111
|
+
const facet = libOptions.allFacets[facetKey];
|
|
109
112
|
if (!facet) {
|
|
110
113
|
this.logger.error('Item Facet is not configured', { facetKey });
|
|
111
114
|
res.status(500).json({ error: 'Item Facet is not configured' });
|
|
@@ -113,7 +116,7 @@ export class ItemRouter<
|
|
|
113
116
|
}
|
|
114
117
|
try {
|
|
115
118
|
const combinedQueryParams = { ...req.query, ...req.params } as Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>;
|
|
116
|
-
res.json(await
|
|
119
|
+
res.json(await libOperations.allFacet(facetKey, combinedQueryParams));
|
|
117
120
|
} catch (err: any) {
|
|
118
121
|
this.logger.error('Error in All Facet', { message: err?.message, stack: err?.stack });
|
|
119
122
|
res.status(500).json(err);
|
|
@@ -121,22 +124,24 @@ export class ItemRouter<
|
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
protected postItemAction = async (req: Request, res: Response) => {
|
|
124
|
-
this.
|
|
127
|
+
const libOptions = this.lib.definition.options;
|
|
128
|
+
const libOperations = this.lib.operations;
|
|
129
|
+
this.logger.debug('Getting Item', { query: req?.query, params: req?.params, locals: res?.locals });
|
|
125
130
|
const ik = this.getIk(res);
|
|
126
131
|
const actionKey = req.path.substring(req.path.lastIndexOf('/') + 1);
|
|
127
|
-
if (!
|
|
132
|
+
if (!libOptions.actions) {
|
|
128
133
|
this.logger.error('Item Actions are not configured');
|
|
129
134
|
res.status(500).json({ error: 'Item Actions are not configured' });
|
|
130
135
|
return;
|
|
131
136
|
}
|
|
132
|
-
const action =
|
|
137
|
+
const action = libOptions.actions[actionKey];
|
|
133
138
|
if (!action) {
|
|
134
139
|
this.logger.error('Item Action is not configured', { actionKey });
|
|
135
140
|
res.status(500).json({ error: 'Item Action is not configured' });
|
|
136
141
|
return;
|
|
137
142
|
}
|
|
138
143
|
try {
|
|
139
|
-
res.json(await
|
|
144
|
+
res.json(await libOperations.action(ik, actionKey, req.body));
|
|
140
145
|
} catch (err: any) {
|
|
141
146
|
this.logger.error('Error in Item Action', { message: err?.message, stack: err?.stack });
|
|
142
147
|
res.status(500).json(err);
|
|
@@ -144,15 +149,17 @@ export class ItemRouter<
|
|
|
144
149
|
}
|
|
145
150
|
|
|
146
151
|
protected getItemFacet = async (req: Request, res: Response) => {
|
|
147
|
-
this.
|
|
152
|
+
const libOptions = this.lib.definition.options;
|
|
153
|
+
const libOperations = this.lib.operations;
|
|
154
|
+
this.logger.debug('Getting Item', { query: req?.query, params: req?.params, locals: res?.locals });
|
|
148
155
|
const ik = this.getIk(res);
|
|
149
156
|
const facetKey = req.path.substring(req.path.lastIndexOf('/') + 1);
|
|
150
|
-
if (!
|
|
157
|
+
if (!libOptions.facets) {
|
|
151
158
|
this.logger.error('Item Facets are not configured');
|
|
152
159
|
res.status(500).json({ error: 'Item Facets are not configured' });
|
|
153
160
|
return;
|
|
154
161
|
}
|
|
155
|
-
const facet =
|
|
162
|
+
const facet = libOptions.facets[facetKey];
|
|
156
163
|
if (!facet) {
|
|
157
164
|
this.logger.error('Item Facet is not configured', { facetKey });
|
|
158
165
|
res.status(500).json({ error: 'Item Facet is not configured' });
|
|
@@ -160,7 +167,7 @@ export class ItemRouter<
|
|
|
160
167
|
}
|
|
161
168
|
try {
|
|
162
169
|
const combinedQueryParams = { ...req.query, ...req.params } as Record<string, string | number | boolean | Date | Array<string | number | boolean | Date>>;
|
|
163
|
-
res.json(await
|
|
170
|
+
res.json(await libOperations.facet(ik, facetKey, combinedQueryParams));
|
|
164
171
|
} catch (err: any) {
|
|
165
172
|
this.logger.error('Error in Item Facet', { message: err?.message, stack: err?.stack });
|
|
166
173
|
res.status(500).json(err);
|
|
@@ -168,23 +175,24 @@ export class ItemRouter<
|
|
|
168
175
|
}
|
|
169
176
|
|
|
170
177
|
private configure = (router: Router) => {
|
|
171
|
-
|
|
178
|
+
const libOptions = this.lib.definition.options;
|
|
179
|
+
this.logger.debug('Configuring Router', { pkType: this.getPkType() });
|
|
172
180
|
router.get('/', this.findItems);
|
|
173
181
|
router.post('/', this.createItem);
|
|
174
182
|
|
|
175
|
-
this.logger.
|
|
176
|
-
if (
|
|
177
|
-
Object.keys(
|
|
178
|
-
this.logger.
|
|
183
|
+
this.logger.default('All Actions supplied to Router', { allActions: libOptions.allActions });
|
|
184
|
+
if (libOptions.allActions) {
|
|
185
|
+
Object.keys(libOptions.allActions).forEach((actionKey) => {
|
|
186
|
+
this.logger.debug('Configuring All Action %s', actionKey);
|
|
179
187
|
// TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers
|
|
180
188
|
router.post(`/${actionKey}`, this.postAllAction);
|
|
181
189
|
});
|
|
182
190
|
}
|
|
183
191
|
|
|
184
|
-
this.logger.
|
|
185
|
-
if (
|
|
186
|
-
Object.keys(
|
|
187
|
-
this.logger.
|
|
192
|
+
this.logger.default('All Facets supplied to Router', { allFacets: libOptions.allFacets });
|
|
193
|
+
if (libOptions.allFacets) {
|
|
194
|
+
Object.keys(libOptions.allFacets).forEach((facetKey) => {
|
|
195
|
+
this.logger.debug('Configuring All Facet %s', facetKey);
|
|
188
196
|
// TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers
|
|
189
197
|
router.get(`/${facetKey}`, this.getAllFacet);
|
|
190
198
|
});
|
|
@@ -195,25 +203,25 @@ export class ItemRouter<
|
|
|
195
203
|
itemRouter.put('/', this.updateItem);
|
|
196
204
|
itemRouter.delete('/', this.deleteItem);
|
|
197
205
|
|
|
198
|
-
this.logger.
|
|
199
|
-
if (
|
|
200
|
-
Object.keys(
|
|
201
|
-
this.logger.
|
|
206
|
+
this.logger.default('Item Actions supplied to Router', { itemActions: libOptions.actions });
|
|
207
|
+
if (libOptions.actions) {
|
|
208
|
+
Object.keys(libOptions.actions).forEach((actionKey) => {
|
|
209
|
+
this.logger.debug('Configuring Item Action %s', actionKey);
|
|
202
210
|
// TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers
|
|
203
211
|
itemRouter.post(`/${actionKey}`, this.postItemAction)
|
|
204
212
|
});
|
|
205
213
|
}
|
|
206
214
|
|
|
207
|
-
this.logger.
|
|
208
|
-
if (
|
|
209
|
-
Object.keys(
|
|
210
|
-
this.logger.
|
|
215
|
+
this.logger.default('Item Facets supplied to Router', { itemFacets: libOptions.facets });
|
|
216
|
+
if (libOptions.facets) {
|
|
217
|
+
Object.keys(libOptions.facets).forEach((facetKey) => {
|
|
218
|
+
this.logger.debug('Configuring Item Facet %s', facetKey);
|
|
211
219
|
// TODO: Ok, this is a bit of a hack, but we need to customize the types of the request handlers
|
|
212
220
|
itemRouter.get(`/${facetKey}`, this.getItemFacet)
|
|
213
221
|
});
|
|
214
222
|
}
|
|
215
223
|
|
|
216
|
-
this.logger.
|
|
224
|
+
this.logger.debug('Configuring Item Operations under PK Param %s', this.getPkParam());
|
|
217
225
|
router.use(`/:${this.getPkParam()}`, this.validatePrimaryKeyValue, itemRouter);
|
|
218
226
|
|
|
219
227
|
if (this.childRouters) {
|
|
@@ -228,14 +236,14 @@ export class ItemRouter<
|
|
|
228
236
|
res.locals[this.getPkParam()] = pkParamValue;
|
|
229
237
|
next();
|
|
230
238
|
} else {
|
|
231
|
-
this.logger.error('Invalid Primary Key', { pkParamValue, path: req?.
|
|
232
|
-
res.status(500).json({ error: 'Invalid Primary Key', path: req?.
|
|
239
|
+
this.logger.error('Invalid Primary Key', { pkParamValue, path: req?.originalUrl });
|
|
240
|
+
res.status(500).json({ error: 'Invalid Primary Key', path: req?.originalUrl });
|
|
233
241
|
}
|
|
234
242
|
}
|
|
235
243
|
|
|
236
244
|
private configureChildRouters = (router: Router, childRouters: Record<string, Router>) => {
|
|
237
245
|
for (const path in childRouters) {
|
|
238
|
-
this.logger.
|
|
246
|
+
this.logger.debug('Configuring Child Router at Path %s', path);
|
|
239
247
|
|
|
240
248
|
router.use(`/${path}`, childRouters[path]);
|
|
241
249
|
}
|
|
@@ -262,14 +270,16 @@ export class ItemRouter<
|
|
|
262
270
|
// TODO: Probably a better way to do this, but this postCreate hook only needs the item.
|
|
263
271
|
/* istanbul ignore next */
|
|
264
272
|
public postCreateItem = async (item: Item<S, L1, L2, L3, L4, L5>): Promise<Item<S, L1, L2, L3, L4, L5>> => {
|
|
265
|
-
this.logger.
|
|
273
|
+
this.logger.debug('Post Create Item', { item });
|
|
266
274
|
return item;
|
|
267
275
|
};
|
|
268
276
|
|
|
269
277
|
protected deleteItem = async (req: Request, res: Response): Promise<void> => {
|
|
270
|
-
|
|
278
|
+
const libOperations = this.lib.operations;
|
|
279
|
+
|
|
280
|
+
this.logger.debug('Deleting Item', { query: req.query, params: req.params, locals: res.locals });
|
|
271
281
|
const ik = this.getIk(res);
|
|
272
|
-
const removedItem = await
|
|
282
|
+
const removedItem = await libOperations.remove(ik);
|
|
273
283
|
const item = validatePK(removedItem, this.getPkType());
|
|
274
284
|
res.json(item);
|
|
275
285
|
};
|
|
@@ -282,11 +292,12 @@ export class ItemRouter<
|
|
|
282
292
|
/* eslint-enable */
|
|
283
293
|
|
|
284
294
|
protected getItem = async (req: Request, res: Response) => {
|
|
285
|
-
|
|
295
|
+
const libOperations = this.lib.operations;
|
|
296
|
+
this.logger.debug('Getting Item', { query: req.query, params: req.params, locals: res.locals });
|
|
286
297
|
const ik = this.getIk(res);
|
|
287
298
|
try {
|
|
288
299
|
// TODO: What error does validate PK throw, when can that fail?
|
|
289
|
-
const item = validatePK(await
|
|
300
|
+
const item = validatePK(await libOperations.get(ik), this.getPkType());
|
|
290
301
|
res.json(item);
|
|
291
302
|
} catch (err: any) {
|
|
292
303
|
if (err instanceof NotFoundError) {
|
|
@@ -306,18 +317,18 @@ export class ItemRouter<
|
|
|
306
317
|
}
|
|
307
318
|
|
|
308
319
|
protected updateItem = async (req: Request, res: Response) => {
|
|
309
|
-
this.
|
|
320
|
+
const libOperations = this.lib.operations;
|
|
321
|
+
this.logger.debug('Updating Item',
|
|
310
322
|
{ body: req?.body, query: req?.query, params: req?.params, locals: res?.locals });
|
|
311
323
|
const ik = this.getIk(res);
|
|
312
|
-
const itemToUpdate = this.convertDates(req.body as
|
|
313
|
-
const retItem = validatePK(await
|
|
324
|
+
const itemToUpdate = this.convertDates(req.body as Partial<Item<S, L1, L2, L3, L4, L5>>);
|
|
325
|
+
const retItem = validatePK(await libOperations.update(ik, itemToUpdate), this.getPkType());
|
|
314
326
|
res.json(retItem);
|
|
315
327
|
};
|
|
316
328
|
|
|
317
|
-
public convertDates = (item: Item<S, L1, L2, L3, L4, L5
|
|
318
|
-
Item<S, L1, L2, L3, L4, L5> | ItemProperties<S, L1, L2, L3, L4, L5> => {
|
|
329
|
+
public convertDates = (item: Partial<Item<S, L1, L2, L3, L4, L5>>): Partial<Item<S, L1, L2, L3, L4, L5>> => {
|
|
319
330
|
const events = item.events as Record<string, ItemEvent>;
|
|
320
|
-
this.logger.
|
|
331
|
+
this.logger.debug('Converting Dates', { item });
|
|
321
332
|
if (events) {
|
|
322
333
|
Object.keys(events).forEach((key: string) => {
|
|
323
334
|
Object.assign(events, {
|
package/src/PItemRouter.ts
CHANGED
|
@@ -2,9 +2,6 @@ import { Item, ItemQuery, paramsToQuery, PriKey, QueryParams, validatePK } from
|
|
|
2
2
|
import { Primary } from "@fjell/lib";
|
|
3
3
|
import { ItemRouter, ItemRouterOptions } from "@/ItemRouter";
|
|
4
4
|
import { Request, Response } from "express";
|
|
5
|
-
import LibLogger from "@/logger";
|
|
6
|
-
|
|
7
|
-
const logger = LibLogger.get('PItemRouter');
|
|
8
5
|
|
|
9
6
|
interface ParsedQuery {
|
|
10
7
|
[key: string]: undefined | string | string[] | ParsedQuery | ParsedQuery[];
|
|
@@ -12,7 +9,7 @@ interface ParsedQuery {
|
|
|
12
9
|
|
|
13
10
|
export class PItemRouter<T extends Item<S>, S extends string> extends ItemRouter<S> {
|
|
14
11
|
|
|
15
|
-
constructor(lib: Primary.
|
|
12
|
+
constructor(lib: Primary.Instance<T, S>, keyType: S, options: ItemRouterOptions = {}) {
|
|
16
13
|
super(lib as any, keyType, options);
|
|
17
14
|
}
|
|
18
15
|
|
|
@@ -22,16 +19,18 @@ export class PItemRouter<T extends Item<S>, S extends string> extends ItemRouter
|
|
|
22
19
|
}
|
|
23
20
|
|
|
24
21
|
public createItem = async (req: Request, res: Response) => {
|
|
25
|
-
|
|
22
|
+
const libOperations = this.lib.operations;
|
|
23
|
+
this.logger.default('Creating Item', { body: req.body, query: req.query, params: req.params, locals: res.locals });
|
|
26
24
|
const itemToCreate = this.convertDates(req.body as Item<S>);
|
|
27
|
-
let item =
|
|
28
|
-
validatePK(await this.lib.create(itemToCreate), this.getPkType()) as Item<S>;
|
|
25
|
+
let item = validatePK(await libOperations.create(itemToCreate), this.getPkType()) as Item<S>;
|
|
29
26
|
item = await this.postCreateItem(item);
|
|
27
|
+
this.logger.default('Created Item %j', item);
|
|
30
28
|
res.json(item);
|
|
31
29
|
};
|
|
32
30
|
|
|
33
31
|
protected findItems = async (req: Request, res: Response) => {
|
|
34
|
-
|
|
32
|
+
const libOperations = this.lib.operations;
|
|
33
|
+
this.logger.default('Finding Items', { query: req.query, params: req.params, locals: res.locals });
|
|
35
34
|
|
|
36
35
|
let items: Item<S>[] = [];
|
|
37
36
|
|
|
@@ -42,19 +41,19 @@ export class PItemRouter<T extends Item<S>, S extends string> extends ItemRouter
|
|
|
42
41
|
|
|
43
42
|
if (finder) {
|
|
44
43
|
// If finder is defined? Call a finder.
|
|
45
|
-
logger.default('Finding Items with
|
|
44
|
+
this.logger.default('Finding Items with Finder %s %j one:%s', finder, finderParams, one);
|
|
46
45
|
|
|
47
46
|
if (one === 'true') {
|
|
48
47
|
const item = await (this.lib as any).findOne(finder, JSON.parse(finderParams));
|
|
49
48
|
items = item ? [item] : [];
|
|
50
49
|
} else {
|
|
51
|
-
items = await
|
|
50
|
+
items = await libOperations.find(finder, JSON.parse(finderParams));
|
|
52
51
|
}
|
|
53
52
|
} else {
|
|
54
|
-
logger.default('Finding Items with a query', { query: req.query });
|
|
55
53
|
// TODO: This is once of the more important places to perform some validaation and feedback
|
|
56
54
|
const itemQuery: ItemQuery = paramsToQuery(req.query as QueryParams);
|
|
57
|
-
|
|
55
|
+
this.logger.default('Finding Items with a query %j', itemQuery);
|
|
56
|
+
items = await libOperations.all(itemQuery);
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
res.json(items.map((item: Item<S>) => validatePK(item, this.getPkType())));
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
/* eslint-disable no-undefined */
|
|
3
|
+
export const clean = (obj: any) => {
|
|
4
|
+
return Object.fromEntries(
|
|
5
|
+
Object.entries(obj).filter(([_, v]) => v !== undefined)
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//Recursive implementation of jSON.stringify;
|
|
10
|
+
export const stringifyJSON = function (obj: any, visited: Set<any> = new Set()): string {
|
|
11
|
+
const arrOfKeyVals: string[] = [];
|
|
12
|
+
const arrVals: string[] = [];
|
|
13
|
+
let objKeys: string[] = [];
|
|
14
|
+
|
|
15
|
+
/*********CHECK FOR PRIMITIVE TYPES**********/
|
|
16
|
+
if (typeof obj === 'number' || typeof obj === 'boolean' || obj === null)
|
|
17
|
+
return '' + obj;
|
|
18
|
+
else if (typeof obj === 'string')
|
|
19
|
+
return '"' + obj + '"';
|
|
20
|
+
|
|
21
|
+
/*********DETECT CIRCULAR REFERENCES**********/
|
|
22
|
+
if (obj instanceof Object && visited.has(obj)) {
|
|
23
|
+
return '"(circular)"';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/*********CHECK FOR ARRAY**********/
|
|
27
|
+
else if (Array.isArray(obj)) {
|
|
28
|
+
//check for empty array
|
|
29
|
+
if (obj[0] === undefined)
|
|
30
|
+
return '[]';
|
|
31
|
+
else {
|
|
32
|
+
// Add array to visited before processing its elements
|
|
33
|
+
visited.add(obj);
|
|
34
|
+
obj.forEach(function (el) {
|
|
35
|
+
arrVals.push(stringifyJSON(el, visited));
|
|
36
|
+
});
|
|
37
|
+
return '[' + arrVals + ']';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/*********CHECK FOR OBJECT**********/
|
|
41
|
+
else if (obj instanceof Object) {
|
|
42
|
+
// Add object to visited before processing its properties
|
|
43
|
+
visited.add(obj);
|
|
44
|
+
//get object keys
|
|
45
|
+
objKeys = Object.keys(obj);
|
|
46
|
+
//set key output;
|
|
47
|
+
objKeys.forEach(function (key) {
|
|
48
|
+
const keyOut = '"' + key + '":';
|
|
49
|
+
const keyValOut = obj[key];
|
|
50
|
+
//skip functions and undefined properties
|
|
51
|
+
if (keyValOut instanceof Function || keyValOut === undefined)
|
|
52
|
+
return; // Skip this entry entirely instead of pushing an empty string
|
|
53
|
+
else if (typeof keyValOut === 'string')
|
|
54
|
+
arrOfKeyVals.push(keyOut + '"' + keyValOut + '"');
|
|
55
|
+
else if (typeof keyValOut === 'boolean' || typeof keyValOut === 'number' || keyValOut === null)
|
|
56
|
+
arrOfKeyVals.push(keyOut + keyValOut);
|
|
57
|
+
//check for nested objects, call recursively until no more objects
|
|
58
|
+
else if (keyValOut instanceof Object) {
|
|
59
|
+
arrOfKeyVals.push(keyOut + stringifyJSON(keyValOut, visited));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return '{' + arrOfKeyVals + '}';
|
|
63
|
+
}
|
|
64
|
+
return '';
|
|
65
|
+
};
|