1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | 'use strict';
|
7 |
|
8 | const g = require('strong-globalize')();
|
9 | const util = require('util');
|
10 | const Any = require('./types').Types.Any;
|
11 | const {
|
12 | applyParentProperty,
|
13 | } = require('./utils');
|
14 |
|
15 | module.exports = List;
|
16 |
|
17 | function 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 |
|
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 |
|
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 |
|
87 | util.inherits(List, Array);
|
88 |
|
89 | const _push = List.prototype.push;
|
90 |
|
91 | List.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 |
|
106 | List.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 |
|
113 | List.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 |
|
130 |
|
131 |
|
132 |
|
133 | List.prototype.toArray = function() {
|
134 | const items = [];
|
135 | this.forEach(function(item) {
|
136 | items.push(item);
|
137 | });
|
138 | return items;
|
139 | };
|
140 |
|
141 | List.prototype.toJSON = function() {
|
142 | return this.toObject(true);
|
143 | };
|
144 |
|
145 | List.prototype.toString = function() {
|
146 | return JSON.stringify(this.toJSON());
|
147 | };
|
148 |
|
149 | function isClass(fn) {
|
150 | return fn && fn.toString().indexOf('class ') === 0;
|
151 | }
|