Skip to content

Commit

Permalink
let's have some fun
Browse files Browse the repository at this point in the history
  • Loading branch information
mimiMonads authored Jan 20, 2023
0 parents commit f6bee4f
Show file tree
Hide file tree
Showing 41 changed files with 2,182 additions and 0 deletions.
182 changes: 182 additions & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Functor

Faster router in Deno (Working in the benchmarks)

Functor was designed to be:

- Independent
- Fast
- Scalable
- Predictable

Get started in 10 Minutes!
## Get Functor and a server

```typescript
//Functor is just a router, so a server that give a Request and expect Response is needed

import { serve } from "https://deno.land/std@0.159.0/http/server.ts";

// import fun

import fun from "https://deno.land/x/functor/fun.ts";
```
## Give a path and a function

```typescript
// the function has to return a valid BodyInt or Promise<BodyInit>
await serve(
fun()([
{
path: "/",
f: (_) => "hello world",
},
]),
{ port: 8080 },
);
```
## Add parameters, a query, a status, or a header!

```typescript
// the router auto detect if you are using them, unless you send the arguments out of the scope
// r: (arguments) => outOfScope(arguments),
// you can add or remove them with "add", "delete"


await serve(
fun(
{ hasName: "http://127.0.0.1:8080/" },
)([
{
path: "/test/:id",
status: 201,
header: new Headers(),
r: (f) => f.param.id + " " + (f.query?.hello || ""),
},
]),
{ port: 8080, hostname: "127.0.0.1" },
);
```

## Parameters

Parameters must be chained, without gaps.

```typescript
// valid (It is important to note that the following routes are different)
"/hello/:id"
"/hello/:id/"
"/hello/:id/:page/:time"
"/hello/:id/:page/:time/"

// invalid
"/hello/:id/page/:time"
"/hello/:id/page/:time/"


```


## Do you need more control ?

```typescript
// use the type:"request" to return a Response or Promise<Response>
// you can use params and query here too!


await serve(
fun(
{ hasName: "http://127.0.0.1:8080/" },
)([
{
type: "request",
path: "/abc",
f: (f) => new Response(f.query?.hello || "abc"),
},
]),
{ port: 8080, hostname: "127.0.0.1" },
);
```
## Do you need Functor just to route your function? I've got you covered!

```typescript
// use the type:"response" to return a Response or Promise<Response>
await serve(
fun(
{ hasName: "http://127.0.0.1:8080/" },
)([
{
type: "response",
path: "/",
r: (_) => new Response("hello world"),

}, ]),
{ port: 8080, hostname: "127.0.0.1" },
);
```
## Static file is natively build in functor!

```typescript
// "path" is relative to terminal
// remove mime types with mime:false
// add mime with extra: [ [header,extension]]
await serve(
fun(
{ hasName: "http://127.0.0.1:8080/" },
)([
{
type: "static",
name: "/s",
path: "./",
},
, ]),
{ port: 8080, hostname: "127.0.0.1" },
);
```
Thanks and have fun ~




# Specifications


## Route options



```typescript
type funRouterOptions = {
hasName?: string;
paramsStartsWith?: string;
notFound?: { (x: Request): Response };
badMethod?: { (x: Request): Response };
};

```

- **"hasName"**: is the name of the server, and it always has to finish with "/"
,
example: "http://127.0.0.1:8080/", the router will be 5% faster if a name is
given.

- **"paramsStartsWith"**: by default, a parameter is defined by ":" next to a
"/", changing this value, will take the first character and check if it's
follow by "/" to star a new parameter.

- **"notFound"**: changes the default NOT_FOUND.

- **"badMethod"**: changes the default BAD_METHOD.

## Methods

There are 4 methods

```typescript
type ParamsMethod = "GET" | "HEAD" | "POST" | "DELETE";
```


## License

[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0/legalcode.txt)
48 changes: 48 additions & 0 deletions builder/arraySwap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
ArrayFiler,
ArraySwap,
funRouterOptions,
RouteTypes,
} from "../types.ts";

export default (o?: funRouterOptions) => (a: RouteTypes[]): ArrayFiler =>
(
(fl) =>
(
(sp) => [
fl
.map((x) => [x[1].split("/"), x[0], x[1], x[2]])
.map((x) =>
[x[0].length - 1, x[0], x[1], x[2], x[3]] as [
number,
string[],
RouteTypes[0],
RouteTypes[1],
RouteTypes[2],
]
)
.map((x) =>
[
x[3] === "/" && o?.globalNotFound === true ? 0 : x[0],
((y) =>
((a) =>
a.length <= 1 ? a.join("") : a[0] + a.slice(1).join("/"))(
x[1]
.filter((z) => z[0] !== y),
))(
typeof o?.paramsStartsWith === "string"
? o?.paramsStartsWith
: ":",
),
x[2],
x[4],
] as ArraySwap
),
sp,
]
)(
a.filter((x) => typeof x[3] === "string") as RouteTypes[],
)
)(
a.filter((x) => x[3] === false),
);
118 changes: 118 additions & 0 deletions builder/atlas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import {
ArrayFiler,
funRouterOptions,
ParamsMethod,
RequestFunction,
} from "../types.ts";
import badMethod from "../components/util/badMethod.ts";
import notFound from "../components/util/notFound.ts";

type InnerObj = [string, RequestFunction] | [];
type InnerObjEmpty = [string, RequestFunction];
type Map = Record<number, Record<number, InnerObj[]>>;

type Atlas = [
ParamsMethod[],
number[][],
string[][][],
RequestFunction[],
ArrayFiler[1],
];
export default (_o?: funRouterOptions) => (a: ArrayFiler): Atlas =>
(
(am) =>
(
(ob) =>
(
(il) =>
(
(al) =>
(
(ul) => [am, il, al, ul, a[1]]
)(
il.map(
(x, i) =>
x.map(
(y) =>
ob[i][y].map(
(z) => [z[1]],
),
) as [RequestFunction][][],
)
.flat(3)
.concat(a[1].map(([_, _a, x]) => x))
.concat(notFound)
.concat(badMethod),
)
)(
il.map(
(x, i) =>
x.map(
(y) => ob[i][y].map((x) => x[0]),
),
) as string[][][],
)
)(
Object.keys(ob)
.map((x) => Number(x))
.map(
(x) =>
Object
.keys(ob[Number(x)])
.map((y) => Number(y)),
) as [number[]],
)
)(
Object.fromEntries(
am.map((x) => a[0].filter((y) => x === y[2]))
.map(
(x) =>
((p) =>
Object.fromEntries(
p.map(
(y) => [
y,
(
(za) =>
za[0][0] === ""
? za
.slice(1)
.reduceRight(
(acc, z) => acc.concat([z]),
[za[0]],
)
.reverse()
: za
)(
x
.reduce(
(acc, z) =>
z[0] === y
? [...acc, [z[1], z[3]]] as InnerObjEmpty[]
: acc,
[] as InnerObjEmpty[],
).sort((a, b) => b[0].length - a[0].length),
),
],
),
))(
x.map((y) => y[0])
.reduce(
(acc, y) => acc.includes(y) ? acc : acc.concat([y]),
[] as number[],
) as number[],
),
)
.map(
(x, i) => [i, x],
),
) as Map,
)
)(
a[0]
.reduce((acc: ParamsMethod[], am) =>
acc
.includes(am[2])
? acc
: [...acc, am[2]], []) as ParamsMethod[],
);
2 changes: 2 additions & 0 deletions builder/methods.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export default (a: string[]) =>
((o) => (s: string) => o.indexOf(s[0]))(a.map((x) => x[0]));
42 changes: 42 additions & 0 deletions builder/position.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { funRouterOptions } from "../types.ts";

export default (_o?: funRouterOptions) =>
(m: number[][]) =>
(c: string[][][]) =>
((h) =>
((j) =>
h.map(
(x, i) =>
((a) =>
m[i][0] === 1 || m[i][0] === 0
? a.map((y, a) => a === 0 && i === 0 ? 0 : y)
: ([0].concat(a.map((x) => x + 1))).slice(0, -1))(
x.map(
(y, a, b) =>
y + (i === 0
? b.reduce(
(acc, y, u) => a > u ? acc + y : acc,
-1,
)
: j.reduce((acc, y, u) => u < i ? acc + y : acc) - 1),
),
),
))(
h.map(
(x) =>
x
.map(
(y, i, a) =>
y +
a.reduce(
(acc, z, u) => i < u ? acc + z : acc,
0,
),
)
.reduce((acc, y) => y > acc ? y : acc, 0),
),
))(
c.map(
(x) => x.map((y) => y.length),
),
);
Loading

0 comments on commit f6bee4f

Please sign in to comment.