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.
Files changed (35) hide show
  1. package/README.md +91 -112
  2. package/package.json +1 -1
  3. package/eslint.config.js +0 -1
  4. package/module.json +0 -15
  5. package/readme/components/edit-user-for.html +0 -10
  6. package/readme/components/edit-user.html +0 -10
  7. package/readme/components/user-index.html +0 -4
  8. package/readme/components/users.html +0 -4
  9. package/readme/extensions/handlers/html/user-index.html +0 -4
  10. package/readme/extensions/handlers/html/user.js +0 -13
  11. package/readme/extensions/handlers/htmx/user-index.html +0 -4
  12. package/readme/extensions/handlers/htmx/user.js +0 -23
  13. package/readme/extensions/handlers/redirect/user.js +0 -6
  14. package/readme/extensions/modules/configure.js +0 -3
  15. package/readme/extensions/modules/domains/configure.js +0 -5
  16. package/readme/extensions/modules/domains/fields.js +0 -11
  17. package/readme/extensions/modules/domains/predicates.js +0 -14
  18. package/readme/extensions/modules/domains/short-field-notation.js +0 -13
  19. package/readme/getting-started.js +0 -3
  20. package/readme/routing/accessing-the-request-body.js +0 -3
  21. package/readme/routing/aliasing.js +0 -14
  22. package/readme/routing/basic.js +0 -4
  23. package/readme/routing/explicit-handlers.js +0 -4
  24. package/readme/routing/named-groups.js +0 -5
  25. package/readme/routing/regular-expressions.js +0 -5
  26. package/readme/routing/sharing-logic-across-requests.js +0 -15
  27. package/readme/routing/the-request-object.js +0 -4
  28. package/readme/serving-content/html.js +0 -12
  29. package/readme/serving-content/json.js +0 -12
  30. package/readme/serving-content/plain-text.js +0 -4
  31. package/readme/serving-content/response.js +0 -6
  32. package/readme/serving-content/streams.js +0 -6
  33. package/readme/template.md +0 -135
  34. package/scripts/docs.sh +0 -7
  35. 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
- Create a route in `routes/hello.js`
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 router => {
11
- router.get("/", () => "Hello, world!");
12
+ export default {
13
+ get() {
14
+ return "Hello, world!";
15
+ },
12
16
  };
13
17
 
14
18
  ```
15
19
 
16
- Add `{"type": "module"}` to your `package.json` and run `npx -y primate@latest`.
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
- - [Regular expressions](#regular-expressions)
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` that exports a default function.
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
- export default router => {
44
- // Serve strings as plain text
45
- router.get("/user", () => "Donald");
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
- import {File} from "runtime-compat/filesystem";
54
-
55
- export default router => {
56
- // Serve proper JavaScript objects as JSON
57
- router.get("/users", () => [
58
- {name: "Donald"},
59
- {name: "Ryan"},
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
- export default router => {
74
- // `File` implements `readable`, which is a `ReadableStream`
75
- router.get("/users", () => new File("users.json"));
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
- export default router => {
86
- // Use a Response object for custom response status
87
- router.get("/create", () => new Response("created!", {status: 201}));
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
- // Use an explicit handler as we can't detect HTML by the return value type
96
- export default (router, {html}) => {
97
- // Embed components/hello-world.html into static/index.html and serve it. In
98
- // case a user-provided index.html doesn't exist, use a fallback index.html
99
- router.get("/hello", () => html("hello-world"));
100
-
101
- // Same as above, but without embedding
102
- router.get("/hello-partial", () => html("hello-world", {partial: true}));
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
- Routes map requests to responses. They are loaded from `routes`.
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
- export default router => {
118
- // accessing /site/login will serve `Hello, world!` as plain text
119
- router.get("/site/login", () => "Hello, world!");
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
- export default router => {
128
- // accessing /site/login will serve `["site", "login"]` as JSON
129
- router.get("/site/login", request => request.path);
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
- export default router => {
143
- router.post("/site/login", ({body}) => `submitted user: ${body.username}`);
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
- ### Sharing logic across requests
174
+ ### Parameterized routes
191
175
 
192
176
  ```js
193
- export default router => {
194
- // Declare `"edit-user"` as alias of `"/user/edit/([0-9])+"`
195
- router.alias("edit-user", "/user/edit/([0-9])+");
196
-
197
- // Pass user instead of request to all verbs on this route
198
- router.map("edit-user", ({body}) => body?.name ?? "Donald");
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
- Most often we can figure out the content type to respond with based on the
214
- return type from the handler. To handle content not automatically detected, use
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
- export default (router, {redirect}) => {
219
- // redirect from source to target
220
- router.get("/source", () => redirect("/target"));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primate",
3
- "version": "0.15.0",
3
+ "version": "0.15.2",
4
4
  "description": "Expressive, minimal and extensible framework for JavaScript",
5
5
  "homepage": "https://primatejs.com",
6
6
  "bugs": "https://github.com/primatejs/primate/issues",
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,10 +0,0 @@
1
- <form for="${user}" method="post">
2
- <h1>Edit user</h1>
3
- <p>
4
- <input name="name" value="${name}" />
5
- </p>
6
- <p>
7
- <input name="email" value="${email}" />
8
- </p>
9
- <input type="submit" value="Save user" />
10
- </form>
@@ -1,10 +0,0 @@
1
- <form method="post">
2
- <h1>Edit user</h1>
3
- <p>
4
- <input name="name" value="${user.name}"></textarea>
5
- </p>
6
- <p>
7
- <input name="email" value="${user.email}"></textarea>
8
- </p>
9
- <input type="submit" value="Save user" />
10
- </form>
@@ -1,4 +0,0 @@
1
- <div for="${users}">
2
- User ${name}.
3
- Email ${email}.
4
- </div>
@@ -1,4 +0,0 @@
1
- <div for="${users}">
2
- User ${name}.
3
- Email ${email}.
4
- </div>
@@ -1,4 +0,0 @@
1
- <div for="${users}">
2
- User ${name}.
3
- Email ${email}.
4
- </div>
@@ -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,4 +0,0 @@
1
- <div for="${users}" hx-get="/other-users" hx-swap="outerHTML">
2
- User ${name}.
3
- Email ${email}.
4
- </div>
@@ -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,6 +0,0 @@
1
- import redirect from "@primate/html";
2
-
3
- export default router => {
4
- // redirect the request
5
- router.get("/user", () => redirect("/users"));
6
- };
@@ -1,3 +0,0 @@
1
- export default {
2
- modules: [],
3
- };
@@ -1,5 +0,0 @@
1
- import domains from "@primate/domains";
2
-
3
- export default {
4
- modules: [domains()],
5
- };
@@ -1,11 +0,0 @@
1
- import {Domain} from "@primate/domains";
2
-
3
- // A basic domain with two properies
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
- };
11
- }
@@ -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,3 +0,0 @@
1
- export default router => {
2
- router.get("/", () => "Hello, world!");
3
- };
@@ -1,3 +0,0 @@
1
- export default router => {
2
- router.post("/site/login", ({body}) => `submitted user: ${body.username}`);
3
- };
@@ -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
- };
@@ -1,4 +0,0 @@
1
- export default router => {
2
- // accessing /site/login will serve `Hello, world!` as plain text
3
- router.get("/site/login", () => "Hello, world!");
4
- };
@@ -1,4 +0,0 @@
1
- export default (router, {redirect}) => {
2
- // redirect from source to target
3
- router.get("/source", () => redirect("/target"));
4
- };
@@ -1,5 +0,0 @@
1
- export default router => {
2
- // named groups are mapped to properties of `request.named`
3
- // accessing /user/view/1234 will serve `1234` as plain text
4
- router.get("/user/view/(?<_id>[0-9])+", ({named}) => named._id);
5
- };
@@ -1,5 +0,0 @@
1
- export default router => {
2
- // accessing /user/view/1234 will serve `1234` as plain text
3
- // accessing /user/view/abcd will show a 404 error
4
- router.get("/user/view/([0-9])+", request => request[2]);
5
- };
@@ -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,4 +0,0 @@
1
- export default router => {
2
- // accessing /site/login will serve `["site", "login"]` as JSON
3
- router.get("/site/login", request => request.path);
4
- };
@@ -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
- };
@@ -1,4 +0,0 @@
1
- export default router => {
2
- // Serve strings as plain text
3
- router.get("/user", () => "Donald");
4
- };
@@ -1,6 +0,0 @@
1
- import {Response} from "runtime-compat/http";
2
-
3
- export default router => {
4
- // Use a Response object for custom response status
5
- router.get("/create", () => new Response("created!", {status: 201}));
6
- };
@@ -1,6 +0,0 @@
1
- import {File} from "runtime-compat/filesystem";
2
-
3
- export default router => {
4
- // `File` implements `readable`, which is a `ReadableStream`
5
- router.get("/users", () => new File("users.json"));
6
- };
@@ -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
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env bash
2
- npx -y embedme\
3
- --source-root readme\
4
- --strip-embed-comment\
5
- --stdout readme/template.md\
6
- > README.md
7
-
@@ -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
- };