Skip to content

Commit

Permalink
Merge pull request #63 from chomosuke/shangzhel/lifecycle
Browse files Browse the repository at this point in the history
Implement app lifecycle
  • Loading branch information
shangzhel committed Sep 7, 2021
2 parents 5b7f6d9 + 0ecdea0 commit 2c93170
Show file tree
Hide file tree
Showing 15 changed files with 829 additions and 73 deletions.
34 changes: 34 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 40 additions & 1 deletion server/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { ArgumentParser } from 'argparse';
import express from 'express';
import express, { ErrorRequestHandler, RequestHandler } from 'express';
import { readFile } from 'fs/promises';
import { createConnection } from 'mongoose';
import { resolve } from 'path';
import { env } from 'process';
import { ApiRouter } from './api/api-router';
import { HttpStatusError } from './api/HttpStatusError';

interface IArgs {
dist: string;
Expand All @@ -12,6 +14,41 @@ interface IArgs {
secret: string;
}

type ServeIndexRequestHandlerAsync =
(distPath: string, ...args: Parameters<RequestHandler>) => Promise<void>;

const serveIndexAsync: ServeIndexRequestHandlerAsync = async (distPath, _req, res) => {
const index = resolve(distPath, 'index.html');
let file: Buffer;
try {
file = await readFile(index);
} catch {
throw new HttpStatusError(404);
}
res.status(200).contentType('.html').send(file);
};

function serveIndex(distPath: string): RequestHandler {
/* eslint-disable-next-line @typescript-eslint/no-shadow */
const serveIndex: RequestHandler = (...args) => {
serveIndexAsync(distPath, ...args).catch(args[2]);
};

return serveIndex;
}

/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
const errorHandler: ErrorRequestHandler = (err, _req, res, _next) => {
if (err) {
if (err instanceof HttpStatusError) {
res.status(err.code).send(err.message);
return;
}
}

res.sendStatus(500);
};

async function main() {
const parser = new ArgumentParser();
parser.add_argument('-d', '--dist');
Expand All @@ -36,6 +73,8 @@ async function main() {

app.use('/api', apiRouter.router);
app.use(dist);
app.get('*', serveIndex(distPath));
app.use(errorHandler);

console.log(`Listening on port ${port}...`);
app.listen(port);
Expand Down
85 changes: 85 additions & 0 deletions shared/src/__tests__/ensure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { ensureArray, ensureObject, ensureType } from '../ensure';

const map = {
undefined,
number: Number(),
bigint: BigInt(Number()),
boolean: Boolean(),
string: String(),
symbol: Symbol('symbol'),
object: Object(),
function() { },
};

/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
function asTypeTag(tag: string): any {
return tag;
}

describe('ensure tests', () => {
describe('ensureType tests', () => {
describe('Success tests', () => {
Object
.entries(map)
.forEach(([k, v]) => test(k, () => {
expect(() => ensureType(v, asTypeTag(k))).not.toThrow();
}));

test('null', () => {
expect(() => ensureType(null, 'object')).not.toThrow();
});
});

describe('Fail tests', () => {
Object
.entries(map)
.forEach(([k0, v]) => describe(k0, () => {
Object
.keys(map)
.filter((k1) => k0 !== k1)
.map((k1) => test(k1, () => {
expect(() => ensureType(v, asTypeTag(k1))).toThrow();
}));
}));

describe('null', () => {
Object
.keys(map)
.filter((k) => k !== 'object')
.map((k) => test(k, () => {
expect(() => ensureType(null, asTypeTag(k))).toThrow();
}));
});
});
});

describe('ensureObject tests', () => {
test('Success test', () => {
expect(() => ensureObject(Object())).not.toThrow();
});

describe('Fail tests', () => {
Object
.entries(map)
.filter(([k]) => k !== 'object')
.map(([k, v]) => test(k, () => {
expect(() => ensureObject(v)).toThrow();
}));
});
});

describe('ensureArray tests', () => {
test('Success test', () => {
expect(() => ensureArray([])).not.toThrow();
});

describe('Fail tests', () => {
Object
.entries(map)
.concat([['null', null]])
.map(([k, v]) => test(k, () => {
expect(() => ensureArray(v)).toThrow();
}));
});
});
});
1 change: 0 additions & 1 deletion shared/src/__tests__/index.ts

This file was deleted.

33 changes: 33 additions & 0 deletions shared/src/ensure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { TypeOfTag } from 'typescript';

export type AnyUnknown = { [k: string]: unknown };

export function ensureType(value: unknown, type: 'undefined'): undefined;
export function ensureType(value: unknown, type: 'number'): number;
export function ensureType(value: unknown, type: 'bigint'): bigint;
export function ensureType(value: unknown, type: 'boolean'): boolean;
export function ensureType(value: unknown, type: 'string'): string;
export function ensureType(value: unknown, type: 'symbol'): symbol;
export function ensureType(value: unknown, type: 'object'): AnyUnknown | null;
export function ensureType(value: unknown, type: 'function'): CallableFunction;

export function ensureType(value: unknown, type: TypeOfTag): unknown {
if (typeof value !== type) throw new Error(`typeof value is not ${type}`);

return value;
}

export function ensureObject(value: unknown): AnyUnknown {
if (value == null) throw new Error('value is nullish');

const ensured = ensureType(value, 'object');
if (ensured == null) throw new Error('ensured is null');

return ensured;
}

export function ensureArray(value: unknown): unknown[] {
if (!(value instanceof Array)) throw new Error(`value is not instanceof ${Array.name}`);

return value;
}
1 change: 1 addition & 0 deletions shared/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './api-types';
export * from './ensure';
1 change: 1 addition & 0 deletions web/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ webpack({
},
plugins: [
new HtmlWebpackPlugin({
publicPath: '/',
title: args.title,
template: src('index.ejs')
})
Expand Down
1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@types/react-router-dom": "^5.1.8",
"@types/react-test-renderer": "^17.0.1",
"argparse": "^2.0.1",
"buffer": "^6.0.3",
"history": "^5.0.1",
"html-webpack-plugin": "^5.3.2",
"prop-types": "^15.7.2",
Expand Down
Loading

0 comments on commit 2c93170

Please sign in to comment.