json-server 1.0.0-alpha.21 → 1.0.0-alpha.23

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
@@ -18,8 +18,8 @@ Create a `db.json` or `db.json5` file
18
18
  ```json
19
19
  {
20
20
  "posts": [
21
- { "id": "1", "title": "a title" },
22
- { "id": "2", "title": "another title" }
21
+ { "id": "1", "title": "a title", "views": 100 },
22
+ { "id": "2", "title": "another title", "views": 200 }
23
23
  ],
24
24
  "comments": [
25
25
  { "id": "1", "text": "a comment about post 1", "postId": "1" },
@@ -38,8 +38,8 @@ Create a `db.json` or `db.json5` file
38
38
  ```json5
39
39
  {
40
40
  posts: [
41
- { id: '1', title: 'a title' },
42
- { id: '2', title: 'another title' },
41
+ { id: '1', title: 'a title', views: 100 },
42
+ { id: '2', title: 'another title', views: 200 },
43
43
  ],
44
44
  comments: [
45
45
  { id: '1', text: 'a comment about post 1', postId: '1' },
@@ -153,9 +153,9 @@ GET /posts?_sort=id,-views
153
153
  - `x.y.z[i]...`
154
154
 
155
155
  ```
156
- GET /posts?author.name=foo
157
- GET /posts?author.email=foo
158
- GET /posts?tags[0]=foo
156
+ GET /foo?a.b=bar
157
+ GET /foo?x.y_lt=100
158
+ GET /foo?arr[0]=bar
159
159
  ```
160
160
 
161
161
  ### Embed
@@ -169,7 +169,7 @@ GET /comments?_embed=post
169
169
 
170
170
  ```
171
171
  DELETE /posts/1
172
- DELETE /posts/1?_embed=comments
172
+ DELETE /posts/1?_dependent=comments
173
173
  ```
174
174
 
175
175
  ## Serving static files
package/lib/app.js CHANGED
@@ -18,7 +18,7 @@ export function createApp(db, options = {}) {
18
18
  // Create app
19
19
  const app = new App();
20
20
  // Static files
21
- app.use(sirv(join(__dirname, '../public'), { dev: !isProduction }));
21
+ app.use(sirv('public', { dev: !isProduction }));
22
22
  options.static
23
23
  ?.map((path) => (isAbsolute(path) ? path : join(process.cwd(), path)))
24
24
  .forEach((dir) => app.use(sirv(dir, { dev: !isProduction })));
@@ -29,7 +29,17 @@ export function createApp(db, options = {}) {
29
29
  app.get('/', (_req, res) => res.send(eta.render('index.html', { data: db.data })));
30
30
  app.get('/:name', (req, res, next) => {
31
31
  const { name = '' } = req.params;
32
- res.locals['data'] = service.find(name, req.query);
32
+ const query = Object.fromEntries(Object.entries(req.query)
33
+ .map(([key, value]) => {
34
+ if (['_start', '_end', '_limit', '_page', '_per_page'].includes(key) && typeof value === 'string') {
35
+ return [key, parseInt(value)];
36
+ }
37
+ else {
38
+ return [key, value];
39
+ }
40
+ })
41
+ .filter(([_, value]) => !Number.isNaN(value)));
42
+ res.locals['data'] = service.find(name, query);
33
43
  next();
34
44
  });
35
45
  app.get('/:name/:id', (req, res, next) => {
@@ -74,7 +84,7 @@ export function createApp(db, options = {}) {
74
84
  });
75
85
  app.delete('/:name/:id', async (req, res, next) => {
76
86
  const { name = '', id = '' } = req.params;
77
- res.locals['data'] = await service.destroyById(name, id);
87
+ res.locals['data'] = await service.destroyById(name, id, req.query['dependent']);
78
88
  next();
79
89
  });
80
90
  app.use('/:name', (req, res) => {
package/lib/service.d.ts CHANGED
@@ -21,8 +21,7 @@ export declare class Service {
21
21
  }): Item | undefined;
22
22
  find(name: string, query?: {
23
23
  [key: string]: unknown;
24
- } & {
25
- _embed?: string[];
24
+ _embed?: string | string[];
26
25
  _sort?: string;
27
26
  _start?: number;
28
27
  _end?: number;
@@ -35,5 +34,5 @@ export declare class Service {
35
34
  patch(name: string, body?: Item): Promise<Item | undefined>;
36
35
  updateById(name: string, id: string, body?: Item): Promise<Item | undefined>;
37
36
  patchById(name: string, id: string, body?: Item): Promise<Item | undefined>;
38
- destroyById(name: string, id: string, dependents?: string[]): Promise<Item | undefined>;
37
+ destroyById(name: string, id: string, dependent?: string | string[]): Promise<Item | undefined>;
39
38
  }
package/lib/service.js CHANGED
@@ -224,11 +224,14 @@ export class Service {
224
224
  const start = query._start;
225
225
  const end = query._end;
226
226
  const limit = query._limit;
227
- if (start === undefined && limit) {
228
- return sorted.slice(0, limit);
227
+ if (start !== undefined) {
228
+ if (end !== undefined) {
229
+ return sorted.slice(start, end);
230
+ }
231
+ return sorted.slice(start, start + (limit || 0));
229
232
  }
230
- if (start && limit) {
231
- return sorted.slice(start, start + limit);
233
+ if (limit !== undefined) {
234
+ return sorted.slice(0, limit);
232
235
  }
233
236
  // Paginate
234
237
  let page = query._page;
@@ -299,7 +302,7 @@ export class Service {
299
302
  async patchById(name, id, body = {}) {
300
303
  return this.#updateOrPatchById(name, id, body, true);
301
304
  }
302
- async destroyById(name, id, dependents = []) {
305
+ async destroyById(name, id, dependent) {
303
306
  const items = this.#get(name);
304
307
  if (items === undefined || !Array.isArray(items))
305
308
  return;
@@ -309,6 +312,7 @@ export class Service {
309
312
  const index = items.indexOf(item);
310
313
  items.splice(index, 1)[0];
311
314
  nullifyForeignKey(this.#db, name, id);
315
+ const dependents = ensureArray(dependent);
312
316
  deleteDependents(this.#db, name, dependents);
313
317
  await this.#db.write();
314
318
  return item;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-server",
3
- "version": "1.0.0-alpha.21",
3
+ "version": "1.0.0-alpha.23",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,21 +9,17 @@
9
9
  "types": "lib",
10
10
  "files": [
11
11
  "lib",
12
- "public",
13
12
  "views"
14
13
  ],
15
14
  "engines": {
16
15
  "node": ">=18.3"
17
16
  },
18
17
  "scripts": {
19
- "css": "tailwindcss -i ./views/input.css -o ./public/output.css",
20
- "watch-ts": "tsx watch src/bin.ts fixtures/db.json",
21
- "watch-css": "npm run css -- --watch",
22
- "dev": "concurrently npm:watch-*",
23
- "build": "rm -rf lib && tsc && npm run css",
24
- "test": "npm run css && node --import tsx/esm --test src/*.test.ts",
18
+ "dev": "tsx watch src/bin.ts fixtures/db.json",
19
+ "build": "rm -rf lib && tsc",
20
+ "test": "node --import tsx/esm --test src/*.test.ts",
25
21
  "lint": "eslint src --ext .ts --ignore-path .gitignore",
26
- "prepare": "husky install",
22
+ "prepare": "husky",
27
23
  "prepublishOnly": "npm run build"
28
24
  },
29
25
  "keywords": [],
@@ -32,15 +28,14 @@
32
28
  "devDependencies": {
33
29
  "@sindresorhus/tsconfig": "^5.0.0",
34
30
  "@tailwindcss/typography": "^0.5.10",
35
- "@types/node": "^20.11.0",
31
+ "@types/node": "^20.11.7",
36
32
  "@typicode/eslint-config": "^1.2.0",
37
33
  "concurrently": "^8.2.2",
38
34
  "get-port": "^7.0.0",
39
- "husky": "^8.0.3",
40
- "tailwindcss": "^3.4.1",
35
+ "husky": "^9.0.6",
41
36
  "tempy": "^3.1.0",
42
37
  "tsx": "^4.7.0",
43
- "type-fest": "^4.9.0",
38
+ "type-fest": "^4.10.1",
44
39
  "typescript": "^5.3.3"
45
40
  },
46
41
  "dependencies": {
package/views/index.html CHANGED
@@ -4,38 +4,94 @@
4
4
  <head>
5
5
  <meta charset="UTF-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <link href="/output.css" rel="stylesheet" />
7
+ <style>
8
+ html {
9
+ font-size: 16px;
10
+ line-height: 1.5;
11
+ background-color: #fff;
12
+ color: #000;
13
+ }
14
+
15
+ body {
16
+ margin: 0 auto;
17
+ max-width: 720px;
18
+ padding: 0 16px;
19
+ font-family: sans-serif;
20
+ }
21
+
22
+ a {
23
+ color: #db2777;
24
+ text-decoration: none;
25
+ }
26
+
27
+ header {
28
+ margin-bottom: 32px;
29
+ padding: 16px 0;
30
+ }
31
+
32
+ nav {
33
+ display: flex;
34
+ justify-content: space-between;
35
+ }
36
+
37
+ nav div a {
38
+ margin-left: 16px;
39
+ }
40
+
41
+ ul {
42
+ margin: 0;
43
+ padding: 0;
44
+ list-style: none;
45
+ }
46
+
47
+ li {
48
+ margin-bottom: 8px;
49
+ }
50
+
51
+ /* Dark mode styles */
52
+ @media (prefers-color-scheme: dark) {
53
+ html {
54
+ background-color: #1e293b;
55
+ color: #fff;
56
+ }
57
+
58
+ a {
59
+
60
+ }
61
+ }
62
+
63
+ </style>
8
64
  </head>
9
65
 
10
- <body class="container mx-auto prose dark:prose-invert dark:bg-slate-900 pt-6 bg-white text-slate-900">
66
+ <body>
11
67
  <header>
12
- <nav class="mx-auto flex items-center justify-between">
68
+ <nav>
13
69
  <strong>JSON Server</strong>
14
- <div class="flex gap-x-6">
15
- <a href="https://github.com/typicode/json-server">
16
- <span class="ml-2">Docs</span>
17
- </a>
18
- <a href="https://github.com/sponsors/typicode" class="text-red-500 font-semibold">
19
- <span class="ml-2">♡ Sponsor</span>
20
- </a>
70
+ <div>
71
+ <a href="https://github.com/typicode/json-server">Docs</a>
72
+ <a href="https://github.com/sponsors/typicode">♡ Sponsor</a>
21
73
  </div>
22
74
  </nav>
23
75
  </header>
24
76
  <main class="my-12">
25
77
  <p class="bg-gradient-to-r from-purple-500 via-pink-500 to-red-500 text-transparent bg-clip-text">✧*。٩(ˊᗜˋ*)و✧*。</p>
26
- <% if (Object.keys(it.data).length === 0) { %>
78
+ <% if (Object.keys(it.data).length===0) { %>
27
79
  <p>No resources found in JSON file</p>
28
80
  <% } %>
29
81
  <% Object.entries(it.data).forEach(function([name]) { %>
30
- <div class="py-1">
31
- <a href="<%= name %>">/<%= name %></a>
32
- <span class="text-gray-500">
33
- <% if (Array.isArray(it.data[name])) { %>
34
- - <%= it.data[name].length %> items</span>
82
+ <ul>
83
+ <li>
84
+ <a href="<%= name %>">/<%= name %></a>
85
+ <span>
86
+ <% if (Array.isArray(it.data[name])) { %>
87
+ - <%= it.data[name].length %>
88
+ <%= it.data[name].length> 1 ? 'items' : 'item' %>
89
+ </span>
35
90
  <% } %>
36
- </div>
91
+ </li>
92
+ </ul>
37
93
  <% }) %>
38
94
  </main>
39
95
  </body>
40
96
 
41
- </html>
97
+ </html>