UNPKG

3.56 kBJavaScriptView Raw
1// Copyright IBM Corp. 2012,2019. All Rights Reserved.
2// Node module: loopback-datasource-juggler
3// This file is licensed under the MIT License.
4// License text available at https://opensource.org/licenses/MIT
5
6'use strict';
7
8const g = require('strong-globalize')();
9const util = require('util');
10const Any = require('./types').Types.Any;
11const {
12 applyParentProperty,
13} = require('./utils');
14
15module.exports = List;
16
17function List(items, itemType, parent) {
18 const list = this;
19 if (!(list instanceof List)) {
20 return new List(items, itemType, parent);
21 }
22
23 if (typeof items === 'string') {
24 try {
25 items = JSON.parse(items);
26 } catch (e) {
27 const err = new Error(g.f('could not create List from JSON string: %j', items));
28 err.statusCode = 400;
29 throw err;
30 }
31 }
32
33 if (typeof items === 'number') {
34 // trying to initialise empty array with a length
35 items = [...new Array(items)];
36 }
37
38 const arr = [];
39 arr.__proto__ = List.prototype;
40
41 items = items || [];
42 if (!Array.isArray(items)) {
43 const err = new Error(g.f('Items must be an array: %j', items));
44 err.statusCode = 400;
45 throw err;
46 }
47
48 if (!itemType) {
49 itemType = items[0] && items[0].constructor;
50 }
51
52 if (Array.isArray(itemType)) {
53 itemType = itemType[0];
54 }
55
56 if (itemType === Array) {
57 itemType = Any;
58 }
59
60 Object.defineProperty(arr, 'itemType', {
61 writable: true,
62 enumerable: false,
63 value: itemType,
64 });
65
66 if (parent) {
67 // List constructor now called with actual model instance
68 Object.defineProperty(arr, 'parent', {
69 writable: true,
70 enumerable: false,
71 value: parent,
72 });
73 }
74
75 items.forEach(function(item, i) {
76 if (itemType && !(item instanceof itemType)) {
77 arr[i] = arr.toItem(item);
78 } else {
79 arr[i] = item;
80 }
81 if (parent && arr[i] && typeof arr[i] === 'object') applyParentProperty(arr[i], parent);
82 });
83
84 return arr;
85}
86
87util.inherits(List, Array);
88
89const _push = List.prototype.push;
90
91List.prototype.toItem = function(item) {
92 if (isClass(this.itemType)) {
93 return new this.itemType(item);
94 } else {
95 if (Array.isArray(item)) {
96 return item;
97 } else if (this.itemType === Date) {
98 if (item === null) return null;
99 return new Date(item);
100 } else {
101 return this.itemType(item);
102 }
103 }
104};
105
106List.prototype.push = function(obj) {
107 const item = this.itemType && (obj instanceof this.itemType) ? obj : this.toItem(obj);
108 if (item && typeof item === 'object' && this.parent) applyParentProperty(item, this.parent);
109 _push.call(this, item);
110 return item;
111};
112
113List.prototype.toObject = function(onlySchema, removeHidden, removeProtected) {
114 const items = [];
115 this.forEach(function(item) {
116 if (item && Array.isArray(item) && item.toArray) {
117 const subArray = item.toArray();
118 items.push(subArray);
119 } else if (item && typeof item === 'object' && item.toObject) {
120 items.push(item.toObject(onlySchema, removeHidden, removeProtected));
121 } else {
122 items.push(item);
123 }
124 });
125 return items;
126};
127
128/**
129 * Convert itself to a plain array.
130 *
131 * Some modules such as `should` checks prototype for comparison
132 */
133List.prototype.toArray = function() {
134 const items = [];
135 this.forEach(function(item) {
136 items.push(item);
137 });
138 return items;
139};
140
141List.prototype.toJSON = function() {
142 return this.toObject(true);
143};
144
145List.prototype.toString = function() {
146 return JSON.stringify(this.toJSON());
147};
148
149function isClass(fn) {
150 return fn && fn.toString().indexOf('class ') === 0;
151}