primate 0.14.2 → 0.15.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primate",
3
- "version": "0.14.2",
3
+ "version": "0.15.0",
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",
@@ -13,7 +13,7 @@
13
13
  "lint": "npx eslint ."
14
14
  },
15
15
  "dependencies": {
16
- "runtime-compat": "^0.14.1"
16
+ "runtime-compat": "^0.15.0"
17
17
  },
18
18
  "devDependencies": {
19
19
  "maximin": "^0.1.2"
@@ -15,5 +15,5 @@ export default async env => {
15
15
  // bundle client-side code
16
16
  await bundle(env);
17
17
  // serve
18
- serve({router: await route(env.paths.routes, env.handlers), ...env});
18
+ serve({router: await route(env), ...env});
19
19
  };
package/src/exports.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import {start} from "./commands/exports.js";
2
2
  import run from "./run.js";
3
3
 
4
+ export * from "./handlers/exports.js";
4
5
  export default () => run(start);
@@ -3,3 +3,4 @@ export {default as json} from "./json.js";
3
3
  export {default as stream} from "./stream.js";
4
4
  export {default as redirect} from "./redirect.js";
5
5
  export {default as html} from "./html.js";
6
+ export {default as view} from "./view.js";
@@ -1,14 +1,5 @@
1
- const getContent = async (env, name) => {
2
- try {
3
- return await env.paths.components.join(`${name}.html`).file.read();
4
- } catch (error) {
5
- throw new Error(`cannot load component at ${name}.html`);
6
- }
7
- };
8
-
9
- export default (content, {status = 200, partial = false, adhoc = false} = {}) =>
1
+ export default (body, {status = 200, partial = false} = {}) =>
10
2
  async (env, headers) => {
11
- const body = adhoc ? content : await getContent(env, content);
12
3
  return [
13
4
  partial ? body : await env.render({body}), {
14
5
  status,
@@ -0,0 +1,9 @@
1
+ export default (name, props, options) =>
2
+ async (env, headers) => {
3
+ const ending = name.slice(name.lastIndexOf(".") + 1);
4
+ const handler = env.handlers[ending];
5
+ if (handler === undefined) {
6
+ return env.log.error(new Error(`no handler for ${ending} components`));
7
+ }
8
+ return handler(name, props, options)(env, headers);
9
+ };
package/src/route.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import {Path} from "runtime-compat/fs";
2
- import {is} from "runtime-compat/dyndef";
3
2
  import RouteError from "./errors/Route.js";
4
3
 
5
4
  // insensitive-case equal
@@ -11,30 +10,13 @@ const verbs = [
11
10
  // extended
12
11
  "delete", "connect", "options", "trace", "patch",
13
12
  ];
14
- export default async (definitions, handlers) => {
15
- const aliases = [];
13
+ export default async env => {
16
14
  const routes = [];
17
- const expand = path => aliases.reduce((expanded, {key, value}) =>
18
- expanded.replace(key, () => value), path);
19
- const exists = (method, path) =>
20
- routes.some(route => route.method === method && route.path === path);
21
- const add = (method, path, handler) => {
22
- is(path).string();
23
- is(handler).function();
24
- if (exists(method, path)) {
25
- throw new RouteError(`a ${method} route for ${path} already exists`);
26
- }
27
- routes.push({method, path: new RegExp(`^${expand(path)}$`, "u"), handler});
28
- };
29
15
  const find = (method, path, fallback = {handler: r => r}) =>
30
16
  routes.find(route =>
31
17
  ieq(route.method, method) && route.path.test(path)) ?? fallback;
32
18
 
33
19
  const router = {
34
- ...Object.fromEntries(verbs.map(verb =>
35
- [verb, (path, callback) => add(verb, path, callback)])),
36
- map: (path, callback) => add("map", path, callback),
37
- alias: (key, value) => aliases.push({key, value}),
38
20
  route: async ({request}) => {
39
21
  const {method} = request.original;
40
22
  const url = new URL(`https://primatejs.com${request.pathname}`);
@@ -50,10 +32,32 @@ export default async (definitions, handlers) => {
50
32
  .handler({...request, pathname, params, path, named}));
51
33
  },
52
34
  };
53
- if (await definitions.exists) {
54
- const files = (await Path.list(definitions)).map(route => import(route));
55
- await Promise.all(files.map(async route =>
56
- (await route).default(router, handlers)));
35
+ const toRoute = file => {
36
+ const ending = -3;
37
+ const route = file
38
+ // remove ending
39
+ .slice(0, ending)
40
+ // transform /index -> ""
41
+ .replace("/index", "")
42
+ // transform index -> ""
43
+ .replace("index", "")
44
+ // prepare for regex
45
+ .replaceAll(/\{(?<named>.*)\}/gu, (_, name) => `(?<${name}>.*?)`)
46
+ ;
47
+ return new RegExp(`^/${route}$`, "u");
48
+ };
49
+ for (const route of await Path.collect(env.paths.routes, /^.*.js$/u)) {
50
+ const imported = (await import(route)).default;
51
+ const file = `${route}`.replace(env.paths.routes, "").slice(1);
52
+ if (imported === undefined) {
53
+ env.log.warn(`empty route file at ${file}`);
54
+ } else {
55
+ const valids = Object.entries(imported)
56
+ .filter(([verb]) => verbs.includes(verb));
57
+ for (const [method, handler] of valids) {
58
+ routes.push({method, path: toRoute(file), handler});
59
+ }
60
+ }
57
61
  }
58
62
  return router;
59
63
  };