From 0d57ff978344e83e63ded17966bf8315bb748a0a Mon Sep 17 00:00:00 2001 From: Hide_D Date: Tue, 8 Aug 2023 14:16:03 +0000 Subject: [PATCH] =?UTF-8?q?=EC=97=85=EA=B7=B8=EB=A0=88=EC=9D=B4=EB=93=9C?= =?UTF-8?q?=20-=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=20ProcDecorator?= =?UTF-8?q?=20-=20Promise=20-=20Pre,=20Post=20=EB=AA=A8=EB=93=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/api/decorator/base.ts | 159 ++++++++++++++++++++++++++------ server/api/decorator/base2.d.ts | 17 ---- server/api/decorator/base2.js | 3 - server/api/decorator/test2.ts | 116 ----------------------- 4 files changed, 131 insertions(+), 164 deletions(-) delete mode 100644 server/api/decorator/base2.d.ts delete mode 100644 server/api/decorator/base2.js delete mode 100644 server/api/decorator/test2.ts diff --git a/server/api/decorator/base.ts b/server/api/decorator/base.ts index b5a8d13..d98b2fc 100644 --- a/server/api/decorator/base.ts +++ b/server/api/decorator/base.ts @@ -1,44 +1,147 @@ -import { Request, Response, NextFunction } from "express"; -import { ReqLogin } from "./reqLogin"; -import { ReqGameLogin } from "./reqGameLogin"; -import { ParseUserLevel } from "./ParseUserLevel"; -import { DeclConverter } from "./base2"; -export type InvalidConversion = { - isInvalid: true; +type MayBePromise = T | Promise; + +export type InvalidProc = { + invalidProcSymbol: unknown; reason?: string; alreadyProcessed?: boolean; } -export interface BaseConverter{ - (inCtx: In, request: Request, response: Response): Out | InvalidConversion; +export interface ProcDecorator> { + (inCtx: In, req: Request, res: Response): MayBePromise; } -function Chain(args: In, request: Request, response: Response) { - return { - next: (inner: (payload: In, request: Request, response: Response) => Out) => { - return Chain(inner(args, request, response), request, response); - } +type Empty = Record; + +type Login = { + userID: number; +} +type GameLogin = { + userID: number; + generalID: number; +} +type UserLevel = { + userID: number; + userLevel: number; +} + +export function ParseUserLevel(): ProcDecorator { + return (inCtx) => { + return { + userLevel: 123, + ...inCtx, + }; } } -type ExtendsType = T extends U ? T : never; +export function ReqLogin(): [ProcDecorator, ProcDecorator] { + return [ + (inCtx) => { + return { + userID: 999, + ...inCtx, + }; + }, + (inCtx) => { + //무언가 + return inCtx; + } + ] +} + +export function ReqGameLogin(): ProcDecorator { + return (inCtx) => { + return { + generalID: inCtx.userID * 4, + ...inCtx, + }; + } +} + +type Compose2 = D & B extends A & C ? B extends C ? ProcDecorator : never : never; + +type PD1 = () => ProcDecorator; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type PD2 = () => [ProcDecorator, ProcDecorator]; + +type PackChain = + T extends readonly [] ? ProcDecorator : + T extends readonly [PD1] ? ProcDecorator : + T extends readonly [PD2] ? ProcDecorator : + T extends readonly [PD1, PD1, ... infer R] ? PackChain<[() => Compose2, ...R]> : + T extends readonly [PD2, PD1, ... infer R] ? PackChain<[() => Compose2, ...R]> : + T extends readonly [PD1, PD2, ... infer R] ? PackChain<[() => Compose2, ...R]> : + T extends readonly [PD2, PD2, ... infer R] ? PackChain<[() => Compose2, ...R]> : + never; + +type Resolve = T extends ProcDecorator ? Empty extends A ? B : never : never; + + +export type ResolveChain = Resolve>; + +const q1 = [ + ReqLogin, + ParseUserLevel, + ReqGameLogin, +] as const; + +const q2 = [ + ReqLogin, + ParseUserLevel, +] as const; + + +type R1 = Resolve>; +type R2 = Resolve>; +const r1: R1 = undefined as unknown as R1; +const r2: R2 = undefined as unknown as R2; +r1.userLevel; +r2.userID; + + +async function test(req: Request, res: Response) { + const a0 = await ReqLogin()[0]({}, req, res); + if ('invalidProcSymbol' in a0) { + return false; + } + const a1 = await ParseUserLevel()(a0, req, res); + if ('invalidProcSymbol' in a1) { + return false; + } + const a2 = await ReqGameLogin()(a1, req, res); + if ('invalidProcSymbol' in a2) { + return false; + } + const b0 = await ReqLogin()[1](a2, req, res); + return true; +} + // eslint-disable-next-line @typescript-eslint/no-explicit-any +export type ProcDecoratorChain = readonly ((() => ProcDecorator) | (() => [ProcDecorator, ProcDecorator]))[]; +function unpack2, B>(v: A | [A, B]): A { + if (Array.isArray(v)) { + return v[0]; + } + return v; +} -//export function DeclConverter(): [[], Record]; +function test2(req: Request, res: Response, chain: T): Resolve> | false { + const tmp = chain[0](); + const actors = chain.map((v) => unpack2(v())); -//TODO: ReqLogin이 위에 있을 경우에만 통과시켜야..? -const a = DeclConverter( - ParseUserLevel(), - ReqLogin(), - ReqGameLogin(), -) + let result = {}; + for (const actor of actors) { + result = actor(result, req, res); + if ('isInvalid' in result) { + return false; + } + } + return result as Resolve>; +} -type b = Exclude<(typeof a)[1], InvalidConversion>; -const c: b = undefined as unknown as b; -//흠.... -console.log(c.generalID); -console.log(c.userID); -console.log(c.userLevel); \ No newline at end of file +const finalResult1 = test2({} as Request, {} as Response, q1); +if (finalResult1 !== false) { + finalResult1.userLevel; +} \ No newline at end of file diff --git a/server/api/decorator/base2.d.ts b/server/api/decorator/base2.d.ts deleted file mode 100644 index fefa0f1..0000000 --- a/server/api/decorator/base2.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -type C = (...args: any) => any; -type Rev = ()=> A; - -type ChainResult = - T extends [infer R0 extends C] ? ReturnType : - T extends [infer R1 extends C, infer R0 extends C] ? ReturnType & ReturnType : - T extends [infer R2, infer R1, ...infer RX] ? ChainResult2, ChainResult<[Rev>, ...RX]>> : - never; - -type ChainResult2 = T extends ChainResult<[A, B]> ? ANS: never; - -export function DeclConverter(r0: R0): [[R0], ReturnType]; -export function DeclConverter(r0: R0, r1: R1): [[R0, R1], ChainResult<[R0, R1]>]; -export function DeclConverter(r0: R0, r1: R1, r2:R2) : [[R0, R1, R2], ChainResult<[R0, R1, R2]>]; -export function DeclConverter(r0: R0, r1: R1, r2:R2, r3:R3) : [[R0, R1, R2, R3], ChainResult<[R0, R1, R2, R3]>]; -export function DeclConverter(r0: R0, r1: R1, r2:R2, r3:R3, r4:R4) : [[R0, R1, R2, R3, R4], ChainResult<[R0, R1, R2, R3, R4]>]; diff --git a/server/api/decorator/base2.js b/server/api/decorator/base2.js deleted file mode 100644 index 3b453ca..0000000 --- a/server/api/decorator/base2.js +++ /dev/null @@ -1,3 +0,0 @@ -export function DeclConverter(...target){ - return [target, undefined]; -} \ No newline at end of file diff --git a/server/api/decorator/test2.ts b/server/api/decorator/test2.ts deleted file mode 100644 index 3324dcb..0000000 --- a/server/api/decorator/test2.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { InvalidConversion } from "./base"; - -type MayBePromise = T | Promise; - -export interface Converter> { - (inCtx: In, req: Request, res: Response): MayBePromise; -} - -type Empty = Record; - -type Login = { - userID: number; -} -type GameLogin = { - userID: number; - generalID: number; -} -type UserLevel = { - userID: number; - userLevel: number; -} - -export function ParseUserLevel(): Converter { - return (inCtx) => { - return { - userLevel: 123, - ...inCtx, - }; - } -} - -export function ReqLogin(): Converter { - return (inCtx) => { - return { - userID: 999, - ...inCtx, - }; - } -} - -export function ReqGameLogin(): Converter { - return (inCtx) => { - return { - generalID: inCtx.userID * 4, - ...inCtx, - }; - } -} - -type Compose2 = D & B extends A & C ? B extends C ? Converter : never : never; -export type Chain = - T extends readonly [() => Converter] ? Converter : - T extends readonly [() => Converter, () => Converter] ? Compose2 : - T extends readonly [() => Converter, () => Converter, ... infer R] ? Chain<[() => Compose2, ...R]> : - never; - - -export type Solve = T extends Converter ? Empty extends A ? B : never : never; - - -const q1 = [ - ReqLogin, - ParseUserLevel, - ReqGameLogin, -] as const; - -const q2 = [ - ReqLogin, -] as const; - -type R1 = Solve>; -type R2 = Solve>; -const r1: R1 = undefined as unknown as R1; -const r2: R2 = undefined as unknown as R2; -r1.userLevel; -r2.userID; - - -async function test(req: Request, res: Response){ - const a0 = await ReqLogin()({}, req, res); - if('isInvalid' in a0){ - return false; - } - const a1 = await ParseUserLevel()(a0, req, res); - if('isInvalid' in a1){ - return false; - } - const a2 = await ReqGameLogin()(a1, req, res); - if('isInvalid' in a2){ - return false; - } - return true; -} - - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type Converters = readonly (() => Converter)[]; - -function test2(req: Request, res: Response, chain: T): Solve> | false{ - - const actors = chain.map((v) => v()); - - let result = {}; - for(const actor of actors){ - result = actor(result, req, res); - if('isInvalid' in result){ - return false; - } - } - return result as Solve>; -} - -const finalResult1 = test2({} as Request, {} as Response, q1); -if(finalResult1 !== false){ - finalResult1.userLevel; -} \ No newline at end of file