json-server 0.15.1 → 0.16.3

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 CHANGED
@@ -12,33 +12,27 @@ See also:
12
12
  * :dog: [husky - Git hooks made easy](https://github.com/typicode/husky)
13
13
  * :hotel: [hotel - developer tool with local .localhost domain and https out of the box](https://github.com/typicode/hotel)
14
14
 
15
- <h2 align="center">Sponsors</h2>
15
+ <p>&nbsp;</p>
16
+
17
+ <h2 align="center">Gold sponsors 🥇</h2>
16
18
 
17
- <h3 align="center">Gold</h3>
19
+ <p>&nbsp;</p>
18
20
 
19
21
  <p align="center">
20
22
  <a href="https://tryretool.com/?utm_source=sponsor&utm_campaign=typicode" target="_blank">
21
- <img src="https://i.imgur.com/IBItATn.png" height="60px">
23
+ <img src="https://i.imgur.com/IBItATn.png" height="70px">
22
24
  </a>
23
25
  </p>
24
26
 
25
- ---
26
-
27
- <h3 align="center">Bronze</h3>
28
-
29
27
  <p align="center">
30
- <a href="https://www.zinggrid.com/hello/json-server?utm_source=jsonserver&utm_medium=github&utm_campaign=sponsorship" target="_blank">
31
- <img src="https://i.imgur.com/3mJGTAQ.png" height="30px">
28
+ <a href="https://mockend.com/" target="_blank">
29
+ <img src="https://i.imgur.com/Gwaqv3q.png" height="70px">
32
30
  </a>
33
31
  </p>
34
32
 
35
- ---
36
-
37
33
  <p>&nbsp;</p>
38
34
 
39
- <p align="center">
40
- <a href="https://github.com/users/typicode/sponsorship">Become a sponsor and have your company logo here</a>
41
- </p>
35
+ [Become a sponsor and have your company logo here](https://github.com/users/typicode/sponsorship)
42
36
 
43
37
  ## Table of contents
44
38
 
@@ -123,7 +117,7 @@ Also when doing requests, it's good to know that:
123
117
  - If you make POST, PUT, PATCH or DELETE requests, changes will be automatically and safely saved to `db.json` using [lowdb](https://github.com/typicode/lowdb).
124
118
  - Your request body JSON should be object enclosed, just like the GET output. (for example `{"name": "Foobar"}`)
125
119
  - Id values are not mutable. Any `id` value in the body of your PUT or PATCH request will be ignored. Only a value set in a POST request will be respected, but only if not already taken.
126
- - A POST, PUT or PATCH request should include a `Content-Type: application/json` header to use the JSON in the request body. Otherwise it will result in a 200 OK but without changes being made to the data.
120
+ - A POST, PUT or PATCH request should include a `Content-Type: application/json` header to use the JSON in the request body. Otherwise it will return a 2XX status code, but without changes being made to the data.
127
121
 
128
122
  ## Routes
129
123
 
@@ -591,7 +585,6 @@ You can deploy JSON Server. For example, [JSONPlaceholder](http://jsonplaceholde
591
585
  ### Articles
592
586
 
593
587
  * [Node Module Of The Week - json-server](http://nmotw.in/json-server/)
594
- * [Mock up your REST API with JSON Server](http://www.betterpixels.co.uk/projects/2015/05/09/mock-up-your-rest-api-with-json-server/)
595
588
  * [ng-admin: Add an AngularJS admin GUI to any RESTful API](http://marmelab.com/blog/2014/09/15/easy-backend-for-your-restful-api.html)
596
589
  * [Fast prototyping using Restangular and Json-server](https://glebbahmutov.com/blog/fast-prototyping-restangular-and-json-server/)
597
590
  * [Create a Mock REST API in Seconds for Prototyping your Frontend](https://coligo.io/create-mock-rest-api-with-json-server/)
package/lib/cli/run.js CHANGED
@@ -33,7 +33,7 @@ function prettyPrint(argv, object, rules) {
33
33
  console.log();
34
34
  console.log(chalk.bold(' Other routes'));
35
35
 
36
- for (var rule in rules) {
36
+ for (const rule in rules) {
37
37
  console.log(` ${rule} -> ${rules[rule]}`);
38
38
  }
39
39
  }
@@ -4,7 +4,9 @@ const fs = require('fs');
4
4
 
5
5
  const path = require('path');
6
6
 
7
- const request = require('request');
7
+ const http = require('http');
8
+
9
+ const https = require('https');
8
10
 
9
11
  const low = require('lowdb');
10
12
 
@@ -44,14 +46,20 @@ module.exports = function (source) {
44
46
 
45
47
  resolve(low(new FileAsync(source)));
46
48
  } else if (is.URL(source)) {
47
- // Load remote data
48
- const opts = {
49
- url: source,
50
- json: true
51
- };
52
- request(opts, (err, response) => {
53
- if (err) return reject(err);
54
- resolve(low(new Memory()).setState(response.body));
49
+ // Normalize the source into a URL object.
50
+ const sourceUrl = new URL(source); // Pick the client based on the protocol scheme
51
+
52
+ const client = sourceUrl.protocol === 'https:' ? https : http;
53
+ client.get(sourceUrl, res => {
54
+ let dbData = '';
55
+ res.on('data', data => {
56
+ dbData += data;
57
+ });
58
+ res.on('end', () => {
59
+ resolve(low(new Memory()).setState(JSON.parse(dbData)));
60
+ });
61
+ }).on('error', error => {
62
+ return reject(error);
55
63
  });
56
64
  } else if (is.JS(source)) {
57
65
  // Clear cache
@@ -14,15 +14,13 @@ const compression = require('compression');
14
14
 
15
15
  const errorhandler = require('errorhandler');
16
16
 
17
- const objectAssign = require('object-assign');
18
-
19
17
  const bodyParser = require('./body-parser');
20
18
 
21
19
  module.exports = function (opts) {
22
20
  const userDir = path.join(process.cwd(), 'public');
23
- const defaultDir = path.join(__dirname, '../../dist');
21
+ const defaultDir = path.join(__dirname, '../../public');
24
22
  const staticDir = fs.existsSync(userDir) ? userDir : defaultDir;
25
- opts = objectAssign({
23
+ opts = Object.assign({
26
24
  logger: true,
27
25
  static: staticDir
28
26
  }, opts);
@@ -1,16 +1,17 @@
1
1
  "use strict";
2
2
 
3
- const nanoid = require('nanoid');
3
+ const {
4
+ nanoid
5
+ } = require('nanoid');
4
6
 
5
7
  const pluralize = require('pluralize');
6
8
 
7
9
  module.exports = {
8
10
  getRemovable,
9
11
  createId,
10
- deepQuery // Returns document ids that have unsatisfied relations
11
- // Example: a comment that references a post that doesn't exist
12
-
13
- };
12
+ deepQuery
13
+ }; // Returns document ids that have unsatisfied relations
14
+ // Example: a comment that references a post that doesn't exist
14
15
 
15
16
  function getRemovable(db, opts) {
16
17
  const _ = this;
@@ -26,10 +26,12 @@ const singular = require('./singular');
26
26
 
27
27
  const mixins = require('../mixins');
28
28
 
29
- module.exports = (db, opts = {
30
- foreignKeySuffix: 'Id',
31
- _isFake: false
32
- }) => {
29
+ module.exports = (db, opts) => {
30
+ opts = Object.assign({
31
+ foreignKeySuffix: 'Id',
32
+ _isFake: false
33
+ }, opts);
34
+
33
35
  if (typeof db === 'string') {
34
36
  db = low(new FileSync(db));
35
37
  } else if (!_.has(db, '__chain__') || !_.has(db, '__wrapped__')) {
@@ -73,7 +75,7 @@ module.exports = (db, opts = {
73
75
  return;
74
76
  }
75
77
 
76
- var sourceMessage = ''; // if (!_.isObject(source)) {
78
+ const sourceMessage = ''; // if (!_.isObject(source)) {
77
79
  // sourceMessage = `in ${source}`
78
80
  // }
79
81
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
4
4
 
5
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
5
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
6
6
 
7
7
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
8
8
 
@@ -103,6 +103,8 @@ module.exports = (db, name, opts) => {
103
103
  return true;
104
104
  }
105
105
  }
106
+
107
+ return false;
106
108
  });
107
109
  }
108
110
 
@@ -124,7 +126,7 @@ module.exports = (db, name, opts) => {
124
126
 
125
127
 
126
128
  if (elementValue === undefined || elementValue === null) {
127
- return;
129
+ return undefined;
128
130
  }
129
131
 
130
132
  if (isRange) {
@@ -230,7 +232,7 @@ module.exports = (db, name, opts) => {
230
232
 
231
233
  if (opts._isFake) {
232
234
  const id = db.get(name).createId().value();
233
- resource = _objectSpread({}, req.body, {
235
+ resource = _objectSpread(_objectSpread({}, req.body), {}, {
234
236
  id
235
237
  });
236
238
  } else {
@@ -254,9 +256,9 @@ module.exports = (db, name, opts) => {
254
256
  resource = db.get(name).getById(id).value();
255
257
 
256
258
  if (req.method === 'PATCH') {
257
- resource = _objectSpread({}, resource, {}, req.body);
259
+ resource = _objectSpread(_objectSpread({}, resource), req.body);
258
260
  } else {
259
- resource = _objectSpread({}, req.body, {
261
+ resource = _objectSpread(_objectSpread({}, req.body), {}, {
260
262
  id: resource.id
261
263
  });
262
264
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
4
4
 
5
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
5
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
6
6
 
7
7
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
8
8
 
@@ -43,7 +43,7 @@ module.exports = (db, name, opts) => {
43
43
  res.locals.data = req.body;
44
44
  } else {
45
45
  const resource = db.get(name).value();
46
- res.locals.data = _objectSpread({}, resource, {}, req.body);
46
+ res.locals.data = _objectSpread(_objectSpread({}, resource), req.body);
47
47
  }
48
48
  } else {
49
49
  if (req.method === 'PUT') {
@@ -5,9 +5,9 @@ module.exports = {
5
5
  };
6
6
 
7
7
  function getPage(array, page, perPage) {
8
- var obj = {};
9
- var start = (page - 1) * perPage;
10
- var end = page * perPage;
8
+ const obj = {};
9
+ const start = (page - 1) * perPage;
10
+ const end = page * perPage;
11
11
  obj.items = array.slice(start, end);
12
12
 
13
13
  if (obj.items.length === 0) {
package/package.json CHANGED
@@ -1,85 +1,74 @@
1
1
  {
2
2
  "name": "json-server",
3
- "version": "0.15.1",
4
- "description": "Serves JSON files through REST routes.",
3
+ "version": "0.16.3",
4
+ "description": "Get a full fake REST API with zero coding in less than 30 seconds",
5
5
  "main": "./lib/server/index.js",
6
6
  "bin": "./lib/cli/bin.js",
7
- "directories": {
8
- "test": "test"
9
- },
7
+ "files": [
8
+ "lib",
9
+ "public"
10
+ ],
10
11
  "scripts": {
12
+ "_postinstall": "husky install",
11
13
  "test": "npm run build && cross-env NODE_ENV=test jest && npm run lint",
12
- "start": "run-p start:**",
13
- "start:babel-node": "babel-node src/cli/bin db.json -r routes.json",
14
- "start:webpack": "webpack -d --watch",
14
+ "start": "babel-node -- src/cli/bin db.json -r routes.json",
15
15
  "lint": "eslint . --ignore-path .gitignore",
16
16
  "fix": "npm run lint -- --fix",
17
- "build": "babel src -d lib && webpack -p",
17
+ "build": "babel src -d lib",
18
18
  "toc": "markdown-toc -i README.md",
19
- "prepublishOnly": "npm test && npm run build && pkg-ok"
19
+ "postversion": "git push && git push --tags",
20
+ "prepublish": "npm test && npm run build && pkg-ok && pinst --disable",
21
+ "postpublish": "pinst --enable"
20
22
  },
21
23
  "dependencies": {
22
24
  "body-parser": "^1.19.0",
23
- "chalk": "^2.4.2",
25
+ "chalk": "^4.1.0",
24
26
  "compression": "^1.7.4",
25
27
  "connect-pause": "^0.1.1",
26
28
  "cors": "^2.8.5",
27
29
  "errorhandler": "^1.5.1",
28
30
  "express": "^4.17.1",
29
- "express-urlrewrite": "^1.2.0",
31
+ "express-urlrewrite": "^1.3.0",
30
32
  "json-parse-helpfulerror": "^1.0.3",
31
- "lodash": "^4.17.15",
33
+ "lodash": "^4.17.20",
32
34
  "lodash-id": "^0.14.0",
33
35
  "lowdb": "^1.0.0",
34
36
  "method-override": "^3.0.0",
35
- "morgan": "^1.9.1",
36
- "nanoid": "^2.1.0",
37
- "object-assign": "^4.1.1",
37
+ "morgan": "^1.10.0",
38
+ "nanoid": "^3.1.16",
38
39
  "please-upgrade-node": "^3.2.0",
39
40
  "pluralize": "^8.0.0",
40
- "request": "^2.88.0",
41
41
  "server-destroy": "^1.0.1",
42
- "update-notifier": "^3.0.1",
43
- "yargs": "^14.0.0"
42
+ "update-notifier": "^5.0.1",
43
+ "yargs": "^16.1.1"
44
44
  },
45
45
  "devDependencies": {
46
- "@babel/cli": "^7.5.5",
47
- "@babel/core": "^7.5.5",
48
- "@babel/node": "^7.5.5",
49
- "@babel/plugin-transform-regenerator": "^7.4.5",
50
- "@babel/polyfill": "^7.4.4",
51
- "@babel/preset-env": "^7.5.5",
52
- "@babel/register": "^7.5.5",
53
- "babel-loader": "^8.0.6",
54
- "clean-webpack-plugin": "^3.0.0",
55
- "cross-env": "^5.2.1",
56
- "css-loader": "^3.2.0",
57
- "eslint": "^6.3.0",
58
- "eslint-config-prettier": "^6.1.0",
59
- "eslint-config-standard": "^14.1.0",
60
- "eslint-plugin-import": "^2.18.2",
61
- "eslint-plugin-node": "^9.2.0",
62
- "eslint-plugin-prettier": "^3.1.0",
46
+ "@babel/cli": "^7.12.1",
47
+ "@babel/core": "^7.12.3",
48
+ "@babel/node": "^7.12.6",
49
+ "@babel/preset-env": "^7.12.1",
50
+ "cross-env": "^7.0.2",
51
+ "eslint": "^7.13.0",
52
+ "eslint-config-prettier": "^6.15.0",
53
+ "eslint-config-standard": "^16.0.1",
54
+ "eslint-plugin-import": "^2.22.1",
55
+ "eslint-plugin-node": "^11.1.0",
56
+ "eslint-plugin-prettier": "^3.1.4",
63
57
  "eslint-plugin-promise": "^4.2.1",
64
- "eslint-plugin-standard": "^4.0.1",
65
- "html-webpack-plugin": "^3.2.0",
66
- "husky": "^3.0.5",
67
- "jest": "^24.9.0",
58
+ "eslint-plugin-standard": "^4.1.0",
59
+ "husky": "^5.0.0-beta.0",
60
+ "jest": "^26.6.3",
68
61
  "markdown-toc": "^1.2.0",
69
- "mini-css-extract-plugin": "^0.8.0",
70
- "mkdirp": "^0.5.1",
62
+ "mkdirp": "^1.0.4",
71
63
  "npm-run-all": "^4.1.5",
72
64
  "os-tmpdir": "^2.0.0",
65
+ "pinst": "^2.1.1",
73
66
  "pkg-ok": "^2.3.1",
74
- "prettier": "^1.18.2",
75
- "promise-polyfill": "^8.1.3",
76
- "rimraf": "^3.0.0",
67
+ "prettier": "^2.1.2",
68
+ "rimraf": "^3.0.2",
77
69
  "server-ready": "^0.3.1",
78
- "supertest": "^4.0.2",
79
- "temp-write": "^4.0.0",
80
- "webpack": "^4.39.3",
81
- "webpack-cli": "^3.3.7",
82
- "whatwg-fetch": "^3.0.0"
70
+ "supertest": "^6.0.1",
71
+ "temp-write": "^4.0.0"
83
72
  },
84
73
  "repository": {
85
74
  "type": "git",
@@ -108,12 +97,7 @@
108
97
  },
109
98
  "homepage": "https://github.com/typicode/json-server",
110
99
  "engines": {
111
- "node": ">=8"
112
- },
113
- "husky": {
114
- "hooks": {
115
- "pre-commit": "npm test"
116
- }
100
+ "node": ">=10"
117
101
  },
118
102
  "jest": {
119
103
  "testURL": "http://localhost/"
File without changes
@@ -6,8 +6,9 @@
6
6
  integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay"
7
7
  crossorigin="anonymous"
8
8
  />
9
+ <link rel="stylesheet" href="style.css" />
9
10
  <title>JSON Server</title>
10
- <link rel="shortcut icon" href="favicon.ico"><link href="main.css" rel="stylesheet"></head>
11
+ </head>
11
12
 
12
13
  <body>
13
14
  <header>
@@ -78,5 +79,7 @@
78
79
  </p>
79
80
  </div>
80
81
  </footer>
81
- <script type="text/javascript" src="main.js"></script></body>
82
+
83
+ <script src="script.js"></script>
84
+ </body>
82
85
  </html>
@@ -0,0 +1,76 @@
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
+ )
@@ -111,4 +111,3 @@ code {
111
111
  border-radius: 0.2rem;
112
112
  background: #e5e9f0;
113
113
  }
114
-
package/.babelrc DELETED
@@ -1,12 +0,0 @@
1
- {
2
- "presets": [
3
- [
4
- "@babel/preset-env",
5
- {
6
- "targets": {
7
- "node": "8"
8
- }
9
- }
10
- ]
11
- ]
12
- }
package/.eslintignore DELETED
@@ -1,2 +0,0 @@
1
- src/server/public
2
- lib
package/.eslintrc.js DELETED
@@ -1,14 +0,0 @@
1
- module.exports = {
2
- extends: ['standard', 'prettier'],
3
- plugins: ['prettier'],
4
- rules: {
5
- 'prettier/prettier': [
6
- 'error',
7
- {
8
- singleQuote: true,
9
- semi: false,
10
- },
11
- ]
12
- },
13
- env: { jest: true }
14
- }
@@ -1,2 +0,0 @@
1
- github: typicode
2
- patreon: typicode
package/.travis.yml DELETED
@@ -1,4 +0,0 @@
1
- language: node_js
2
- node_js:
3
- - "node"
4
- - "8"
package/appveyor.yml DELETED
@@ -1,21 +0,0 @@
1
- # Test against this version of Node.js
2
- environment:
3
- nodejs_version: "8"
4
-
5
- # Install scripts. (runs after repo cloning)
6
- install:
7
- # Get the latest stable version of Node.js
8
- - ps: Install-Product node $env:nodejs_version
9
- # install modules
10
- - npm install
11
-
12
- # Post-install test scripts.
13
- test_script:
14
- # Output useful info for debugging.
15
- - node --version
16
- - npm --version
17
- # run tests
18
- - npm test
19
-
20
- # Don't actually build.
21
- build: off
package/db.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "posts": [
3
- { "id": 1, "title": "json-server", "author": "typicode" }
4
- ],
5
- "comments": [
6
- { "id": 1, "body": "some comment", "postId": 1 }
7
- ],
8
- "profile": { "name": "typicode" }
9
- }
package/dist/main.js DELETED
@@ -1 +0,0 @@
1
- !function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=8)}([function(t,e,n){"use strict";e.a=function(t){var e=this.constructor;return this.then(function(n){return e.resolve(t()).then(function(){return n})},function(n){return e.resolve(t()).then(function(){return e.reject(n)})})}},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){"use strict";(function(t){var r=n(0),o=setTimeout;function i(t){return Boolean(t&&void 0!==t.length)}function s(){}function a(t){if(!(this instanceof a))throw new TypeError("Promises must be constructed via new");if("function"!=typeof t)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],h(t,this)}function u(t,e){for(;3===t._state;)t=t._value;0!==t._state?(t._handled=!0,a._immediateFn(function(){var n=1===t._state?e.onFulfilled:e.onRejected;if(null!==n){var r;try{r=n(t._value)}catch(t){return void f(e.promise,t)}c(e.promise,r)}else(1===t._state?c:f)(e.promise,t._value)})):t._deferreds.push(e)}function c(t,e){try{if(e===t)throw new TypeError("A promise cannot be resolved with itself.");if(e&&("object"==typeof e||"function"==typeof e)){var n=e.then;if(e instanceof a)return t._state=3,t._value=e,void l(t);if("function"==typeof n)return void h((r=n,o=e,function(){r.apply(o,arguments)}),t)}t._state=1,t._value=e,l(t)}catch(e){f(t,e)}var r,o}function f(t,e){t._state=2,t._value=e,l(t)}function l(t){2===t._state&&0===t._deferreds.length&&a._immediateFn(function(){t._handled||a._unhandledRejectionFn(t._value)});for(var e=0,n=t._deferreds.length;e<n;e++)u(t,t._deferreds[e]);t._deferreds=null}function d(t,e,n){this.onFulfilled="function"==typeof t?t:null,this.onRejected="function"==typeof e?e:null,this.promise=n}function h(t,e){var n=!1;try{t(function(t){n||(n=!0,c(e,t))},function(t){n||(n=!0,f(e,t))})}catch(t){if(n)return;n=!0,f(e,t)}}a.prototype.catch=function(t){return this.then(null,t)},a.prototype.then=function(t,e){var n=new this.constructor(s);return u(this,new d(t,e,n)),n},a.prototype.finally=r.a,a.all=function(t){return new a(function(e,n){if(!i(t))return n(new TypeError("Promise.all accepts an array"));var r=Array.prototype.slice.call(t);if(0===r.length)return e([]);var o=r.length;function s(t,i){try{if(i&&("object"==typeof i||"function"==typeof i)){var a=i.then;if("function"==typeof a)return void a.call(i,function(e){s(t,e)},n)}r[t]=i,0==--o&&e(r)}catch(t){n(t)}}for(var a=0;a<r.length;a++)s(a,r[a])})},a.resolve=function(t){return t&&"object"==typeof t&&t.constructor===a?t:new a(function(e){e(t)})},a.reject=function(t){return new a(function(e,n){n(t)})},a.race=function(t){return new a(function(e,n){if(!i(t))return n(new TypeError("Promise.race accepts an array"));for(var r=0,o=t.length;r<o;r++)a.resolve(t[r]).then(e,n)})},a._immediateFn="function"==typeof t&&function(e){t(e)}||function(t){o(t,0)},a._unhandledRejectionFn=function(t){"undefined"!=typeof console&&console&&console.warn("Possible Unhandled Promise Rejection:",t)},e.a=a}).call(this,n(4).setImmediate)},function(t,e,n){"use strict";(function(t){var e=n(2),r=n(0),o=function(){if("undefined"!=typeof self)return self;if("undefined"!=typeof window)return window;if(void 0!==t)return t;throw new Error("unable to locate global object")}();"Promise"in o?o.Promise.prototype.finally||(o.Promise.prototype.finally=r.a):o.Promise=e.a}).call(this,n(1))},function(t,e,n){(function(t){var r=void 0!==t&&t||"undefined"!=typeof self&&self||window,o=Function.prototype.apply;function i(t,e){this._id=t,this._clearFn=e}e.setTimeout=function(){return new i(o.call(setTimeout,r,arguments),clearTimeout)},e.setInterval=function(){return new i(o.call(setInterval,r,arguments),clearInterval)},e.clearTimeout=e.clearInterval=function(t){t&&t.close()},i.prototype.unref=i.prototype.ref=function(){},i.prototype.close=function(){this._clearFn.call(r,this._id)},e.enroll=function(t,e){clearTimeout(t._idleTimeoutId),t._idleTimeout=e},e.unenroll=function(t){clearTimeout(t._idleTimeoutId),t._idleTimeout=-1},e._unrefActive=e.active=function(t){clearTimeout(t._idleTimeoutId);var e=t._idleTimeout;e>=0&&(t._idleTimeoutId=setTimeout(function(){t._onTimeout&&t._onTimeout()},e))},n(5),e.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==t&&t.setImmediate||this&&this.setImmediate,e.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==t&&t.clearImmediate||this&&this.clearImmediate}).call(this,n(1))},function(t,e,n){(function(t,e){!function(t,n){"use strict";if(!t.setImmediate){var r,o,i,s,a,u=1,c={},f=!1,l=t.document,d=Object.getPrototypeOf&&Object.getPrototypeOf(t);d=d&&d.setTimeout?d:t,"[object process]"==={}.toString.call(t.process)?r=function(t){e.nextTick(function(){p(t)})}:!function(){if(t.postMessage&&!t.importScripts){var e=!0,n=t.onmessage;return t.onmessage=function(){e=!1},t.postMessage("","*"),t.onmessage=n,e}}()?t.MessageChannel?((i=new MessageChannel).port1.onmessage=function(t){p(t.data)},r=function(t){i.port2.postMessage(t)}):l&&"onreadystatechange"in l.createElement("script")?(o=l.documentElement,r=function(t){var e=l.createElement("script");e.onreadystatechange=function(){p(t),e.onreadystatechange=null,o.removeChild(e),e=null},o.appendChild(e)}):r=function(t){setTimeout(p,0,t)}:(s="setImmediate$"+Math.random()+"$",a=function(e){e.source===t&&"string"==typeof e.data&&0===e.data.indexOf(s)&&p(+e.data.slice(s.length))},t.addEventListener?t.addEventListener("message",a,!1):t.attachEvent("onmessage",a),r=function(e){t.postMessage(s+e,"*")}),d.setImmediate=function(t){"function"!=typeof t&&(t=new Function(""+t));for(var e=new Array(arguments.length-1),n=0;n<e.length;n++)e[n]=arguments[n+1];var o={callback:t,args:e};return c[u]=o,r(u),u++},d.clearImmediate=h}function h(t){delete c[t]}function p(t){if(f)setTimeout(p,0,t);else{var e=c[t];if(e){f=!0;try{!function(t){var e=t.callback,r=t.args;switch(r.length){case 0:e();break;case 1:e(r[0]);break;case 2:e(r[0],r[1]);break;case 3:e(r[0],r[1],r[2]);break;default:e.apply(n,r)}}(e)}finally{h(t),f=!1}}}}}("undefined"==typeof self?void 0===t?this:t:self)}).call(this,n(1),n(6))},function(t,e){var n,r,o=t.exports={};function i(){throw new Error("setTimeout has not been defined")}function s(){throw new Error("clearTimeout has not been defined")}function a(t){if(n===setTimeout)return setTimeout(t,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(t,0);try{return n(t,0)}catch(e){try{return n.call(null,t,0)}catch(e){return n.call(this,t,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(t){n=i}try{r="function"==typeof clearTimeout?clearTimeout:s}catch(t){r=s}}();var u,c=[],f=!1,l=-1;function d(){f&&u&&(f=!1,u.length?c=u.concat(c):l=-1,c.length&&h())}function h(){if(!f){var t=a(d);f=!0;for(var e=c.length;e;){for(u=c,c=[];++l<e;)u&&u[l].run();l=-1,e=c.length}u=null,f=!1,function(t){if(r===clearTimeout)return clearTimeout(t);if((r===s||!r)&&clearTimeout)return r=clearTimeout,clearTimeout(t);try{r(t)}catch(e){try{return r.call(null,t)}catch(e){return r.call(this,t)}}}(t)}}function p(t,e){this.fun=t,this.array=e}function y(){}o.nextTick=function(t){var e=new Array(arguments.length-1);if(arguments.length>1)for(var n=1;n<arguments.length;n++)e[n-1]=arguments[n];c.push(new p(t,e)),1!==c.length||f||a(h)},p.prototype.run=function(){this.fun.apply(null,this.array)},o.title="browser",o.browser=!0,o.env={},o.argv=[],o.version="",o.versions={},o.on=y,o.addListener=y,o.once=y,o.off=y,o.removeListener=y,o.removeAllListeners=y,o.emit=y,o.prependListener=y,o.prependOnceListener=y,o.listeners=function(t){return[]},o.binding=function(t){throw new Error("process.binding is not supported")},o.cwd=function(){return"/"},o.chdir=function(t){throw new Error("process.chdir is not supported")},o.umask=function(){return 0}},function(t,e,n){},function(t,e,n){"use strict";n.r(e);n(3);var r={searchParams:"URLSearchParams"in self,iterable:"Symbol"in self&&"iterator"in Symbol,blob:"FileReader"in self&&"Blob"in self&&function(){try{return new Blob,!0}catch(t){return!1}}(),formData:"FormData"in self,arrayBuffer:"ArrayBuffer"in self};if(r.arrayBuffer)var o=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],i=ArrayBuffer.isView||function(t){return t&&o.indexOf(Object.prototype.toString.call(t))>-1};function s(t){if("string"!=typeof t&&(t=String(t)),/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(t))throw new TypeError("Invalid character in header field name");return t.toLowerCase()}function a(t){return"string"!=typeof t&&(t=String(t)),t}function u(t){var e={next:function(){var e=t.shift();return{done:void 0===e,value:e}}};return r.iterable&&(e[Symbol.iterator]=function(){return e}),e}function c(t){this.map={},t instanceof c?t.forEach(function(t,e){this.append(e,t)},this):Array.isArray(t)?t.forEach(function(t){this.append(t[0],t[1])},this):t&&Object.getOwnPropertyNames(t).forEach(function(e){this.append(e,t[e])},this)}function f(t){if(t.bodyUsed)return Promise.reject(new TypeError("Already read"));t.bodyUsed=!0}function l(t){return new Promise(function(e,n){t.onload=function(){e(t.result)},t.onerror=function(){n(t.error)}})}function d(t){var e=new FileReader,n=l(e);return e.readAsArrayBuffer(t),n}function h(t){if(t.slice)return t.slice(0);var e=new Uint8Array(t.byteLength);return e.set(new Uint8Array(t)),e.buffer}function p(){return this.bodyUsed=!1,this._initBody=function(t){var e;this._bodyInit=t,t?"string"==typeof t?this._bodyText=t:r.blob&&Blob.prototype.isPrototypeOf(t)?this._bodyBlob=t:r.formData&&FormData.prototype.isPrototypeOf(t)?this._bodyFormData=t:r.searchParams&&URLSearchParams.prototype.isPrototypeOf(t)?this._bodyText=t.toString():r.arrayBuffer&&r.blob&&((e=t)&&DataView.prototype.isPrototypeOf(e))?(this._bodyArrayBuffer=h(t.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):r.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(t)||i(t))?this._bodyArrayBuffer=h(t):this._bodyText=t=Object.prototype.toString.call(t):this._bodyText="",this.headers.get("content-type")||("string"==typeof t?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):r.searchParams&&URLSearchParams.prototype.isPrototypeOf(t)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))},r.blob&&(this.blob=function(){var t=f(this);if(t)return t;if(this._bodyBlob)return Promise.resolve(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(new Blob([this._bodyArrayBuffer]));if(this._bodyFormData)throw new Error("could not read FormData body as blob");return Promise.resolve(new Blob([this._bodyText]))},this.arrayBuffer=function(){return this._bodyArrayBuffer?f(this)||Promise.resolve(this._bodyArrayBuffer):this.blob().then(d)}),this.text=function(){var t,e,n,r=f(this);if(r)return r;if(this._bodyBlob)return t=this._bodyBlob,e=new FileReader,n=l(e),e.readAsText(t),n;if(this._bodyArrayBuffer)return Promise.resolve(function(t){for(var e=new Uint8Array(t),n=new Array(e.length),r=0;r<e.length;r++)n[r]=String.fromCharCode(e[r]);return n.join("")}(this._bodyArrayBuffer));if(this._bodyFormData)throw new Error("could not read FormData body as text");return Promise.resolve(this._bodyText)},r.formData&&(this.formData=function(){return this.text().then(b)}),this.json=function(){return this.text().then(JSON.parse)},this}c.prototype.append=function(t,e){t=s(t),e=a(e);var n=this.map[t];this.map[t]=n?n+", "+e:e},c.prototype.delete=function(t){delete this.map[s(t)]},c.prototype.get=function(t){return t=s(t),this.has(t)?this.map[t]:null},c.prototype.has=function(t){return this.map.hasOwnProperty(s(t))},c.prototype.set=function(t,e){this.map[s(t)]=a(e)},c.prototype.forEach=function(t,e){for(var n in this.map)this.map.hasOwnProperty(n)&&t.call(e,this.map[n],n,this)},c.prototype.keys=function(){var t=[];return this.forEach(function(e,n){t.push(n)}),u(t)},c.prototype.values=function(){var t=[];return this.forEach(function(e){t.push(e)}),u(t)},c.prototype.entries=function(){var t=[];return this.forEach(function(e,n){t.push([n,e])}),u(t)},r.iterable&&(c.prototype[Symbol.iterator]=c.prototype.entries);var y=["DELETE","GET","HEAD","OPTIONS","POST","PUT"];function m(t,e){var n,r,o=(e=e||{}).body;if(t instanceof m){if(t.bodyUsed)throw new TypeError("Already read");this.url=t.url,this.credentials=t.credentials,e.headers||(this.headers=new c(t.headers)),this.method=t.method,this.mode=t.mode,this.signal=t.signal,o||null==t._bodyInit||(o=t._bodyInit,t.bodyUsed=!0)}else this.url=String(t);if(this.credentials=e.credentials||this.credentials||"same-origin",!e.headers&&this.headers||(this.headers=new c(e.headers)),this.method=(n=e.method||this.method||"GET",r=n.toUpperCase(),y.indexOf(r)>-1?r:n),this.mode=e.mode||this.mode||null,this.signal=e.signal||this.signal,this.referrer=null,("GET"===this.method||"HEAD"===this.method)&&o)throw new TypeError("Body not allowed for GET or HEAD requests");this._initBody(o)}function b(t){var e=new FormData;return t.trim().split("&").forEach(function(t){if(t){var n=t.split("="),r=n.shift().replace(/\+/g," "),o=n.join("=").replace(/\+/g," ");e.append(decodeURIComponent(r),decodeURIComponent(o))}}),e}function v(t,e){e||(e={}),this.type="default",this.status=void 0===e.status?200:e.status,this.ok=this.status>=200&&this.status<300,this.statusText="statusText"in e?e.statusText:"OK",this.headers=new c(e.headers),this.url=e.url||"",this._initBody(t)}m.prototype.clone=function(){return new m(this,{body:this._bodyInit})},p.call(m.prototype),p.call(v.prototype),v.prototype.clone=function(){return new v(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new c(this.headers),url:this.url})},v.error=function(){var t=new v(null,{status:0,statusText:""});return t.type="error",t};var w=[301,302,303,307,308];v.redirect=function(t,e){if(-1===w.indexOf(e))throw new RangeError("Invalid status code");return new v(null,{status:e,headers:{location:t}})};var g=self.DOMException;try{new g}catch(t){(g=function(t,e){this.message=t,this.name=e;var n=Error(t);this.stack=n.stack}).prototype=Object.create(Error.prototype),g.prototype.constructor=g}function _(t,e){return new Promise(function(n,o){var i=new m(t,e);if(i.signal&&i.signal.aborted)return o(new g("Aborted","AbortError"));var s=new XMLHttpRequest;function a(){s.abort()}s.onload=function(){var t,e,r={status:s.status,statusText:s.statusText,headers:(t=s.getAllResponseHeaders()||"",e=new c,t.replace(/\r?\n[\t ]+/g," ").split(/\r?\n/).forEach(function(t){var n=t.split(":"),r=n.shift().trim();if(r){var o=n.join(":").trim();e.append(r,o)}}),e)};r.url="responseURL"in s?s.responseURL:r.headers.get("X-Request-URL");var o="response"in s?s.response:s.responseText;n(new v(o,r))},s.onerror=function(){o(new TypeError("Network request failed"))},s.ontimeout=function(){o(new TypeError("Network request failed"))},s.onabort=function(){o(new g("Aborted","AbortError"))},s.open(i.method,i.url,!0),"include"===i.credentials?s.withCredentials=!0:"omit"===i.credentials&&(s.withCredentials=!1),"responseType"in s&&r.blob&&(s.responseType="blob"),i.headers.forEach(function(t,e){s.setRequestHeader(e,t)}),i.signal&&(i.signal.addEventListener("abort",a),s.onreadystatechange=function(){4===s.readyState&&i.signal.removeEventListener("abort",a)}),s.send(void 0===i._bodyInit?null:i._bodyInit)})}_.polyfill=!0,self.fetch||(self.fetch=_,self.Headers=c,self.Request=m,self.Response=v);n(7);function T({db:t}){return`\n <div>\n <h1>Resources</h1>\n ${Object.keys(t).length?function({db:t}){return`\n <ul>\n ${Object.keys(t).map(e=>(function({name:t,length:e}){return`\n <li>\n <a href="${t}">/${t}</a>\n <sup>${e?`${e}x`:"object"}</sup>\n </li>\n `})({name:e,length:Array.isArray(t[e])&&t[e].length})).join("")}\n </ul>\n `}({db:t}):"<p>No resources found</p>"}\n </div>\n `}window.fetch("db").then(t=>t.json()).then(t=>document.getElementById("resources").innerHTML=T({db:t})),window.fetch("__rules").then(t=>t.json()).then(t=>document.getElementById("custom-routes").innerHTML=function({customRoutes:t}){const e=Object.keys(t);if(e.length)return`\n <div>\n <h1>Custom Routes</h1>\n <table>\n ${e.map(e=>`<tr>\n <td>${e}</td>\n <td><code>⇢</code> ${t[e]}</td>\n </tr>`).join("")}\n </table>\n </div>\n `}({customRoutes:t}))}]);
@@ -1,77 +0,0 @@
1
- "use strict";
2
-
3
- require("promise-polyfill/src/polyfill");
4
-
5
- require("whatwg-fetch");
6
-
7
- require("./style.css");
8
-
9
- function ResourceItem({
10
- name,
11
- length
12
- }) {
13
- return `
14
- <li>
15
- <a href="${name}">/${name}</a>
16
- <sup>${length ? `${length}x` : 'object'}</sup>
17
- </li>
18
- `;
19
- }
20
-
21
- function ResourceList({
22
- db
23
- }) {
24
- return `
25
- <ul>
26
- ${Object.keys(db).map(name => ResourceItem({
27
- name,
28
- length: Array.isArray(db[name]) && db[name].length
29
- })).join('')}
30
- </ul>
31
- `;
32
- }
33
-
34
- function NoResources() {
35
- return `<p>No resources found</p>`;
36
- }
37
-
38
- function ResourcesBlock({
39
- db
40
- }) {
41
- return `
42
- <div>
43
- <h1>Resources</h1>
44
- ${Object.keys(db).length ? ResourceList({
45
- db
46
- }) : NoResources()}
47
- </div>
48
- `;
49
- }
50
-
51
- window.fetch('db').then(response => response.json()).then(db => document.getElementById('resources').innerHTML = ResourcesBlock({
52
- db
53
- }));
54
-
55
- function CustomRoutesBlock({
56
- customRoutes
57
- }) {
58
- const rules = Object.keys(customRoutes);
59
-
60
- if (rules.length) {
61
- return `
62
- <div>
63
- <h1>Custom Routes</h1>
64
- <table>
65
- ${rules.map(rule => `<tr>
66
- <td>${rule}</td>
67
- <td><code>⇢</code> ${customRoutes[rule]}</td>
68
- </tr>`).join('')}
69
- </table>
70
- </div>
71
- `;
72
- }
73
- }
74
-
75
- window.fetch('__rules').then(response => response.json()).then(customRoutes => document.getElementById('custom-routes').innerHTML = CustomRoutesBlock({
76
- customRoutes
77
- }));
package/postinstall.js DELETED
@@ -1,10 +0,0 @@
1
- const chalk = require('chalk')
2
-
3
- console.log(
4
- 'Like JSON Server? You can support the project on',
5
- chalk.bold('GitHub Sponsors')
6
- )
7
- console.log(
8
- chalk.underline('https://github.com/users/typicode/sponsorship'),
9
- chalk.red('❤')
10
- )
package/routes.json DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "/api/": "/",
3
- "/blog/:resource/:id/show": "/:resource/:id",
4
- "/blog/:category": "/posts?category=:category"
5
- }
package/webpack.config.js DELETED
@@ -1,21 +0,0 @@
1
- const { CleanWebpackPlugin } = require('clean-webpack-plugin')
2
- const HtmlWebpackPlugin = require('html-webpack-plugin')
3
- const MiniCssExtractPlugin = require('mini-css-extract-plugin')
4
-
5
- module.exports = {
6
- entry: './src/front/index.js',
7
- module: {
8
- rules: [
9
- { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'] },
10
- { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }
11
- ]
12
- },
13
- plugins: [
14
- new CleanWebpackPlugin(),
15
- new HtmlWebpackPlugin({
16
- favicon: 'src/front/favicon.ico',
17
- template: 'src/front/index.html'
18
- }),
19
- new MiniCssExtractPlugin()
20
- ]
21
- }