Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript fixes & minor cleanup #894

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ trace
*.tsbuildinfo
.wrangler
.elysia
.vscode
4 changes: 2 additions & 2 deletions example/cookie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ const app = new Elysia({
(council.value = [
{
name: 'Rin',
affilation: 'Administration'
affiliation: 'Administration'
}
]),
{
cookie: t.Cookie({
council: t.Array(
t.Object({
name: t.String(),
affilation: t.String()
affiliation: t.String()
})
)
})
Expand Down
14 changes: 8 additions & 6 deletions example/custom-response.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Elysia } from '../src'

const prettyJson = new Elysia().onAfterHandle(({ response }) => {
if (response instanceof Object)
try {
return JSON.stringify(response, null, 4)
} catch {}
})
const prettyJson = new Elysia().onAfterHandle(
({ response }: { response: unknown }) => {
if (response instanceof Object)
try {
return JSON.stringify(response, null, 4)
} catch {}
}
)

new Elysia()
.use(prettyJson)
Expand Down
6 changes: 2 additions & 4 deletions example/video.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Elysia } from 'elysia'
import { Elysia } from '../src'

new Elysia()
.get('/', Bun.file('test/kyuukurarin.mp4'))
.listen(3000)
new Elysia().get('/', Bun.file('test/kyuukurarin.mp4')).listen(3000)
2 changes: 1 addition & 1 deletion example/websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const app = new Elysia()
},
message(ws, message) {
ws.publish('asdf', message)
ws.send('asdf', message)
ws.send(message)
}
})
.get('/publish/:publish', ({ params: { publish: text } }) => {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"test:imports": "bun run ./test/type-system/import.ts",
"test:types": "tsc --project tsconfig.test.json",
"test:node": "npm install --prefix ./test/node/cjs/ && npm install --prefix ./test/node/esm/ && node ./test/node/cjs/index.js && node ./test/node/esm/index.js && bun dist/bun/index.js",
"pretest:node": "npm run build",
"dev": "bun run --watch example/a.ts",
"build": "rm -rf dist && bun build.ts",
"release": "npm run build && npm run test && npm publish"
Expand Down
3 changes: 1 addition & 2 deletions src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,7 @@ export class ValidationError extends Error {
get all() {
return 'Errors' in this.validator
? [...this.validator.Errors(this.value)].map(mapValueError)
: // @ts-ignore
[...Value.Errors(this.validator, this.value)].map(mapValueError)
: [...Value.Errors(this.validator, this.value)].map(mapValueError)
}

static simplifyModel(validator: TSchema | TypeCheck<any>) {
Expand Down
14 changes: 3 additions & 11 deletions src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { StatusMap } from './utils'
import { Cookie } from './cookies'

import type { Context } from './context'
import type { LocalHook } from './types'
import type { HTTPHeaders, LocalHook } from './types'
import { ElysiaCustomStatusResponse } from './error'

const hasHeaderShorthand = 'toJSON' in new Headers()
Expand Down Expand Up @@ -112,14 +112,6 @@ export const serializeCookie = (cookies: Context['set']['cookie']) => {
return set
}

// const concatUint8Array = (a: Uint8Array, b: Uint8Array) => {
// const arr = new Uint8Array(a.length + b.length)
// arr.set(a, 0)
// arr.set(b, a.length)

// return arr
// }

const handleStream = async (
generator: Generator | AsyncGenerator,
set?: Context['set'],
Expand Down Expand Up @@ -196,8 +188,8 @@ const handleStream = async (
// Manually set transfer-encoding for direct response, eg. app.handle, eden
'transfer-encoding': 'chunked',
'content-type': 'text/event-stream; charset=utf-8',
...set?.headers
}
...((set?.headers || {}) as HTTPHeaders)
} as Record<string, string> | [string, string][] | Headers
}
)
}
Expand Down
105 changes: 17 additions & 88 deletions src/type-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import {
TArray,
TDate,
TUnsafe,
TypeRegistry
TypeRegistry,
type Static,
type TString,
type TTransform
} from '@sinclair/typebox'
import { TypeSystem } from '@sinclair/typebox/system'
import {
Type,
type SchemaOptions,
// type TNull,
// type TUnion,
type TSchema,
// type TUndefined,
TProperties,
ObjectOptions,
TObject,
Expand Down Expand Up @@ -98,8 +98,6 @@ const t = Object.assign({}, Type)
export namespace ElysiaTypeOptions {
export type Numeric = NumberOptions

export type FileUnit = number | `${number}${'k' | 'm'}`

export type StrictFileType =
| 'image'
| 'image/*'
Expand Down Expand Up @@ -186,6 +184,8 @@ export namespace ElysiaTypeOptions {
*/
sign?: Readonly<(keyof T | (string & {}))[]>
}

export type FileUnit = number | `${number}${'k' | 'm'}`
}

const parseFileUnit = (size: ElysiaTypeOptions.FileUnit) => {
Expand Down Expand Up @@ -318,8 +318,11 @@ type NonEmptyArray<T> = [T, ...T[]]

export type TEnumValue = number | string | null

export interface TUnionEnum<T extends NonEmptyArray<TEnumValue> | Readonly<NonEmptyArray<TEnumValue>> = [TEnumValue]>
extends TSchema {
export interface TUnionEnum<
T extends
| NonEmptyArray<TEnumValue>
| Readonly<NonEmptyArray<TEnumValue>> = [TEnumValue]
> extends TSchema {
type?: 'number' | 'string' | 'null'
[Kind]: 'UnionEnum'
static: T[number]
Expand Down Expand Up @@ -542,7 +545,7 @@ export const ElysiaType = {
throw new ValidationError('property', schema, value)

return JSON.stringify(value)
}) as any as TArray<T>
}) as any as TTransform<TString, Static<T>[]>
},
File,
Files: (options: ElysiaTypeOptions.Files = {}) =>
Expand Down Expand Up @@ -593,7 +596,11 @@ export const ElysiaType = {
return v
},
// based on https://github.com/elysiajs/elysia/issues/512#issuecomment-1980134955
UnionEnum: <const T extends NonEmptyArray<TEnumValue> | Readonly<NonEmptyArray<TEnumValue>>>(
UnionEnum: <
const T extends
| NonEmptyArray<TEnumValue>
| Readonly<NonEmptyArray<TEnumValue>>
>(
values: T,
options: SchemaOptions = {}
) => {
Expand Down Expand Up @@ -707,81 +714,3 @@ export {
TypeSystemDuplicateTypeKind
} from '@sinclair/typebox/system'
export { TypeCompiler, TypeCheck } from '@sinclair/typebox/compiler'

// type Template =
// | string
// | number
// | bigint
// | boolean
// | StringConstructor
// | NumberConstructor
// | undefined

// type Join<A> = A extends Readonly<[infer First, ...infer Rest]>
// ? (
// First extends Readonly<Template[]>
// ? First[number]
// : First extends StringConstructor
// ? string
// : First extends NumberConstructor
// ? `${number}`
// : First
// ) extends infer A
// ? Rest extends []
// ? A extends undefined
// ? NonNullable<A> | ''
// : A
// : // @ts-ignore
// A extends undefined
// ? `${NonNullable<A>}${Join<Rest>}` | ''
// : // @ts-ignore
// `${A}${Join<Rest>}`
// : ''
// : ''

// const template = <
// const T extends Readonly<(Template | Readonly<Template[]>)[]>
// >(
// ...p: T
// ): Join<T> => {
// return a as any
// }

// const create =
// <const T extends string>(t: T): ((t: T) => void) =>
// (t) =>
// t

// const optional = <
// const T extends Readonly<(Template | Readonly<Template[]>)[]>
// >(
// ...p: T
// ): T | undefined => {
// return undefined
// }

// template.optional = optional

// const hi = create(
// template(
// ['seminar', 'millennium'],
// ':',
// ['Rio', 'Yuuka', 'Noa', 'Koyuki'],
// template.optional(template(',', ['Rio', 'Yuuka', 'Noa', 'Koyuki'])),
// template.optional(template(',', ['Rio', 'Yuuka', 'Noa', 'Koyuki'])),
// template.optional(template(',', ['Rio', 'Yuuka', 'Noa', 'Koyuki']))
// )
// )

// hi(`seminar:Noa,Koyuki,Yuuka`)

// const a = TypeCompiler.Compile(t.String())

// console.log(v.Decode.toString())

// const T = t.Transform(v.schema)
// .Decode((value) => new Date(value)) // required: number to Date
// .Encode((value) => value.getTime()) // required: Date to number

// const decoded = Value.Decode(T, 0) // const decoded = Date(1970-01-01T00:00:00.000Z)
// const encoded = Value.Encode(T, decoded)
55 changes: 2 additions & 53 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1428,12 +1428,12 @@ type ElysiaFormData<T extends Record<string | number, unknown>> = FormData & {
export const ELYSIA_REQUEST_ID = Symbol('ElysiaRequestId')
export type ELYSIA_REQUEST_ID = typeof ELYSIA_REQUEST_ID

export const form = <const T extends Record<string | number, unknown>>(
export const form = <const T extends Record<string | number, string | Blob>>(
items: T
): ElysiaFormData<T> => {
const formData = new FormData()

for (const [key, value] of Object.entries(items)) {
for (const [key, value] of Object.entries<string | Blob>(items)) {
if (Array.isArray(value)) {
for (const v of value) {
if (value instanceof File)
Expand Down Expand Up @@ -1495,54 +1495,3 @@ export const promoteEvent = (

for (const event of events) if ('scope' in event) event.scope = 'global'
}

type PropertyKeys<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any ? never : K
}[keyof T]

type PropertiesOnly<T> = Pick<T, PropertyKeys<T>>

// export const classToObject = <T>(
// instance: T,
// processed: WeakMap<object, object> = new WeakMap()
// ): T extends object ? PropertiesOnly<T> : T => {
// if (typeof instance !== 'object' || instance === null)
// return instance as any

// if (Array.isArray(instance))
// return instance.map((x) => classToObject(x, processed)) as any

// if (processed.has(instance)) return processed.get(instance) as any

// const result: Partial<T> = {}

// for (const key of Object.keys(instance) as Array<keyof T>) {
// const value = instance[key]
// if (typeof value === 'object' && value !== null)
// result[key] = classToObject(value, processed) as T[keyof T]
// else result[key] = value
// }

// const prototype = Object.getPrototypeOf(instance)
// if (!prototype) return result as any

// const properties = Object.getOwnPropertyNames(prototype)

// for (const property of properties) {
// const descriptor = Object.getOwnPropertyDescriptor(
// Object.getPrototypeOf(instance),
// property
// )

// if (descriptor && typeof descriptor.get === 'function') {
// // ? Very important to prevent prototype pollution
// if (property === '__proto__') continue

// ;(result as any)[property as keyof typeof instance] = classToObject(
// instance[property as keyof typeof instance]
// )
// }
// }

// return result as any
// }
Loading