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 +8 -8
- package/lib/app.js +13 -3
- package/lib/service.d.ts +2 -3
- package/lib/service.js +9 -5
- package/package.json +8 -13
- package/views/index.html +74 -18
- package/public/output.css +0 -1201
- package/views/input.css +0 -3
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 /
|
|
157
|
-
GET /
|
|
158
|
-
GET /
|
|
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?
|
|
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(
|
|
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
|
-
|
|
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,
|
|
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
|
|
228
|
-
|
|
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 (
|
|
231
|
-
return sorted.slice(
|
|
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,
|
|
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.
|
|
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
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
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
|
|
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.
|
|
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": "^
|
|
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.
|
|
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
|
-
<
|
|
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
|
|
66
|
+
<body>
|
|
11
67
|
<header>
|
|
12
|
-
<nav
|
|
68
|
+
<nav>
|
|
13
69
|
<strong>JSON Server</strong>
|
|
14
|
-
<div
|
|
15
|
-
<a href="https://github.com/typicode/json-server">
|
|
16
|
-
|
|
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
|
|
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
|
-
<
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
91
|
+
</li>
|
|
92
|
+
</ul>
|
|
37
93
|
<% }) %>
|
|
38
94
|
</main>
|
|
39
95
|
</body>
|
|
40
96
|
|
|
41
|
-
</html>
|
|
97
|
+
</html>
|