primate 0.15.0 → 0.15.2
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 +91 -112
- package/package.json +1 -1
- package/eslint.config.js +0 -1
- package/module.json +0 -15
- package/readme/components/edit-user-for.html +0 -10
- package/readme/components/edit-user.html +0 -10
- package/readme/components/user-index.html +0 -4
- package/readme/components/users.html +0 -4
- package/readme/extensions/handlers/html/user-index.html +0 -4
- package/readme/extensions/handlers/html/user.js +0 -13
- package/readme/extensions/handlers/htmx/user-index.html +0 -4
- package/readme/extensions/handlers/htmx/user.js +0 -23
- package/readme/extensions/handlers/redirect/user.js +0 -6
- package/readme/extensions/modules/configure.js +0 -3
- package/readme/extensions/modules/domains/configure.js +0 -5
- package/readme/extensions/modules/domains/fields.js +0 -11
- package/readme/extensions/modules/domains/predicates.js +0 -14
- package/readme/extensions/modules/domains/short-field-notation.js +0 -13
- package/readme/getting-started.js +0 -3
- package/readme/routing/accessing-the-request-body.js +0 -3
- package/readme/routing/aliasing.js +0 -14
- package/readme/routing/basic.js +0 -4
- package/readme/routing/explicit-handlers.js +0 -4
- package/readme/routing/named-groups.js +0 -5
- package/readme/routing/regular-expressions.js +0 -5
- package/readme/routing/sharing-logic-across-requests.js +0 -15
- package/readme/routing/the-request-object.js +0 -4
- package/readme/serving-content/html.js +0 -12
- package/readme/serving-content/json.js +0 -12
- package/readme/serving-content/plain-text.js +0 -4
- package/readme/serving-content/response.js +0 -6
- package/readme/serving-content/streams.js +0 -6
- package/readme/template.md +0 -135
- package/scripts/docs.sh +0 -7
- package/src/extend.spec.js +0 -103
package/README.md
CHANGED
|
@@ -4,16 +4,20 @@ Expressive, minimal and extensible framework for JavaScript.
|
|
|
4
4
|
|
|
5
5
|
## Getting started
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Run `npx -y primate@latest create` to create a project structure.
|
|
8
|
+
|
|
9
|
+
Create a route in `routes/index.js`
|
|
8
10
|
|
|
9
11
|
```js
|
|
10
|
-
export default
|
|
11
|
-
|
|
12
|
+
export default {
|
|
13
|
+
get() {
|
|
14
|
+
return "Hello, world!";
|
|
15
|
+
},
|
|
12
16
|
};
|
|
13
17
|
|
|
14
18
|
```
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
Run `npm i && npm start` and visit `localhost:6161` in your browser.
|
|
17
21
|
|
|
18
22
|
## Table of Contents
|
|
19
23
|
|
|
@@ -27,22 +31,22 @@ Add `{"type": "module"}` to your `package.json` and run `npx -y primate@latest`.
|
|
|
27
31
|
- [Basic](#basic)
|
|
28
32
|
- [The request object](#the-request-object)
|
|
29
33
|
- [Accessing the request body](#accessing-the-request-body)
|
|
30
|
-
- [
|
|
31
|
-
- [Named groups](#named-groups)
|
|
32
|
-
- [Aliasing](#aliasing)
|
|
33
|
-
- [Sharing logic across requests](#sharing-logic-across-requests)
|
|
34
|
+
- [Parameterized routes](#parameterized-routes)
|
|
34
35
|
- [Explicit handlers](#explicit-handlers)
|
|
35
36
|
|
|
36
37
|
## Serving content
|
|
37
38
|
|
|
38
|
-
Create a file in `routes`
|
|
39
|
+
Create a file in `routes/index.js` to handle the special `/` route.
|
|
39
40
|
|
|
40
41
|
### Plain text
|
|
41
42
|
|
|
42
43
|
```js
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
// routes/index.js handles the `/` route
|
|
45
|
+
export default {
|
|
46
|
+
get() {
|
|
47
|
+
// strings are served as plain text
|
|
48
|
+
return "Donald";
|
|
49
|
+
},
|
|
46
50
|
};
|
|
47
51
|
|
|
48
52
|
```
|
|
@@ -50,17 +54,15 @@ export default router => {
|
|
|
50
54
|
### JSON
|
|
51
55
|
|
|
52
56
|
```js
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// Load from file and serve as JSON
|
|
63
|
-
router.get("/users-from-file", () => File.json("users.json"));
|
|
57
|
+
// routes/index.js handles the `/` route
|
|
58
|
+
export default {
|
|
59
|
+
get() {
|
|
60
|
+
// proper JavaScript objects are served as JSON
|
|
61
|
+
return [
|
|
62
|
+
{name: "Donald"},
|
|
63
|
+
{name: "Ryan"},
|
|
64
|
+
];
|
|
65
|
+
},
|
|
64
66
|
};
|
|
65
67
|
|
|
66
68
|
```
|
|
@@ -70,9 +72,12 @@ export default router => {
|
|
|
70
72
|
```js
|
|
71
73
|
import {File} from "runtime-compat/filesystem";
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
// routes/index.js handles the `/` route
|
|
76
|
+
export default {
|
|
77
|
+
get() {
|
|
78
|
+
// ReadableStream or Blob objects are streamed to the client
|
|
79
|
+
return new File("users.json");
|
|
80
|
+
},
|
|
76
81
|
};
|
|
77
82
|
|
|
78
83
|
```
|
|
@@ -82,9 +87,12 @@ export default router => {
|
|
|
82
87
|
```js
|
|
83
88
|
import {Response} from "runtime-compat/http";
|
|
84
89
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
// routes/index.js handles the `/` route
|
|
91
|
+
export default {
|
|
92
|
+
get() {
|
|
93
|
+
// use a Response object for custom response status
|
|
94
|
+
return new Response("created!", {status: 201});
|
|
95
|
+
},
|
|
88
96
|
};
|
|
89
97
|
|
|
90
98
|
```
|
|
@@ -92,31 +100,43 @@ export default router => {
|
|
|
92
100
|
### HTML
|
|
93
101
|
|
|
94
102
|
```js
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// Serve directly from string instead of loading a component
|
|
105
|
-
router.get("/hello-adhoc", () => html("<p>Hello, world!</p>", {adhoc: true}));
|
|
103
|
+
import {html} from "primate";
|
|
104
|
+
|
|
105
|
+
// routes/index.js handles the `/` route
|
|
106
|
+
export default {
|
|
107
|
+
get() {
|
|
108
|
+
// to serve HTML, import and use the html handler
|
|
109
|
+
return html("<p>Hello, world!</p>");
|
|
110
|
+
},
|
|
106
111
|
};
|
|
107
112
|
|
|
108
113
|
```
|
|
109
114
|
|
|
110
115
|
## Routing
|
|
111
116
|
|
|
112
|
-
|
|
117
|
+
Primate uses filesystem-based routes. Every path a client accesses is mapped to
|
|
118
|
+
a route under `routes`.
|
|
119
|
+
|
|
120
|
+
* `index.js` handles the root route (`/`)
|
|
121
|
+
* `post.js` handles the `/post` route
|
|
122
|
+
* `post/{postId}.js` handles a parameterized route where `{postId}` can
|
|
123
|
+
be mapped to anything, such as `/post/1`
|
|
113
124
|
|
|
114
125
|
### Basic
|
|
115
126
|
|
|
116
127
|
```js
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
import {redirect} from "primate";
|
|
129
|
+
|
|
130
|
+
// routes/site/login.js handles the `/site/login` route
|
|
131
|
+
export default {
|
|
132
|
+
get() {
|
|
133
|
+
// strings are served as plain text
|
|
134
|
+
return "Hello, world!";
|
|
135
|
+
},
|
|
136
|
+
// other HTTP verbs are also available
|
|
137
|
+
post() {
|
|
138
|
+
return redirect("/");
|
|
139
|
+
},
|
|
120
140
|
};
|
|
121
141
|
|
|
122
142
|
```
|
|
@@ -124,9 +144,12 @@ export default router => {
|
|
|
124
144
|
### The request object
|
|
125
145
|
|
|
126
146
|
```js
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
147
|
+
// routes/site/login.js handles the `/site/login` route
|
|
148
|
+
export default {
|
|
149
|
+
get(request) {
|
|
150
|
+
// will serve `["site", "login"]` as JSON
|
|
151
|
+
return request.path;
|
|
152
|
+
},
|
|
130
153
|
};
|
|
131
154
|
|
|
132
155
|
```
|
|
@@ -139,85 +162,41 @@ to the content type sent along the request. Currently supported are
|
|
|
139
162
|
`application/json`.
|
|
140
163
|
|
|
141
164
|
```js
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
### Regular expressions
|
|
149
|
-
|
|
150
|
-
```js
|
|
151
|
-
export default router => {
|
|
152
|
-
// accessing /user/view/1234 will serve `1234` as plain text
|
|
153
|
-
// accessing /user/view/abcd will show a 404 error
|
|
154
|
-
router.get("/user/view/([0-9])+", request => request[2]);
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Named groups
|
|
160
|
-
|
|
161
|
-
```js
|
|
162
|
-
export default router => {
|
|
163
|
-
// named groups are mapped to properties of `request.named`
|
|
164
|
-
// accessing /user/view/1234 will serve `1234` as plain text
|
|
165
|
-
router.get("/user/view/(?<_id>[0-9])+", ({named}) => named._id);
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Aliasing
|
|
171
|
-
|
|
172
|
-
```js
|
|
173
|
-
export default router => {
|
|
174
|
-
// will replace `"_id"` in any path with `"([0-9])+"`
|
|
175
|
-
router.alias("_id", "([0-9])+");
|
|
176
|
-
|
|
177
|
-
// equivalent to `router.get("/user/view/([0-9])+", ...)`
|
|
178
|
-
// will return id if matched, 404 otherwise
|
|
179
|
-
router.get("/user/view/_id", request => request.path[2]);
|
|
180
|
-
|
|
181
|
-
// can be combined with named groups
|
|
182
|
-
router.alias("_name", "(?<name>[a-z])+");
|
|
183
|
-
|
|
184
|
-
// will return name if matched, 404 otherwise
|
|
185
|
-
router.get("/user/view/_name", request => request.named.name);
|
|
165
|
+
// routes/site/login.js handles the `/site/login` route
|
|
166
|
+
export default {
|
|
167
|
+
get(request) {
|
|
168
|
+
return `username submitted: ${request.body.username}`;
|
|
169
|
+
},
|
|
186
170
|
};
|
|
187
171
|
|
|
188
172
|
```
|
|
189
173
|
|
|
190
|
-
###
|
|
174
|
+
### Parameterized routes
|
|
191
175
|
|
|
192
176
|
```js
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
// Show user as plain text
|
|
201
|
-
router.get("edit-user", user => user);
|
|
202
|
-
|
|
203
|
-
// Verify or show error
|
|
204
|
-
router.post("edit-user", user => user === "Donald"
|
|
205
|
-
? "Hi Donald!"
|
|
206
|
-
: {message: "Error saving user"});
|
|
177
|
+
// routes/user/{userId}.js handles all routes of the sort `/user/{userId}`
|
|
178
|
+
// where {userId} can be anything
|
|
179
|
+
export default {
|
|
180
|
+
get(request) {
|
|
181
|
+
return `user id: ${request.named.userId}`;
|
|
182
|
+
},
|
|
207
183
|
};
|
|
208
184
|
|
|
209
185
|
```
|
|
210
186
|
|
|
211
187
|
### Explicit handlers
|
|
212
188
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
the second argument of the exported function.
|
|
189
|
+
Often we can figure out the content type to respond with based on the return
|
|
190
|
+
type from the handler. For other cases, we need to use an explicit handler.
|
|
216
191
|
|
|
217
192
|
```js
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
193
|
+
import {redirect} from "primate";
|
|
194
|
+
|
|
195
|
+
// routes/source.js handles the `/source` route
|
|
196
|
+
export default {
|
|
197
|
+
get() {
|
|
198
|
+
return redirect("/target");
|
|
199
|
+
},
|
|
221
200
|
};
|
|
222
201
|
|
|
223
202
|
```
|
package/package.json
CHANGED
package/eslint.config.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {default} from "maximin";
|
package/module.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "primate",
|
|
3
|
-
"version": "0.13.0",
|
|
4
|
-
"description": "Expressive, minimal and extensible framework for JavaScript",
|
|
5
|
-
"homepage": "https://primatejs.com",
|
|
6
|
-
"bugs": "https://github.com/primatejs/primate/issues",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"bin": "src/bin.js",
|
|
9
|
-
"repository": "https://github.com/primatejs/primate",
|
|
10
|
-
"scripts": {
|
|
11
|
-
"docs": "scripts/docs.sh",
|
|
12
|
-
"test": "npx debris",
|
|
13
|
-
"lint": "npx eslint ."
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import html from "@primate/html";
|
|
2
|
-
|
|
3
|
-
export default router => {
|
|
4
|
-
// the HTML tagged template handler loads a component from the `components`
|
|
5
|
-
// directory and serves it as HTML, passing any given data as attributes
|
|
6
|
-
router.get("/users", () => {
|
|
7
|
-
const users = [
|
|
8
|
-
{name: "Donald", email: "donald@the.duck"},
|
|
9
|
-
{name: "Joe", email: "joe@was.absent"},
|
|
10
|
-
];
|
|
11
|
-
return html("user-index", {users});
|
|
12
|
-
});
|
|
13
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import {default as htmx, partial} from "@primate/htmx";
|
|
2
|
-
|
|
3
|
-
export default router => {
|
|
4
|
-
// the HTML tagged template handler loads a component from the `components`
|
|
5
|
-
// directory and serves it as HTML, passing any given data as attributes
|
|
6
|
-
router.get("/users", () => {
|
|
7
|
-
const users = [
|
|
8
|
-
{name: "Donald", email: "donald@the.duck"},
|
|
9
|
-
{name: "Joe", email: "joe@was.absent"},
|
|
10
|
-
];
|
|
11
|
-
return htmx("user-index", {users});
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
// this is the same as above, with support for partial rendering (without
|
|
15
|
-
// index.html)
|
|
16
|
-
router.get("/other-users", () => {
|
|
17
|
-
const users = [
|
|
18
|
-
{name: "Other Donald", email: "donald@the.goose"},
|
|
19
|
-
{name: "Other Joe", email: "joe@was.around"},
|
|
20
|
-
];
|
|
21
|
-
return partial("user-index", {users});
|
|
22
|
-
});
|
|
23
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {Domain} from "@primate/domains";
|
|
2
|
-
import House from "./House.js";
|
|
3
|
-
|
|
4
|
-
export default class User extends Domain {
|
|
5
|
-
static fields = {
|
|
6
|
-
// a user's name is a string unique across the user collection
|
|
7
|
-
name: [String, "unique"],
|
|
8
|
-
// a user's age is a positive integer
|
|
9
|
-
age: [Number, "integer", "positive"],
|
|
10
|
-
// a user's house has the foreign id of a house record and no two
|
|
11
|
-
// users may have the same house
|
|
12
|
-
house_id: [House, "unique"],
|
|
13
|
-
};
|
|
14
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import {Domain} from "@primate/domains";
|
|
2
|
-
import House from "./House.js";
|
|
3
|
-
|
|
4
|
-
export default class User extends Domain {
|
|
5
|
-
static fields = {
|
|
6
|
-
// a user's name is a string
|
|
7
|
-
name: String,
|
|
8
|
-
// a user's age is a number
|
|
9
|
-
age: Number,
|
|
10
|
-
// a user's house has the foreign id of a house record
|
|
11
|
-
house_id: House,
|
|
12
|
-
};
|
|
13
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export default router => {
|
|
2
|
-
// will replace `"_id"` in any path with `"([0-9])+"`
|
|
3
|
-
router.alias("_id", "([0-9])+");
|
|
4
|
-
|
|
5
|
-
// equivalent to `router.get("/user/view/([0-9])+", ...)`
|
|
6
|
-
// will return id if matched, 404 otherwise
|
|
7
|
-
router.get("/user/view/_id", request => request.path[2]);
|
|
8
|
-
|
|
9
|
-
// can be combined with named groups
|
|
10
|
-
router.alias("_name", "(?<name>[a-z])+");
|
|
11
|
-
|
|
12
|
-
// will return name if matched, 404 otherwise
|
|
13
|
-
router.get("/user/view/_name", request => request.named.name);
|
|
14
|
-
};
|
package/readme/routing/basic.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export default router => {
|
|
2
|
-
// Declare `"edit-user"` as alias of `"/user/edit/([0-9])+"`
|
|
3
|
-
router.alias("edit-user", "/user/edit/([0-9])+");
|
|
4
|
-
|
|
5
|
-
// Pass user instead of request to all verbs on this route
|
|
6
|
-
router.map("edit-user", ({body}) => body?.name ?? "Donald");
|
|
7
|
-
|
|
8
|
-
// Show user as plain text
|
|
9
|
-
router.get("edit-user", user => user);
|
|
10
|
-
|
|
11
|
-
// Verify or show error
|
|
12
|
-
router.post("edit-user", user => user === "Donald"
|
|
13
|
-
? "Hi Donald!"
|
|
14
|
-
: {message: "Error saving user"});
|
|
15
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Use an explicit handler as we can't detect HTML by the return value type
|
|
2
|
-
export default (router, {html}) => {
|
|
3
|
-
// Embed components/hello-world.html into static/index.html and serve it. In
|
|
4
|
-
// case a user-provided index.html doesn't exist, use a fallback index.html
|
|
5
|
-
router.get("/hello", () => html("hello-world"));
|
|
6
|
-
|
|
7
|
-
// Same as above, but without embedding
|
|
8
|
-
router.get("/hello-partial", () => html("hello-world", {partial: true}));
|
|
9
|
-
|
|
10
|
-
// Serve directly from string instead of loading a component
|
|
11
|
-
router.get("/hello-adhoc", () => html("<p>Hello, world!</p>", {adhoc: true}));
|
|
12
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import {File} from "runtime-compat/filesystem";
|
|
2
|
-
|
|
3
|
-
export default router => {
|
|
4
|
-
// Serve proper JavaScript objects as JSON
|
|
5
|
-
router.get("/users", () => [
|
|
6
|
-
{name: "Donald"},
|
|
7
|
-
{name: "Ryan"},
|
|
8
|
-
]);
|
|
9
|
-
|
|
10
|
-
// Load from file and serve as JSON
|
|
11
|
-
router.get("/users-from-file", () => File.json("users.json"));
|
|
12
|
-
};
|
package/readme/template.md
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
# Primate
|
|
2
|
-
|
|
3
|
-
Expressive, minimal and extensible framework for JavaScript.
|
|
4
|
-
|
|
5
|
-
## Getting started
|
|
6
|
-
|
|
7
|
-
Create a route in `routes/hello.js`
|
|
8
|
-
|
|
9
|
-
```js
|
|
10
|
-
// getting-started.js
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Add `{"type": "module"}` to your `package.json` and run `npx -y primate@latest`.
|
|
14
|
-
|
|
15
|
-
## Table of Contents
|
|
16
|
-
|
|
17
|
-
- [Serving content](#serving-content)
|
|
18
|
-
- [Plain text](#plain-text)
|
|
19
|
-
- [JSON](#json)
|
|
20
|
-
- [Streams](#streams)
|
|
21
|
-
- [Response](#response)
|
|
22
|
-
- [HTML](#html)
|
|
23
|
-
- [Routing](#routing)
|
|
24
|
-
- [Basic](#basic)
|
|
25
|
-
- [The request object](#the-request-object)
|
|
26
|
-
- [Accessing the request body](#accessing-the-request-body)
|
|
27
|
-
- [Regular expressions](#regular-expressions)
|
|
28
|
-
- [Named groups](#named-groups)
|
|
29
|
-
- [Aliasing](#aliasing)
|
|
30
|
-
- [Sharing logic across requests](#sharing-logic-across-requests)
|
|
31
|
-
- [Explicit handlers](#explicit-handlers)
|
|
32
|
-
|
|
33
|
-
## Serving content
|
|
34
|
-
|
|
35
|
-
Create a file in `routes` that exports a default function.
|
|
36
|
-
|
|
37
|
-
### Plain text
|
|
38
|
-
|
|
39
|
-
```js
|
|
40
|
-
// serving-content/plain-text.js
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### JSON
|
|
44
|
-
|
|
45
|
-
```js
|
|
46
|
-
// serving-content/json.js
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Streams
|
|
50
|
-
|
|
51
|
-
```js
|
|
52
|
-
// serving-content/streams.js
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Response
|
|
56
|
-
|
|
57
|
-
```js
|
|
58
|
-
// serving-content/response.js
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### HTML
|
|
62
|
-
|
|
63
|
-
```js
|
|
64
|
-
// serving-content/html.js
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Routing
|
|
68
|
-
|
|
69
|
-
Routes map requests to responses. They are loaded from `routes`.
|
|
70
|
-
|
|
71
|
-
### Basic
|
|
72
|
-
|
|
73
|
-
```js
|
|
74
|
-
// routing/basic.js
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### The request object
|
|
78
|
-
|
|
79
|
-
```js
|
|
80
|
-
// routing/the-request-object.js
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Accessing the request body
|
|
84
|
-
|
|
85
|
-
For requests containing a body, Primate will attempt to parse the body according
|
|
86
|
-
to the content type sent along the request. Currently supported are
|
|
87
|
-
`application/x-www-form-urlencoded` (typically for form submission) and
|
|
88
|
-
`application/json`.
|
|
89
|
-
|
|
90
|
-
```js
|
|
91
|
-
// routing/accessing-the-request-body.js
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Regular expressions
|
|
95
|
-
|
|
96
|
-
```js
|
|
97
|
-
// routing/regular-expressions.js
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Named groups
|
|
101
|
-
|
|
102
|
-
```js
|
|
103
|
-
// routing/named-groups.js
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Aliasing
|
|
107
|
-
|
|
108
|
-
```js
|
|
109
|
-
// routing/aliasing.js
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Sharing logic across requests
|
|
113
|
-
|
|
114
|
-
```js
|
|
115
|
-
// routing/sharing-logic-across-requests.js
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### Explicit handlers
|
|
119
|
-
|
|
120
|
-
Most often we can figure out the content type to respond with based on the
|
|
121
|
-
return type from the handler. To handle content not automatically detected, use
|
|
122
|
-
the second argument of the exported function.
|
|
123
|
-
|
|
124
|
-
```js
|
|
125
|
-
// routing/explicit-handlers.js
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Resources
|
|
129
|
-
|
|
130
|
-
* Website: https://primatejs.com
|
|
131
|
-
* IRC: Join the `#primate` channel on `irc.libera.chat`.
|
|
132
|
-
|
|
133
|
-
## License
|
|
134
|
-
|
|
135
|
-
MIT
|
package/scripts/docs.sh
DELETED
package/src/extend.spec.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import extend from "./extend.js";
|
|
2
|
-
|
|
3
|
-
export default test => {
|
|
4
|
-
test.case("no params", assert => {
|
|
5
|
-
assert(extend()).equals({});
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
test.case("no base", assert => {
|
|
9
|
-
const extension = {key: "value"};
|
|
10
|
-
assert(extend(undefined, extension)).equals(extension);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test.case("no extension", assert => {
|
|
14
|
-
const base = {keys: "values"};
|
|
15
|
-
assert(extend(base)).equals(base);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test.case("base and extension same", assert => {
|
|
19
|
-
const object = {key: "value"};
|
|
20
|
-
assert(extend(object, object)).equals(object);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test.case("one property", assert => {
|
|
24
|
-
const base = {key: "value"};
|
|
25
|
-
const extension = {key: "value2"};
|
|
26
|
-
assert(extend(base, extension)).equals(extension);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test.case("two properties, one replaced", assert => {
|
|
30
|
-
const base = {key: "value", key2: "value2"};
|
|
31
|
-
const extension = {key: "other value"};
|
|
32
|
-
const extended = {key: "other value", key2: "value2"};
|
|
33
|
-
assert(extend(base, extension)).equals(extended);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test.case("arrays overwritten", assert => {
|
|
37
|
-
const base = {key: ["value", "value2"]};
|
|
38
|
-
const extension = {key: ["value3", "value4"]};
|
|
39
|
-
assert(extend(base, extension)).equals(extension);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test.case("one property of a subobject", assert => {
|
|
43
|
-
const base = {key: {subkey: "subvalue"}};
|
|
44
|
-
const extension = {key: {subkey: "subvalue 2"}};
|
|
45
|
-
assert(extend(base, extension)).equals(extension);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test.case("two properties of a subobject, one replaced", assert => {
|
|
49
|
-
const base = {key: {subkey: "subvalue", subkey2: "subvalue2"}};
|
|
50
|
-
const extension = {key: {subkey: "subvalue 2"}};
|
|
51
|
-
const extended = {key: {subkey: "subvalue 2", subkey2: "subvalue2"}};
|
|
52
|
-
assert(extend(base, extension)).equals(extended);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test.case("config enhancement", assert => {
|
|
56
|
-
const base = {
|
|
57
|
-
base: "/",
|
|
58
|
-
debug: false,
|
|
59
|
-
defaults: {
|
|
60
|
-
action: "index",
|
|
61
|
-
context: "guest",
|
|
62
|
-
},
|
|
63
|
-
paths: {
|
|
64
|
-
public: "public",
|
|
65
|
-
static: "static",
|
|
66
|
-
routes: "routes",
|
|
67
|
-
components: "components",
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const additional = {
|
|
72
|
-
debug: true,
|
|
73
|
-
environment: "testing",
|
|
74
|
-
defaults: {
|
|
75
|
-
context: "user",
|
|
76
|
-
mode: "operational",
|
|
77
|
-
},
|
|
78
|
-
paths: {
|
|
79
|
-
client: "client",
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const extended = {
|
|
84
|
-
base: "/",
|
|
85
|
-
debug: true,
|
|
86
|
-
environment: "testing",
|
|
87
|
-
defaults: {
|
|
88
|
-
action: "index",
|
|
89
|
-
context: "user",
|
|
90
|
-
mode: "operational",
|
|
91
|
-
},
|
|
92
|
-
paths: {
|
|
93
|
-
client: "client",
|
|
94
|
-
public: "public",
|
|
95
|
-
static: "static",
|
|
96
|
-
routes: "routes",
|
|
97
|
-
components: "components",
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
assert(extend(base, additional)).equals(extended);
|
|
102
|
-
});
|
|
103
|
-
};
|