primate 0.7.0 → 0.8.0
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 +54 -29
- package/exports.js +28 -0
- package/package.json +5 -5
- package/source/App.js +1 -1
- package/source/Bundler.js +6 -15
- package/source/Router.js +10 -7
- package/source/Server.js +3 -3
- package/source/handlers/DOM/Node.js +32 -36
- package/source/handlers/html.js +2 -2
- package/debris.json +0 -4
- package/jsconfig.json +0 -8
- package/source/exports.js +0 -28
- package/source/preset/static/index.html +0 -8
package/README.md
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
# Primate
|
|
1
|
+
# Primate
|
|
2
2
|
|
|
3
|
-
A full-stack Javascript framework
|
|
4
|
-
|
|
5
|
-
expressive code.
|
|
3
|
+
A full-stack Javascript framework with data verification and server-side HTML
|
|
4
|
+
rendering.
|
|
6
5
|
|
|
7
6
|
## Highlights
|
|
8
7
|
|
|
@@ -15,10 +14,12 @@ expressive code.
|
|
|
15
14
|
[MongoDB][primate-mongodb-store]
|
|
16
15
|
* Easy modelling of`1:1`, `1:n` and `n:m` relationships
|
|
17
16
|
* Minimally opinionated with sane, overrideable defaults
|
|
18
|
-
*
|
|
17
|
+
* Supports both Node.js and Deno
|
|
19
18
|
|
|
20
19
|
## Getting started
|
|
21
20
|
|
|
21
|
+
### Prepare
|
|
22
|
+
|
|
22
23
|
Lay out your app
|
|
23
24
|
|
|
24
25
|
```sh
|
|
@@ -32,13 +33,13 @@ Create a route for `/`
|
|
|
32
33
|
|
|
33
34
|
import {router, html} from "primate";
|
|
34
35
|
|
|
35
|
-
router.get("/", () => html`<site-index date
|
|
36
|
+
router.get("/", () => html`<site-index date="${new Date()}" />`);
|
|
36
37
|
```
|
|
37
38
|
|
|
38
39
|
Create a component for your route (in `components/site-index.html`)
|
|
39
40
|
|
|
40
41
|
```html
|
|
41
|
-
Today's date is <span
|
|
42
|
+
Today's date is <span value="${date}"></span>.
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
Generate SSL key/certificate
|
|
@@ -56,6 +57,8 @@ import {app} from "primate";
|
|
|
56
57
|
app.run();
|
|
57
58
|
```
|
|
58
59
|
|
|
60
|
+
### Run on Node.js
|
|
61
|
+
|
|
59
62
|
Create a start script and enable ES modules (in `package.json`)
|
|
60
63
|
|
|
61
64
|
```json
|
|
@@ -79,15 +82,33 @@ Run app
|
|
|
79
82
|
$ npm start
|
|
80
83
|
```
|
|
81
84
|
|
|
82
|
-
|
|
85
|
+
### Run on Deno
|
|
86
|
+
|
|
87
|
+
Create an import map file (`import-map.json`)
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"imports": {
|
|
92
|
+
"runtime-compat": "https://deno.land/x/runtime_compat/exports.js",
|
|
93
|
+
"primate": "https:/deno.land/x/primate/exports.js"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Run app
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
deno run --import-map=import-map.json app.js
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
You will typically need the `allow-read`, `allow-write` and `allow-net`
|
|
105
|
+
permissions.
|
|
83
106
|
|
|
84
107
|
## Table of Contents
|
|
85
108
|
|
|
86
109
|
* [Routes](#routes)
|
|
87
110
|
* [Handlers](#handlers)
|
|
88
111
|
* [Components](#components)
|
|
89
|
-
* [Domains](#domains)
|
|
90
|
-
* [Verification](#verification)
|
|
91
112
|
|
|
92
113
|
## Routes
|
|
93
114
|
|
|
@@ -171,13 +192,15 @@ router.map("/user/edit/_id", request => {
|
|
|
171
192
|
|
|
172
193
|
router.get("/user/edit/_id", request => {
|
|
173
194
|
// show user edit form
|
|
174
|
-
return html`<user-edit user
|
|
195
|
+
return html`<user-edit user="${request.user}" />`
|
|
175
196
|
});
|
|
176
197
|
|
|
177
198
|
router.post("/user/edit/_id", request => {
|
|
178
199
|
const {user} = request;
|
|
179
200
|
// verify form and save / show errors
|
|
180
|
-
return await user.save()
|
|
201
|
+
return await user.save()
|
|
202
|
+
? redirect`/users`
|
|
203
|
+
: html`<user-edit user="${user}" />`
|
|
181
204
|
});
|
|
182
205
|
```
|
|
183
206
|
|
|
@@ -185,7 +208,7 @@ router.post("/user/edit/_id", request => {
|
|
|
185
208
|
|
|
186
209
|
Handlers are tagged template functions usually associated with data.
|
|
187
210
|
|
|
188
|
-
### ``html`<component-name attribute
|
|
211
|
+
### ``html`<component-name attribute="${value}" />` ``
|
|
189
212
|
|
|
190
213
|
Compiles and serves a component from the `components` directory and with the
|
|
191
214
|
specified attributes and their values. Returns an HTTP 200 response with the
|
|
@@ -202,8 +225,8 @@ Redirects to `url`. Returns an HTTP 302 response.
|
|
|
202
225
|
|
|
203
226
|
## Components
|
|
204
227
|
|
|
205
|
-
Create HTML components in the `components` directory. Use
|
|
206
|
-
|
|
228
|
+
Create HTML components in the `components` directory. Use attributes to expose
|
|
229
|
+
passed data within your component.
|
|
207
230
|
|
|
208
231
|
```js
|
|
209
232
|
// in routes/user.js
|
|
@@ -219,14 +242,16 @@ router.map("/user/edit/_id", request => {
|
|
|
219
242
|
|
|
220
243
|
router.get("/user/edit/_id", request => {
|
|
221
244
|
// show user edit form
|
|
222
|
-
return html`<user-edit user
|
|
245
|
+
return html`<user-edit user="${request.user}" />`
|
|
223
246
|
});
|
|
224
247
|
|
|
225
248
|
router.post("/user/edit/_id", request => {
|
|
226
249
|
const {user, payload} = request;
|
|
227
250
|
// verify form and save / show errors
|
|
228
251
|
// this assumes `user` has a method `save` to verify data
|
|
229
|
-
return await user.save(payload)
|
|
252
|
+
return await user.save(payload)
|
|
253
|
+
? redirect`/users`
|
|
254
|
+
: html`<user-edit user="${user}" />`
|
|
230
255
|
});
|
|
231
256
|
```
|
|
232
257
|
|
|
@@ -235,28 +260,28 @@ router.post("/user/edit/_id", request => {
|
|
|
235
260
|
<form method="post">
|
|
236
261
|
<h1>Edit user</h1>
|
|
237
262
|
<p>
|
|
238
|
-
<input name="
|
|
263
|
+
<input name="name" value="${user.name}"></textarea>
|
|
239
264
|
</p>
|
|
240
265
|
<p>
|
|
241
|
-
<input name="
|
|
266
|
+
<input name="email" value="${user.email}"></textarea>
|
|
242
267
|
</p>
|
|
243
268
|
<input type="submit" value="Save user" />
|
|
244
269
|
</form>
|
|
245
270
|
```
|
|
246
271
|
|
|
247
|
-
### Grouping objects with `
|
|
272
|
+
### Grouping objects with `for`
|
|
248
273
|
|
|
249
|
-
You can use the special attribute `
|
|
274
|
+
You can use the special attribute `for` to group objects.
|
|
250
275
|
|
|
251
276
|
```html
|
|
252
277
|
<!-- components/edit-user.html -->
|
|
253
|
-
<form
|
|
278
|
+
<form for="${user}" method="post">
|
|
254
279
|
<h1>Edit user</h1>
|
|
255
280
|
<p>
|
|
256
|
-
<input name="name"
|
|
281
|
+
<input name="name" value="${name}" />
|
|
257
282
|
</p>
|
|
258
283
|
<p>
|
|
259
|
-
<input name="email"
|
|
284
|
+
<input name="email" value="${email}" />
|
|
260
285
|
</p>
|
|
261
286
|
<input type="submit" value="Save user" />
|
|
262
287
|
</form>
|
|
@@ -264,7 +289,7 @@ You can use the special attribute `data-for` to group objects.
|
|
|
264
289
|
|
|
265
290
|
### Expanding arrays
|
|
266
291
|
|
|
267
|
-
`
|
|
292
|
+
`for` can also be used to expand arrays.
|
|
268
293
|
|
|
269
294
|
```js
|
|
270
295
|
// in routes/user.js
|
|
@@ -275,15 +300,15 @@ router.get("/users", request => {
|
|
|
275
300
|
{"name": "Donald", "email": "donald@was.here"},
|
|
276
301
|
{"name": "Ryan", "email": "ryan@was.here"},
|
|
277
302
|
];
|
|
278
|
-
return html`<user-index users
|
|
303
|
+
return html`<user-index users="${users}" />`;
|
|
279
304
|
});
|
|
280
305
|
```
|
|
281
306
|
|
|
282
307
|
```html
|
|
283
308
|
<!-- in components/user-index.html -->
|
|
284
|
-
<div
|
|
285
|
-
User <span
|
|
286
|
-
Email <span
|
|
309
|
+
<div for="${users}">
|
|
310
|
+
User <span value="${name}"></span>
|
|
311
|
+
Email <span value="${email}"></span>
|
|
287
312
|
</div>
|
|
288
313
|
```
|
|
289
314
|
|
package/exports.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import conf from "./source/conf.js";
|
|
2
|
+
import App from "./source/App.js";
|
|
3
|
+
|
|
4
|
+
export {App};
|
|
5
|
+
export {default as Bundler} from "./source/Bundler.js";
|
|
6
|
+
export {default as EagerPromise, eager} from "./source/EagerPromise.js" ;
|
|
7
|
+
|
|
8
|
+
export {default as Domain} from "./source/domain/Domain.js";
|
|
9
|
+
export {default as Storeable} from "./source/types/Storeable.js";
|
|
10
|
+
|
|
11
|
+
export * from "./source/errors.js";
|
|
12
|
+
export * from "./source/invariants.js";
|
|
13
|
+
|
|
14
|
+
export {default as MemoryStore} from "./source/store/Memory.js";
|
|
15
|
+
export {default as Store} from "./source/store/Store.js";
|
|
16
|
+
|
|
17
|
+
export {default as extend_object} from "./source/extend_object.js";
|
|
18
|
+
export {default as sanitize} from "./source/sanitize.js";
|
|
19
|
+
|
|
20
|
+
export {default as html} from "./source/handlers/html.js";
|
|
21
|
+
export {default as json} from "./source/handlers/json.js";
|
|
22
|
+
export {default as redirect} from "./source/handlers/redirect.js";
|
|
23
|
+
|
|
24
|
+
export {default as router} from "./source/Router.js";
|
|
25
|
+
|
|
26
|
+
const app = new App(conf());
|
|
27
|
+
|
|
28
|
+
export {app};
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"author": "Primate core team <core@primatejs.com>",
|
|
5
5
|
"homepage": "https://primatejs.com",
|
|
6
6
|
"bugs": "https://github.com/primatejs/primate/issues",
|
|
7
7
|
"repository": "https://github.com/primatejs/primate",
|
|
8
|
-
"description": "
|
|
8
|
+
"description": "Cross-runtime JavaScript framework",
|
|
9
9
|
"license": "BSD-3-Clause",
|
|
10
10
|
"scripts": {
|
|
11
11
|
"copy": "rm -rf output && mkdir output && cp source/* output -a",
|
|
@@ -15,16 +15,16 @@
|
|
|
15
15
|
"test": "npm run copy && npm run debris"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"runtime-compat": "^0.1.
|
|
18
|
+
"runtime-compat": "^0.1.5"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"debris": "^0.2.2",
|
|
22
|
-
"eslint": "^8.
|
|
22
|
+
"eslint": "^8.14.0",
|
|
23
23
|
"eslint-plugin-json": "^3.1.0",
|
|
24
24
|
"nyc": "^15.1.0"
|
|
25
25
|
},
|
|
26
26
|
"type": "module",
|
|
27
|
-
"exports": "./
|
|
27
|
+
"exports": "./exports.js",
|
|
28
28
|
"engines": {
|
|
29
29
|
"node": ">=17.9.0"
|
|
30
30
|
}
|
package/source/App.js
CHANGED
|
@@ -13,7 +13,7 @@ export default class App {
|
|
|
13
13
|
log.reset("Primate").yellow(package_json.version);
|
|
14
14
|
const routes = await File.list(this.conf.paths.routes);
|
|
15
15
|
for (const route of routes) {
|
|
16
|
-
await import(
|
|
16
|
+
await import(`file://${this.conf.paths.routes}/${route}`);
|
|
17
17
|
}
|
|
18
18
|
await new Bundler(this.conf).bundle();
|
|
19
19
|
|
package/source/Bundler.js
CHANGED
|
@@ -12,25 +12,16 @@ export default class Bundler {
|
|
|
12
12
|
this.scripts = [];
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
async copy_with_preset(subdirectory, to) {
|
|
16
|
-
const {paths} = this.conf;
|
|
17
|
-
|
|
18
|
-
// copy files preset files first
|
|
19
|
-
await File.copy(`${preset}/${subdirectory}`, to);
|
|
20
|
-
|
|
21
|
-
// copy any user code over it, not recreating the folder
|
|
22
|
-
try {
|
|
23
|
-
await File.copy(paths[subdirectory], to);
|
|
24
|
-
} catch(error) {
|
|
25
|
-
// directory doesn't exist
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
15
|
async bundle() {
|
|
30
16
|
const {paths} = this.conf;
|
|
31
17
|
|
|
18
|
+
// remove public directory in case exists
|
|
19
|
+
await File.remove(paths.public);
|
|
20
|
+
// create public directory
|
|
21
|
+
await File.create(paths.public);
|
|
22
|
+
|
|
32
23
|
// copy static files to public
|
|
33
|
-
await
|
|
24
|
+
await File.copy(paths.static, paths.public);
|
|
34
25
|
|
|
35
26
|
// read index.html from public, then remove it (we serve it dynamically)
|
|
36
27
|
await File.remove(`${paths.public}/${this.index}`);
|
package/source/Router.js
CHANGED
|
@@ -6,8 +6,8 @@ const dealias = path => aliases.reduce((dealiased, {key, value}) =>
|
|
|
6
6
|
dealiased.replace(key, () => value), path);
|
|
7
7
|
const push = (type, path, handler) =>
|
|
8
8
|
routes.push({type, "path": new RegExp(`^${dealias(path)}$`, "u"), handler});
|
|
9
|
-
const find = (type, path, fallback) => routes.find(route =>
|
|
10
|
-
route.type === type && route.path.test(path))
|
|
9
|
+
const find = (type, path, fallback = {"handler": r => r}) => routes.find(route =>
|
|
10
|
+
route.type === type && route.path.test(path)) ?? fallback;
|
|
11
11
|
|
|
12
12
|
export default {
|
|
13
13
|
"map": (path, callback) => push("map", path, callback),
|
|
@@ -19,10 +19,13 @@ export default {
|
|
|
19
19
|
const url = new URL(`https://primatejs.com${original_request.pathname}`);
|
|
20
20
|
const {pathname, searchParams} = url;
|
|
21
21
|
const params = Object.fromEntries(searchParams);
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
const verb = find(method, pathname, () => ({"handler": http404``}));
|
|
23
|
+
const path = pathname.split("/").filter(path => path !== "");
|
|
24
|
+
Object.entries(verb.path.exec(pathname)?.groups ?? [])
|
|
25
|
+
.filter(([key]) => path[key] === undefined)
|
|
26
|
+
.forEach(([key, value]) => Object.defineProperty(path, key, {value}));
|
|
27
|
+
|
|
28
|
+
const request = {...original_request, pathname, params, path};
|
|
29
|
+
return verb.handler(await find("map", pathname).handler(request));
|
|
27
30
|
},
|
|
28
31
|
};
|
package/source/Server.js
CHANGED
|
@@ -30,12 +30,12 @@ export default class Server {
|
|
|
30
30
|
response.setHeader("Set-Cookie", `${cookie}; SameSite=${same_site}`);
|
|
31
31
|
}
|
|
32
32
|
response.session = session;
|
|
33
|
-
const
|
|
34
|
-
const payload = Object.fromEntries(decodeURI(
|
|
33
|
+
const text = await request.text();
|
|
34
|
+
const payload = Object.fromEntries(decodeURI(text).replaceAll("+", " ")
|
|
35
35
|
.split("&")
|
|
36
36
|
.map(part => part.split("="))
|
|
37
37
|
.filter(([, value]) => value !== ""));
|
|
38
|
-
const {pathname, search} =
|
|
38
|
+
const {pathname, search} = request.url;
|
|
39
39
|
return this.try(pathname + search, request, response, payload);
|
|
40
40
|
});
|
|
41
41
|
}
|
|
@@ -2,6 +2,7 @@ import Parser from "./Parser.js";
|
|
|
2
2
|
|
|
3
3
|
const replacement_regex = /^\$([0-9]*)$/;
|
|
4
4
|
const data_regex = /\${([^}]*)}/g;
|
|
5
|
+
const attributes_regex = /([-a-z]*="[^"]+")/g;
|
|
5
6
|
const replace = (attribute, source) => {
|
|
6
7
|
if (attribute.includes(".")) {
|
|
7
8
|
const index = attribute.indexOf(".");
|
|
@@ -18,16 +19,17 @@ const fulfill = (attribute, source) => {
|
|
|
18
19
|
if (source === undefined) {
|
|
19
20
|
return undefined;
|
|
20
21
|
}
|
|
21
|
-
let value;
|
|
22
|
+
let value = attribute;
|
|
22
23
|
const matches = [...attribute.matchAll(data_regex)];
|
|
23
24
|
if (matches.length > 0) {
|
|
24
25
|
for (const match of matches) {
|
|
25
26
|
const [key] = match;
|
|
26
27
|
const new_value = replace(match[1], source);
|
|
28
|
+
if (attribute === key) {
|
|
29
|
+
return new_value;
|
|
30
|
+
}
|
|
27
31
|
value = attribute.replace(key, new_value);
|
|
28
32
|
}
|
|
29
|
-
} else {
|
|
30
|
-
value = replace(attribute, source);
|
|
31
33
|
}
|
|
32
34
|
return value;
|
|
33
35
|
};
|
|
@@ -43,7 +45,8 @@ export default class Node {
|
|
|
43
45
|
this.#data = data;
|
|
44
46
|
this.attributes = {};
|
|
45
47
|
if (content !== undefined) {
|
|
46
|
-
const [tag_name
|
|
48
|
+
const [tag_name] = content.split(" ");
|
|
49
|
+
const attributes = content.match(attributes_regex) ?? [];
|
|
47
50
|
this.tag_name = tag_name;
|
|
48
51
|
for (const attribute of attributes
|
|
49
52
|
.map(a => a.replaceAll("\"", ""))
|
|
@@ -64,11 +67,7 @@ export default class Node {
|
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
get data() {
|
|
67
|
-
|
|
68
|
-
return this.#data;
|
|
69
|
-
} else {
|
|
70
|
-
return this.parent?.data;
|
|
71
|
-
}
|
|
70
|
+
return this.#data ?? this.parent?.data;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
set data(value) {
|
|
@@ -119,13 +118,13 @@ export default class Node {
|
|
|
119
118
|
return tag;
|
|
120
119
|
}
|
|
121
120
|
|
|
122
|
-
compose(components) {
|
|
121
|
+
async compose(components) {
|
|
123
122
|
if (components[this.tag_name]) {
|
|
124
|
-
return Parser.parse(components[this.tag_name], this.attributes)
|
|
125
|
-
|
|
126
|
-
for (let i = 0; i < this.children.length; i++) {
|
|
127
|
-
this.children[i] = this.children[i].compose(components);
|
|
123
|
+
return Parser.parse(components[this.tag_name], this.attributes)
|
|
124
|
+
.compose(components);
|
|
128
125
|
}
|
|
126
|
+
this.children = await Promise.all(this.children.map(child =>
|
|
127
|
+
child.compose(components)));
|
|
129
128
|
return this;
|
|
130
129
|
}
|
|
131
130
|
|
|
@@ -136,15 +135,15 @@ export default class Node {
|
|
|
136
135
|
cloned.attributes[attribute] = this.attributes[attribute];
|
|
137
136
|
}
|
|
138
137
|
for (const child of this.children) {
|
|
139
|
-
child.clone(cloned);
|
|
138
|
+
child.clone(cloned, child.data !== this.data ? child.data : undefined);
|
|
140
139
|
}
|
|
141
140
|
}
|
|
142
141
|
|
|
143
142
|
async expand() {
|
|
144
|
-
if (this.attributes["
|
|
145
|
-
const key = this.attributes["
|
|
146
|
-
delete this.attributes["
|
|
147
|
-
const value = await this.data
|
|
143
|
+
if (this.attributes["for"] !== undefined) {
|
|
144
|
+
const key = this.attributes["for"];
|
|
145
|
+
delete this.attributes["for"];
|
|
146
|
+
const value = await fulfill(key, this.data);
|
|
148
147
|
const arr = Array.isArray(value) ? value : [value];
|
|
149
148
|
const newparent = new Node();
|
|
150
149
|
for (const val of arr) {
|
|
@@ -154,21 +153,18 @@ export default class Node {
|
|
|
154
153
|
return newparent.expand();
|
|
155
154
|
}
|
|
156
155
|
for (const attribute in this.attributes) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
delete this.attributes[attribute];
|
|
156
|
+
const fulfilled = fulfill(this.attributes[attribute], this.data);
|
|
157
|
+
switch(attribute) {
|
|
158
|
+
case "value":
|
|
159
|
+
if (this.tag_name === "input") {
|
|
160
|
+
this.attributes.value = fulfilled;
|
|
161
|
+
} else {
|
|
162
|
+
this.text = fulfilled;
|
|
163
|
+
}
|
|
164
|
+
break;
|
|
165
|
+
default:
|
|
166
|
+
this.attributes[attribute] = fulfilled;
|
|
167
|
+
break;
|
|
172
168
|
}
|
|
173
169
|
}
|
|
174
170
|
for (let i = 0; i < this.children.length; i++) {
|
|
@@ -177,7 +173,7 @@ export default class Node {
|
|
|
177
173
|
return this;
|
|
178
174
|
}
|
|
179
175
|
|
|
180
|
-
unfold(components) {
|
|
181
|
-
return this.compose(components).expand();
|
|
176
|
+
async unfold(components) {
|
|
177
|
+
return (await this.compose(components)).expand();
|
|
182
178
|
}
|
|
183
179
|
}
|
package/source/handlers/html.js
CHANGED
|
@@ -16,11 +16,11 @@ if (await File.exists(path)) {
|
|
|
16
16
|
|
|
17
17
|
export default async (strings, ...keys) => {
|
|
18
18
|
const awaited_keys = await Promise.all(keys);
|
|
19
|
-
const rendered = await (await Parser.parse(strings
|
|
19
|
+
const rendered = await (await (await Parser.parse(strings
|
|
20
20
|
.slice(0, last)
|
|
21
21
|
.map((string, i) => `${string}$${i}`)
|
|
22
22
|
.join("") + strings[strings.length+last], awaited_keys)
|
|
23
|
-
.unfold(components))
|
|
23
|
+
.unfold(components)))
|
|
24
24
|
.render();
|
|
25
25
|
const body = (await index(conf)).replace("<body>", () => `<body>${rendered}`);
|
|
26
26
|
const code = 200;
|
package/debris.json
DELETED
package/jsconfig.json
DELETED
package/source/exports.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import conf from "./conf.js";
|
|
2
|
-
import App from "./App.js";
|
|
3
|
-
|
|
4
|
-
export {App};
|
|
5
|
-
export {default as Bundler} from "./Bundler.js";
|
|
6
|
-
export {default as EagerPromise, eager} from "./EagerPromise.js" ;
|
|
7
|
-
|
|
8
|
-
export {default as Domain} from "./domain/Domain.js";
|
|
9
|
-
export {default as Storeable} from "./types/Storeable.js";
|
|
10
|
-
|
|
11
|
-
export * from "./errors.js";
|
|
12
|
-
export * from "./invariants.js";
|
|
13
|
-
|
|
14
|
-
export {default as MemoryStore} from "./store/Memory.js";
|
|
15
|
-
export {default as Store} from "./store/Store.js";
|
|
16
|
-
|
|
17
|
-
export {default as extend_object} from "./extend_object.js";
|
|
18
|
-
export {default as sanitize} from "./sanitize.js";
|
|
19
|
-
|
|
20
|
-
export {default as html} from "./handlers/html.js";
|
|
21
|
-
export {default as json} from "./handlers/json.js";
|
|
22
|
-
export {default as redirect} from "./handlers/redirect.js";
|
|
23
|
-
|
|
24
|
-
export {default as router} from "./Router.js";
|
|
25
|
-
|
|
26
|
-
const app = new App(conf());
|
|
27
|
-
|
|
28
|
-
export {app};
|