json-server 0.17.4 → 1.0.0-alpha.10
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/LICENSE +44 -20
- package/README.md +81 -555
- package/lib/app.d.ts +8 -0
- package/lib/app.js +92 -0
- package/lib/app.test.d.ts +1 -0
- package/lib/app.test.js +90 -0
- package/lib/bin.d.ts +2 -0
- package/lib/bin.js +109 -0
- package/lib/observer.d.ts +11 -0
- package/lib/observer.js +30 -0
- package/lib/service.d.ts +39 -0
- package/lib/service.js +281 -0
- package/lib/service.test.d.ts +1 -0
- package/lib/service.test.js +294 -0
- package/package.json +40 -89
- package/public/output.css +1164 -0
- package/lib/cli/bin.js +0 -5
- package/lib/cli/index.js +0 -77
- package/lib/cli/run.js +0 -213
- package/lib/cli/utils/is.js +0 -16
- package/lib/cli/utils/load.js +0 -69
- package/lib/server/body-parser.js +0 -9
- package/lib/server/defaults.js +0 -73
- package/lib/server/index.js +0 -10
- package/lib/server/mixins.js +0 -76
- package/lib/server/rewriter.js +0 -14
- package/lib/server/router/delay.js +0 -10
- package/lib/server/router/get-full-url.js +0 -10
- package/lib/server/router/index.js +0 -91
- package/lib/server/router/nested.js +0 -26
- package/lib/server/router/plural.js +0 -273
- package/lib/server/router/singular.js +0 -52
- package/lib/server/router/validate-data.js +0 -17
- package/lib/server/router/write.js +0 -8
- package/lib/server/utils.js +0 -26
- package/public/favicon.ico +0 -0
- package/public/index.html +0 -85
- package/public/script.js +0 -76
- package/public/style.css +0 -113
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const express = require('express');
|
|
4
|
-
const pluralize = require('pluralize');
|
|
5
|
-
const delay = require('./delay');
|
|
6
|
-
module.exports = opts => {
|
|
7
|
-
const router = express.Router();
|
|
8
|
-
router.use(delay);
|
|
9
|
-
|
|
10
|
-
// Rewrite URL (/:resource/:id/:nested -> /:nested) and request query
|
|
11
|
-
function get(req, res, next) {
|
|
12
|
-
const prop = pluralize.singular(req.params.resource);
|
|
13
|
-
req.query[`${prop}${opts.foreignKeySuffix}`] = req.params.id;
|
|
14
|
-
req.url = `/${req.params.nested}`;
|
|
15
|
-
next();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Rewrite URL (/:resource/:id/:nested -> /:nested) and request body
|
|
19
|
-
function post(req, res, next) {
|
|
20
|
-
const prop = pluralize.singular(req.params.resource);
|
|
21
|
-
req.body[`${prop}${opts.foreignKeySuffix}`] = req.params.id;
|
|
22
|
-
req.url = `/${req.params.nested}`;
|
|
23
|
-
next();
|
|
24
|
-
}
|
|
25
|
-
return router.get('/:resource/:id/:nested', get).post('/:resource/:id/:nested', post);
|
|
26
|
-
};
|
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5
|
-
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
|
-
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
7
|
-
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
8
|
-
const express = require('express');
|
|
9
|
-
const _ = require('lodash');
|
|
10
|
-
const pluralize = require('pluralize');
|
|
11
|
-
const write = require('./write');
|
|
12
|
-
const getFullURL = require('./get-full-url');
|
|
13
|
-
const utils = require('../utils');
|
|
14
|
-
const delay = require('./delay');
|
|
15
|
-
module.exports = (db, name, opts) => {
|
|
16
|
-
// Create router
|
|
17
|
-
const router = express.Router();
|
|
18
|
-
router.use(delay);
|
|
19
|
-
|
|
20
|
-
// Embed function used in GET /name and GET /name/id
|
|
21
|
-
function embed(resource, e) {
|
|
22
|
-
e && [].concat(e).forEach(externalResource => {
|
|
23
|
-
if (db.get(externalResource).value) {
|
|
24
|
-
const query = {};
|
|
25
|
-
const singularResource = pluralize.singular(name);
|
|
26
|
-
query[`${singularResource}${opts.foreignKeySuffix}`] = resource.id;
|
|
27
|
-
resource[externalResource] = db.get(externalResource).filter(query).value();
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Expand function used in GET /name and GET /name/id
|
|
33
|
-
function expand(resource, e) {
|
|
34
|
-
e && [].concat(e).forEach(innerResource => {
|
|
35
|
-
const plural = pluralize(innerResource);
|
|
36
|
-
if (db.get(plural).value()) {
|
|
37
|
-
const prop = `${innerResource}${opts.foreignKeySuffix}`;
|
|
38
|
-
resource[innerResource] = db.get(plural).getById(resource[prop]).value();
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// GET /name
|
|
44
|
-
// GET /name?q=
|
|
45
|
-
// GET /name?attr=&attr=
|
|
46
|
-
// GET /name?_end=&
|
|
47
|
-
// GET /name?_start=&_end=&
|
|
48
|
-
// GET /name?_embed=&_expand=
|
|
49
|
-
function list(req, res, next) {
|
|
50
|
-
// Resource chain
|
|
51
|
-
let chain = db.get(name);
|
|
52
|
-
|
|
53
|
-
// Remove q, _start, _end, ... from req.query to avoid filtering using those
|
|
54
|
-
// parameters
|
|
55
|
-
let q = req.query.q;
|
|
56
|
-
let _start = req.query._start;
|
|
57
|
-
let _end = req.query._end;
|
|
58
|
-
let _page = req.query._page;
|
|
59
|
-
const _sort = req.query._sort;
|
|
60
|
-
const _order = req.query._order;
|
|
61
|
-
let _limit = req.query._limit;
|
|
62
|
-
const _embed = req.query._embed;
|
|
63
|
-
const _expand = req.query._expand;
|
|
64
|
-
delete req.query.q;
|
|
65
|
-
delete req.query._start;
|
|
66
|
-
delete req.query._end;
|
|
67
|
-
delete req.query._sort;
|
|
68
|
-
delete req.query._order;
|
|
69
|
-
delete req.query._limit;
|
|
70
|
-
delete req.query._embed;
|
|
71
|
-
delete req.query._expand;
|
|
72
|
-
|
|
73
|
-
// Automatically delete query parameters that can't be found
|
|
74
|
-
// in the database
|
|
75
|
-
Object.keys(req.query).forEach(query => {
|
|
76
|
-
const arr = db.get(name).value();
|
|
77
|
-
for (const i in arr) {
|
|
78
|
-
if (_.has(arr[i], query) || query === 'callback' || query === '_' || /_lte$/.test(query) || /_gte$/.test(query) || /_ne$/.test(query) || /_like$/.test(query)) return;
|
|
79
|
-
}
|
|
80
|
-
delete req.query[query];
|
|
81
|
-
});
|
|
82
|
-
if (q) {
|
|
83
|
-
// Full-text search
|
|
84
|
-
if (Array.isArray(q)) {
|
|
85
|
-
q = q[0];
|
|
86
|
-
}
|
|
87
|
-
q = q.toLowerCase();
|
|
88
|
-
chain = chain.filter(obj => {
|
|
89
|
-
for (const key in obj) {
|
|
90
|
-
const value = obj[key];
|
|
91
|
-
if (db._.deepQuery(value, q)) {
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return false;
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
Object.keys(req.query).forEach(key => {
|
|
99
|
-
// Don't take into account JSONP query parameters
|
|
100
|
-
// jQuery adds a '_' query parameter too
|
|
101
|
-
if (key !== 'callback' && key !== '_') {
|
|
102
|
-
// Always use an array, in case req.query is an array
|
|
103
|
-
const arr = [].concat(req.query[key]);
|
|
104
|
-
const isDifferent = /_ne$/.test(key);
|
|
105
|
-
const isRange = /_lte$/.test(key) || /_gte$/.test(key);
|
|
106
|
-
const isLike = /_like$/.test(key);
|
|
107
|
-
const path = key.replace(/(_lte|_gte|_ne|_like)$/, '');
|
|
108
|
-
chain = chain.filter(element => {
|
|
109
|
-
return arr.map(function (value) {
|
|
110
|
-
// get item value based on path
|
|
111
|
-
// i.e post.title -> 'foo'
|
|
112
|
-
const elementValue = _.get(element, path);
|
|
113
|
-
|
|
114
|
-
// Prevent toString() failing on undefined or null values
|
|
115
|
-
if (elementValue === undefined || elementValue === null) {
|
|
116
|
-
return undefined;
|
|
117
|
-
}
|
|
118
|
-
if (isRange) {
|
|
119
|
-
const isLowerThan = /_gte$/.test(key);
|
|
120
|
-
return isLowerThan ? value <= elementValue : value >= elementValue;
|
|
121
|
-
} else if (isDifferent) {
|
|
122
|
-
return value !== elementValue.toString();
|
|
123
|
-
} else if (isLike) {
|
|
124
|
-
return new RegExp(value, 'i').test(elementValue.toString());
|
|
125
|
-
} else {
|
|
126
|
-
return value === elementValue.toString();
|
|
127
|
-
}
|
|
128
|
-
}).reduce((a, b) => isDifferent ? a && b : a || b);
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Sort
|
|
134
|
-
if (_sort) {
|
|
135
|
-
const _sortSet = _sort.split(',');
|
|
136
|
-
const _orderSet = (_order || '').split(',').map(s => s.toLowerCase());
|
|
137
|
-
chain = chain.orderBy(_sortSet, _orderSet);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Slice result
|
|
141
|
-
if (_end || _limit || _page) {
|
|
142
|
-
res.setHeader('X-Total-Count', chain.size());
|
|
143
|
-
res.setHeader('Access-Control-Expose-Headers', `X-Total-Count${_page ? ', Link' : ''}`);
|
|
144
|
-
}
|
|
145
|
-
if (_page) {
|
|
146
|
-
_page = parseInt(_page, 10);
|
|
147
|
-
_page = _page >= 1 ? _page : 1;
|
|
148
|
-
_limit = parseInt(_limit, 10) || 10;
|
|
149
|
-
const page = utils.getPage(chain.value(), _page, _limit);
|
|
150
|
-
const links = {};
|
|
151
|
-
const fullURL = getFullURL(req);
|
|
152
|
-
if (page.first) {
|
|
153
|
-
links.first = fullURL.replace(`page=${page.current}`, `page=${page.first}`);
|
|
154
|
-
}
|
|
155
|
-
if (page.prev) {
|
|
156
|
-
links.prev = fullURL.replace(`page=${page.current}`, `page=${page.prev}`);
|
|
157
|
-
}
|
|
158
|
-
if (page.next) {
|
|
159
|
-
links.next = fullURL.replace(`page=${page.current}`, `page=${page.next}`);
|
|
160
|
-
}
|
|
161
|
-
if (page.last) {
|
|
162
|
-
links.last = fullURL.replace(`page=${page.current}`, `page=${page.last}`);
|
|
163
|
-
}
|
|
164
|
-
res.links(links);
|
|
165
|
-
chain = _.chain(page.items);
|
|
166
|
-
} else if (_end) {
|
|
167
|
-
_start = parseInt(_start, 10) || 0;
|
|
168
|
-
_end = parseInt(_end, 10);
|
|
169
|
-
chain = chain.slice(_start, _end);
|
|
170
|
-
} else if (_limit) {
|
|
171
|
-
_start = parseInt(_start, 10) || 0;
|
|
172
|
-
_limit = parseInt(_limit, 10);
|
|
173
|
-
chain = chain.slice(_start, _start + _limit);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// embed and expand
|
|
177
|
-
chain = chain.cloneDeep().forEach(function (element) {
|
|
178
|
-
embed(element, _embed);
|
|
179
|
-
expand(element, _expand);
|
|
180
|
-
});
|
|
181
|
-
res.locals.data = chain.value();
|
|
182
|
-
next();
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// GET /name/:id
|
|
186
|
-
// GET /name/:id?_embed=&_expand
|
|
187
|
-
function show(req, res, next) {
|
|
188
|
-
const _embed = req.query._embed;
|
|
189
|
-
const _expand = req.query._expand;
|
|
190
|
-
const resource = db.get(name).getById(req.params.id).value();
|
|
191
|
-
if (resource) {
|
|
192
|
-
// Clone resource to avoid making changes to the underlying object
|
|
193
|
-
const clone = _.cloneDeep(resource);
|
|
194
|
-
|
|
195
|
-
// Embed other resources based on resource id
|
|
196
|
-
// /posts/1?_embed=comments
|
|
197
|
-
embed(clone, _embed);
|
|
198
|
-
|
|
199
|
-
// Expand inner resources based on id
|
|
200
|
-
// /posts/1?_expand=user
|
|
201
|
-
expand(clone, _expand);
|
|
202
|
-
res.locals.data = clone;
|
|
203
|
-
}
|
|
204
|
-
next();
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// POST /name
|
|
208
|
-
function create(req, res, next) {
|
|
209
|
-
let resource;
|
|
210
|
-
if (opts._isFake) {
|
|
211
|
-
const id = db.get(name).createId().value();
|
|
212
|
-
resource = _objectSpread(_objectSpread({}, req.body), {}, {
|
|
213
|
-
id
|
|
214
|
-
});
|
|
215
|
-
} else {
|
|
216
|
-
resource = db.get(name).insert(req.body).value();
|
|
217
|
-
}
|
|
218
|
-
res.setHeader('Access-Control-Expose-Headers', 'Location');
|
|
219
|
-
res.location(`${getFullURL(req)}/${resource.id}`);
|
|
220
|
-
res.status(201);
|
|
221
|
-
res.locals.data = resource;
|
|
222
|
-
next();
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// PUT /name/:id
|
|
226
|
-
// PATCH /name/:id
|
|
227
|
-
function update(req, res, next) {
|
|
228
|
-
const id = req.params.id;
|
|
229
|
-
let resource;
|
|
230
|
-
if (opts._isFake) {
|
|
231
|
-
resource = db.get(name).getById(id).value();
|
|
232
|
-
if (req.method === 'PATCH') {
|
|
233
|
-
resource = _objectSpread(_objectSpread({}, resource), req.body);
|
|
234
|
-
} else {
|
|
235
|
-
resource = _objectSpread(_objectSpread({}, req.body), {}, {
|
|
236
|
-
id: resource.id
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
} else {
|
|
240
|
-
let chain = db.get(name);
|
|
241
|
-
chain = req.method === 'PATCH' ? chain.updateById(id, req.body) : chain.replaceById(id, req.body);
|
|
242
|
-
resource = chain.value();
|
|
243
|
-
}
|
|
244
|
-
if (resource) {
|
|
245
|
-
res.locals.data = resource;
|
|
246
|
-
}
|
|
247
|
-
next();
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// DELETE /name/:id
|
|
251
|
-
function destroy(req, res, next) {
|
|
252
|
-
let resource;
|
|
253
|
-
if (opts._isFake) {
|
|
254
|
-
resource = db.get(name).value();
|
|
255
|
-
} else {
|
|
256
|
-
resource = db.get(name).removeById(req.params.id).value();
|
|
257
|
-
|
|
258
|
-
// Remove dependents documents
|
|
259
|
-
const removable = db._.getRemovable(db.getState(), opts);
|
|
260
|
-
removable.forEach(item => {
|
|
261
|
-
db.get(item.name).removeById(item.id).value();
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
if (resource) {
|
|
265
|
-
res.locals.data = {};
|
|
266
|
-
}
|
|
267
|
-
next();
|
|
268
|
-
}
|
|
269
|
-
const w = write(db);
|
|
270
|
-
router.route('/').get(list).post(create, w);
|
|
271
|
-
router.route('/:id').get(show).put(update, w).patch(update, w).delete(destroy, w);
|
|
272
|
-
return router;
|
|
273
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
4
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
5
|
-
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
|
-
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
7
|
-
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
8
|
-
const express = require('express');
|
|
9
|
-
const write = require('./write');
|
|
10
|
-
const getFullURL = require('./get-full-url');
|
|
11
|
-
const delay = require('./delay');
|
|
12
|
-
module.exports = (db, name, opts) => {
|
|
13
|
-
const router = express.Router();
|
|
14
|
-
router.use(delay);
|
|
15
|
-
function show(req, res, next) {
|
|
16
|
-
res.locals.data = db.get(name).value();
|
|
17
|
-
next();
|
|
18
|
-
}
|
|
19
|
-
function create(req, res, next) {
|
|
20
|
-
if (opts._isFake) {
|
|
21
|
-
res.locals.data = req.body;
|
|
22
|
-
} else {
|
|
23
|
-
db.set(name, req.body).value();
|
|
24
|
-
res.locals.data = db.get(name).value();
|
|
25
|
-
}
|
|
26
|
-
res.setHeader('Access-Control-Expose-Headers', 'Location');
|
|
27
|
-
res.location(`${getFullURL(req)}`);
|
|
28
|
-
res.status(201);
|
|
29
|
-
next();
|
|
30
|
-
}
|
|
31
|
-
function update(req, res, next) {
|
|
32
|
-
if (opts._isFake) {
|
|
33
|
-
if (req.method === 'PUT') {
|
|
34
|
-
res.locals.data = req.body;
|
|
35
|
-
} else {
|
|
36
|
-
const resource = db.get(name).value();
|
|
37
|
-
res.locals.data = _objectSpread(_objectSpread({}, resource), req.body);
|
|
38
|
-
}
|
|
39
|
-
} else {
|
|
40
|
-
if (req.method === 'PUT') {
|
|
41
|
-
db.set(name, req.body).value();
|
|
42
|
-
} else {
|
|
43
|
-
db.get(name).assign(req.body).value();
|
|
44
|
-
}
|
|
45
|
-
res.locals.data = db.get(name).value();
|
|
46
|
-
}
|
|
47
|
-
next();
|
|
48
|
-
}
|
|
49
|
-
const w = write(db);
|
|
50
|
-
router.route('/').get(show).post(create, w).put(update, w).patch(update, w);
|
|
51
|
-
return router;
|
|
52
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const _ = require('lodash');
|
|
4
|
-
function validateKey(key) {
|
|
5
|
-
if (key.indexOf('/') !== -1) {
|
|
6
|
-
const msg = [`Oops, found / character in database property '${key}'.`, '', "/ aren't supported, if you want to tweak default routes, see", 'https://github.com/typicode/json-server/#add-custom-routes'].join('\n');
|
|
7
|
-
throw new Error(msg);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
module.exports = obj => {
|
|
11
|
-
if (_.isPlainObject(obj)) {
|
|
12
|
-
Object.keys(obj).forEach(validateKey);
|
|
13
|
-
} else {
|
|
14
|
-
throw new Error(`Data must be an object. Found ${Array.isArray(obj) ? 'array' : typeof obj}.
|
|
15
|
-
'See https://github.com/typicode/json-server for example.`);
|
|
16
|
-
}
|
|
17
|
-
};
|
package/lib/server/utils.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
module.exports = {
|
|
4
|
-
getPage
|
|
5
|
-
};
|
|
6
|
-
function getPage(array, page, perPage) {
|
|
7
|
-
const obj = {};
|
|
8
|
-
const start = (page - 1) * perPage;
|
|
9
|
-
const end = page * perPage;
|
|
10
|
-
obj.items = array.slice(start, end);
|
|
11
|
-
if (obj.items.length === 0) {
|
|
12
|
-
return obj;
|
|
13
|
-
}
|
|
14
|
-
if (page > 1) {
|
|
15
|
-
obj.prev = page - 1;
|
|
16
|
-
}
|
|
17
|
-
if (end < array.length) {
|
|
18
|
-
obj.next = page + 1;
|
|
19
|
-
}
|
|
20
|
-
if (obj.items.length !== array.length) {
|
|
21
|
-
obj.current = page;
|
|
22
|
-
obj.first = 1;
|
|
23
|
-
obj.last = Math.ceil(array.length / perPage);
|
|
24
|
-
}
|
|
25
|
-
return obj;
|
|
26
|
-
}
|
package/public/favicon.ico
DELETED
|
Binary file
|
package/public/index.html
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
<html>
|
|
2
|
-
<head>
|
|
3
|
-
<link
|
|
4
|
-
rel="stylesheet"
|
|
5
|
-
href="https://use.fontawesome.com/releases/v5.8.2/css/all.css"
|
|
6
|
-
integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay"
|
|
7
|
-
crossorigin="anonymous"
|
|
8
|
-
/>
|
|
9
|
-
<link rel="stylesheet" href="style.css" />
|
|
10
|
-
<title>JSON Server</title>
|
|
11
|
-
</head>
|
|
12
|
-
|
|
13
|
-
<body>
|
|
14
|
-
<header>
|
|
15
|
-
<div class="container">
|
|
16
|
-
<nav>
|
|
17
|
-
<ul>
|
|
18
|
-
<li class="title">
|
|
19
|
-
JSON Server
|
|
20
|
-
</li>
|
|
21
|
-
<li>
|
|
22
|
-
<a href="https://github.com/users/typicode/sponsorship">
|
|
23
|
-
<i class="fas fa-heart"></i>GitHub Sponsors
|
|
24
|
-
</a>
|
|
25
|
-
</li>
|
|
26
|
-
<li>
|
|
27
|
-
<a href="https://my-json-server.typicode.com">
|
|
28
|
-
<i class="fas fa-burn"></i>My JSON Server
|
|
29
|
-
</a>
|
|
30
|
-
</li>
|
|
31
|
-
<li>
|
|
32
|
-
<a href="https://thanks.typicode.com">
|
|
33
|
-
<i class="far fa-laugh"></i>Supporters
|
|
34
|
-
</a>
|
|
35
|
-
</li>
|
|
36
|
-
</ul>
|
|
37
|
-
</nav>
|
|
38
|
-
</div>
|
|
39
|
-
</header>
|
|
40
|
-
<main>
|
|
41
|
-
<div class="container">
|
|
42
|
-
<h1>Congrats!</h1>
|
|
43
|
-
<p>
|
|
44
|
-
You're successfully running JSON Server
|
|
45
|
-
<br />
|
|
46
|
-
✧*。٩(ˊᗜˋ*)و✧*。
|
|
47
|
-
</p>
|
|
48
|
-
|
|
49
|
-
<div id="resources"></div>
|
|
50
|
-
|
|
51
|
-
<p>
|
|
52
|
-
To access and modify resources, you can use any HTTP method:
|
|
53
|
-
</p>
|
|
54
|
-
<p>
|
|
55
|
-
<code>GET</code>
|
|
56
|
-
<code>POST</code>
|
|
57
|
-
<code>PUT</code>
|
|
58
|
-
<code>PATCH</code>
|
|
59
|
-
<code>DELETE</code>
|
|
60
|
-
<code>OPTIONS</code>
|
|
61
|
-
</p>
|
|
62
|
-
|
|
63
|
-
<div id="custom-routes"></div>
|
|
64
|
-
|
|
65
|
-
<h1>Documentation</h1>
|
|
66
|
-
<p>
|
|
67
|
-
<a href="https://github.com/typicode/json-server">
|
|
68
|
-
README
|
|
69
|
-
</a>
|
|
70
|
-
</p>
|
|
71
|
-
</div>
|
|
72
|
-
</main>
|
|
73
|
-
|
|
74
|
-
<footer>
|
|
75
|
-
<div class="container">
|
|
76
|
-
<p>
|
|
77
|
-
To replace this page, create a
|
|
78
|
-
<code>./public/index.html</code> file.
|
|
79
|
-
</p>
|
|
80
|
-
</div>
|
|
81
|
-
</footer>
|
|
82
|
-
|
|
83
|
-
<script src="script.js"></script>
|
|
84
|
-
</body>
|
|
85
|
-
</html>
|
package/public/script.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
function ResourceItem({ name, length }) {
|
|
2
|
-
return `
|
|
3
|
-
<li>
|
|
4
|
-
<a href="${name}">/${name}</a>
|
|
5
|
-
<sup>${length ? `${length}x` : 'object'}</sup>
|
|
6
|
-
</li>
|
|
7
|
-
`
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function ResourceList({ db }) {
|
|
11
|
-
return `
|
|
12
|
-
<ul>
|
|
13
|
-
${Object.keys(db)
|
|
14
|
-
.map((name) =>
|
|
15
|
-
ResourceItem({
|
|
16
|
-
name,
|
|
17
|
-
length: Array.isArray(db[name]) && db[name].length,
|
|
18
|
-
}),
|
|
19
|
-
)
|
|
20
|
-
.join('')}
|
|
21
|
-
</ul>
|
|
22
|
-
`
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function NoResources() {
|
|
26
|
-
return `<p>No resources found</p>`
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function ResourcesBlock({ db }) {
|
|
30
|
-
return `
|
|
31
|
-
<div>
|
|
32
|
-
<h1>Resources</h1>
|
|
33
|
-
${Object.keys(db).length ? ResourceList({ db }) : NoResources()}
|
|
34
|
-
</div>
|
|
35
|
-
`
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
window
|
|
39
|
-
.fetch('db')
|
|
40
|
-
.then((response) => response.json())
|
|
41
|
-
.then(
|
|
42
|
-
(db) =>
|
|
43
|
-
(document.getElementById('resources').innerHTML = ResourcesBlock({ db })),
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
function CustomRoutesBlock({ customRoutes }) {
|
|
47
|
-
const rules = Object.keys(customRoutes)
|
|
48
|
-
if (rules.length) {
|
|
49
|
-
return `
|
|
50
|
-
<div>
|
|
51
|
-
<h1>Custom Routes</h1>
|
|
52
|
-
<table>
|
|
53
|
-
${rules
|
|
54
|
-
.map(
|
|
55
|
-
(rule) =>
|
|
56
|
-
`<tr>
|
|
57
|
-
<td>${rule}</td>
|
|
58
|
-
<td><code>⇢</code> ${customRoutes[rule]}</td>
|
|
59
|
-
</tr>`,
|
|
60
|
-
)
|
|
61
|
-
.join('')}
|
|
62
|
-
</table>
|
|
63
|
-
</div>
|
|
64
|
-
`
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
window
|
|
69
|
-
.fetch('__rules')
|
|
70
|
-
.then((response) => response.json())
|
|
71
|
-
.then(
|
|
72
|
-
(customRoutes) =>
|
|
73
|
-
(document.getElementById('custom-routes').innerHTML = CustomRoutesBlock({
|
|
74
|
-
customRoutes,
|
|
75
|
-
})),
|
|
76
|
-
)
|
package/public/style.css
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
body {
|
|
2
|
-
display: flex;
|
|
3
|
-
min-height: 100vh;
|
|
4
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
|
5
|
-
Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
|
|
6
|
-
flex-direction: column;
|
|
7
|
-
padding: 0;
|
|
8
|
-
margin: 0;
|
|
9
|
-
color: #3b4252;
|
|
10
|
-
letter-spacing: 0;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.container {
|
|
14
|
-
max-width: 960px;
|
|
15
|
-
margin: auto;
|
|
16
|
-
padding: 1rem;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
header {
|
|
20
|
-
border-bottom: 1px solid #eee;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
header a {
|
|
24
|
-
color: inherit;
|
|
25
|
-
text-decoration: none;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
header a:hover {
|
|
29
|
-
text-decoration: underline;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
nav ul {
|
|
33
|
-
display: flex;
|
|
34
|
-
flex-wrap: nowrap;
|
|
35
|
-
justify-content: space-between;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
nav li.title {
|
|
39
|
-
flex-grow: 5;
|
|
40
|
-
text-align: left;
|
|
41
|
-
font-weight: bold;
|
|
42
|
-
font-size: 1.4rem;
|
|
43
|
-
color: #3b4252;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
nav li {
|
|
47
|
-
flex-grow: 1;
|
|
48
|
-
align-self: center;
|
|
49
|
-
text-align: right;
|
|
50
|
-
color: #4c566a;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.fa-heart {
|
|
54
|
-
color: deeppink;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
main {
|
|
58
|
-
flex: 1;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
footer {
|
|
62
|
-
margin-top: 4rem;
|
|
63
|
-
border-top: 1px solid #eee;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
h1 {
|
|
67
|
-
margin-top: 4rem;
|
|
68
|
-
font-weight: normal;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
i {
|
|
72
|
-
margin-right: 0.5rem;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
a {
|
|
76
|
-
color: #5e81ac;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
a:hover {
|
|
80
|
-
color: #81a1c1;
|
|
81
|
-
text-decoration: underline;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
table {
|
|
85
|
-
margin-left: 0;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
td {
|
|
89
|
-
border: 0;
|
|
90
|
-
padding: 0 1em 0.5em 0;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
td:first-child {
|
|
94
|
-
width: 1%;
|
|
95
|
-
white-space: nowrap;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
ul {
|
|
99
|
-
list-style-position: inside;
|
|
100
|
-
padding-left: 0;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
li {
|
|
104
|
-
list-style-type: none;
|
|
105
|
-
margin-bottom: 0.2rem;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
code {
|
|
109
|
-
padding: 0.2rem;
|
|
110
|
-
margin: 0rem 0.2rem;
|
|
111
|
-
border-radius: 0.2rem;
|
|
112
|
-
background: #e5e9f0;
|
|
113
|
-
}
|