Skip to content

Commit

Permalink
chore: format with prettier
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Dec 13, 2022
1 parent 0812e81 commit a0e21c1
Show file tree
Hide file tree
Showing 31 changed files with 1,179 additions and 522 deletions.
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"scripts": {
"build": "unbuild",
"dev": "vitest",
"lint": "eslint --ext ts,mjs,cjs .",
"lint": "eslint --ext ts,mjs,cjs . && prettier -c src test playground",
"play": "jiti ./playground/index.ts",
"profile": "0x -o -D .profile -P 'autocannon -c 100 -p 10 -d 40 http://localhost:$PORT' ./playground/server.cjs",
"release": "pnpm test && pnpm build && changelogen --release && pnpm publish && git push --follow-tags",
Expand Down
41 changes: 31 additions & 10 deletions playground/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,39 @@
import { listen } from "listhen";
import { fetch } from "node-fetch-native";
import { createApp, createRouter, eventHandler, toNodeListener, parseCookies, createError, proxyRequest } from "../src";
import {
createApp,
createRouter,
eventHandler,
toNodeListener,
parseCookies,
createError,
proxyRequest,
} from "../src";

const app = createApp({ debug: true });
const router = createRouter()
.get("/", eventHandler(event => proxyRequest(event, "http://icanhazip.com", {
fetch
})))
.get("/error/:code", eventHandler((event) => {
throw createError({ statusCode: Number.parseInt(event.context.params.code) });
}))
.get("/hello/:name", eventHandler((event) => {
return `Hello ${parseCookies(event)}!`;
}));
.get(
"/",
eventHandler((event) =>
proxyRequest(event, "http://icanhazip.com", {
fetch,
})
)
)
.get(
"/error/:code",
eventHandler((event) => {
throw createError({
statusCode: Number.parseInt(event.context.params.code),
});
})
)
.get(
"/hello/:name",
eventHandler((event) => {
return `Hello ${parseCookies(event)}!`;
})
);

app.use(router);

Expand Down
97 changes: 63 additions & 34 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,83 +1,102 @@
import { withoutTrailingSlash } from "ufo";
import { lazyEventHandler, toEventHandler, isEventHandler, eventHandler, H3Event } from "./event";
import {
lazyEventHandler,
toEventHandler,
isEventHandler,
eventHandler,
H3Event,
} from "./event";
import { createError } from "./error";
import { send, sendStream, isStream, MIMES } from "./utils";
import type { EventHandler, LazyEventHandler } from "./types";

export interface Layer {
route: string
match?: Matcher
handler: EventHandler
route: string;
match?: Matcher;
handler: EventHandler;
}

export type Stack = Layer[]
export type Stack = Layer[];

export interface InputLayer {
route?: string
match?: Matcher
handler: EventHandler
lazy?: boolean
route?: string;
match?: Matcher;
handler: EventHandler;
lazy?: boolean;
}

export type InputStack = InputLayer[]
export type InputStack = InputLayer[];

export type Matcher = (url: string, event?: H3Event) => boolean
export type Matcher = (url: string, event?: H3Event) => boolean;

export interface AppUse {
(route: string | string[], handler: EventHandler | EventHandler[], options?: Partial<InputLayer>): App
(handler: EventHandler | EventHandler[], options?: Partial<InputLayer>): App
(options: InputLayer): App
(
route: string | string[],
handler: EventHandler | EventHandler[],
options?: Partial<InputLayer>
): App;
(handler: EventHandler | EventHandler[], options?: Partial<InputLayer>): App;
(options: InputLayer): App;
}

export interface AppOptions {
debug?: boolean
onError?: (error: Error, event: H3Event) => any
debug?: boolean;
onError?: (error: Error, event: H3Event) => any;
}

export interface App {
stack: Stack
handler: EventHandler
options: AppOptions
use: AppUse
stack: Stack;
handler: EventHandler;
options: AppOptions;
use: AppUse;
}

export function createApp (options: AppOptions = {}): App {
export function createApp(options: AppOptions = {}): App {
const stack: Stack = [];
const handler = createAppEventHandler(stack, options);
const app: App = {
// @ts-ignore
use: (arg1, arg2, arg3) => use(app as App, arg1, arg2, arg3),
handler,
stack,
options
options,
};
return app;
}

export function use (
export function use(
app: App,
arg1: string | EventHandler | InputLayer | InputLayer[],
arg2?: Partial<InputLayer> | EventHandler | EventHandler[],
arg3?: Partial<InputLayer>
) {
if (Array.isArray(arg1)) {
for (const i of arg1) { use(app, i, arg2, arg3); }
for (const i of arg1) {
use(app, i, arg2, arg3);
}
} else if (Array.isArray(arg2)) {
for (const i of arg2) { use(app, arg1, i, arg3); }
for (const i of arg2) {
use(app, arg1, i, arg3);
}
} else if (typeof arg1 === "string") {
app.stack.push(normalizeLayer({ ...arg3, route: arg1, handler: arg2 as EventHandler }));
app.stack.push(
normalizeLayer({ ...arg3, route: arg1, handler: arg2 as EventHandler })
);
} else if (typeof arg1 === "function") {
app.stack.push(normalizeLayer({ ...arg2, route: "/", handler: arg1 as EventHandler }));
app.stack.push(
normalizeLayer({ ...arg2, route: "/", handler: arg1 as EventHandler })
);
} else {
app.stack.push(normalizeLayer({ ...arg1 }));
}
return app;
}

export function createAppEventHandler (stack: Stack, options: AppOptions) {
export function createAppEventHandler(stack: Stack, options: AppOptions) {
const spacing = options.debug ? 2 : undefined;
return eventHandler(async (event) => {
(event.node.req as any).originalUrl = (event.node.req as any).originalUrl || event.node.req.url || "/";
(event.node.req as any).originalUrl =
(event.node.req as any).originalUrl || event.node.req.url || "/";
const reqUrl = event.node.req.url || "/";
for (const layer of stack) {
if (layer.route.length > 1) {
Expand All @@ -103,26 +122,36 @@ export function createAppEventHandler (stack: Stack, options: AppOptions) {
} else if (val === null) {
event.node.res.statusCode = 204;
return send(event);
} else if (type === "object" || type === "boolean" || type === "number" /* IS_JSON */) {
} else if (
type === "object" ||
type === "boolean" ||
type === "number" /* IS_JSON */
) {
if (val.buffer) {
return send(event, val);
} else if (val instanceof Error) {
throw createError(val);
} else {
return send(event, JSON.stringify(val, undefined, spacing), MIMES.json);
return send(
event,
JSON.stringify(val, undefined, spacing),
MIMES.json
);
}
}
}
if (!event.node.res.writableEnded) {
throw createError({
statusCode: 404,
statusMessage: `Cannot find any route matching ${event.node.req.url || "/"}.`
statusMessage: `Cannot find any route matching ${
event.node.req.url || "/"
}.`,
});
}
});
}

function normalizeLayer (input: InputLayer) {
function normalizeLayer(input: InputLayer) {
let handler = input.handler;
// @ts-ignore
if (handler.handler) {
Expand All @@ -139,6 +168,6 @@ function normalizeLayer (input: InputLayer) {
return {
route: withoutTrailingSlash(input.route),
match: input.match,
handler
handler,
} as Layer;
}
76 changes: 57 additions & 19 deletions src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@ import { MIMES } from "./utils";
*/
export class H3Error extends Error {
static __h3_error__ = true;
toJSON () {
const obj: Pick<H3Error, "message" | "statusCode" | "statusMessage" | "data"> = {
toJSON() {
const obj: Pick<
H3Error,
"message" | "statusCode" | "statusMessage" | "data"
> = {
message: this.message,
statusCode: this.statusCode
statusCode: this.statusCode,
};

if (this.statusMessage) { obj.statusMessage = this.statusMessage; }
if (this.statusMessage) {
obj.statusMessage = this.statusMessage;
}
if (this.data !== undefined) {
obj.data = this.data;
}
Expand All @@ -42,7 +47,9 @@ export class H3Error extends Error {
* @param input {Partial<H3Error>}
* @return {H3Error} An instance of the H3Error
*/
export function createError (input: string | Partial<H3Error> & { status?: number, statusText?: string }): H3Error {
export function createError(
input: string | (Partial<H3Error> & { status?: number; statusText?: string })
): H3Error {
if (typeof input === "string") {
return new H3Error(input);
}
Expand All @@ -52,23 +59,46 @@ export function createError (input: string | Partial<H3Error> & { status?: numbe
}

// @ts-ignore
const err = new H3Error(input.message ?? input.statusMessage, input.cause ? { cause: input.cause } : undefined);
const err = new H3Error(
input.message ?? input.statusMessage,
input.cause ? { cause: input.cause } : undefined
);

if ("stack" in input) {
try {
Object.defineProperty(err, "stack", { get () { return input.stack; } });
Object.defineProperty(err, "stack", {
get() {
return input.stack;
},
});
} catch {
try { err.stack = input.stack; } catch {}
try {
err.stack = input.stack;
} catch {}
}
}

if (input.data) { err.data = input.data; }
if (input.data) {
err.data = input.data;
}

if (input.statusCode) { err.statusCode = input.statusCode; } else if (input.status) { err.statusCode = input.status; }
if (input.statusMessage) { err.statusMessage = input.statusMessage; } else if (input.statusText) { err.statusMessage = input.statusText; }
if (input.statusCode) {
err.statusCode = input.statusCode;
} else if (input.status) {
err.statusCode = input.status;
}
if (input.statusMessage) {
err.statusMessage = input.statusMessage;
} else if (input.statusText) {
err.statusMessage = input.statusText;
}

if (input.fatal !== undefined) { err.fatal = input.fatal; }
if (input.unhandled !== undefined) { err.unhandled = input.unhandled; }
if (input.fatal !== undefined) {
err.fatal = input.fatal;
}
if (input.unhandled !== undefined) {
err.unhandled = input.unhandled;
}

return err;
}
Expand All @@ -83,23 +113,31 @@ export function createError (input: string | Partial<H3Error> & { status?: numbe
* @param debug {Boolean} Whether application is in debug mode.<br>
* In the debug mode the stack trace of errors will be return in response.
*/
export function sendError (event: H3Event, error: Error | H3Error, debug?: boolean) {
if (event.node.res.writableEnded) { return; }
export function sendError(
event: H3Event,
error: Error | H3Error,
debug?: boolean
) {
if (event.node.res.writableEnded) {
return;
}

const h3Error = isError(error) ? error : createError(error);

const responseBody = {
statusCode: h3Error.statusCode,
statusMessage: h3Error.statusMessage,
stack: [] as string[],
data: h3Error.data
data: h3Error.data,
};

if (debug) {
responseBody.stack = (h3Error.stack || "").split("\n").map(l => l.trim());
responseBody.stack = (h3Error.stack || "").split("\n").map((l) => l.trim());
}

if (event.node.res.writableEnded) { return; }
if (event.node.res.writableEnded) {
return;
}
const _code = Number.parseInt(h3Error.statusCode as unknown as string);
if (_code) {
event.node.res.statusCode = _code;
Expand All @@ -111,6 +149,6 @@ export function sendError (event: H3Event, error: Error | H3Error, debug?: boole
event.node.res.end(JSON.stringify(responseBody, undefined, 2));
}

export function isError (input: any): input is H3Error {
export function isError(input: any): input is H3Error {
return input?.constructor?.__h3_error__ === true;
}

0 comments on commit a0e21c1

Please sign in to comment.