Skip to content

Commit

Permalink
Add FunctionCall Value
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed May 4, 2024
1 parent 48158df commit adcd66f
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 20 deletions.
11 changes: 4 additions & 7 deletions example/index.ts
Expand Up @@ -3,12 +3,9 @@ import { TypeCompiler } from '@sinclair/typebox/compiler'
import { Value, ValuePointer } from '@sinclair/typebox/value'
import { Type, TypeGuard, KindGuard, Kind, Static, TSchema } from '@sinclair/typebox'

function Enum(value: unknown[]) {
return Type.FunctionCall(null, [], Type.Undefined())
}


const D = Type.Object({
constructor: Type.Object({ name: Type.Literal('Date') })
})
const date = new Date()
console.log(date.constructor.name)
console.log(Value.Check(D, new Date())) // this should work
console.log(Value.Check(Enum([1, 2, 3]), () => { console.log('hmmm' )} ))

13 changes: 3 additions & 10 deletions src/type/function-call/function-call.ts
Expand Up @@ -30,7 +30,6 @@ import type { TSchema, SchemaOptions } from '../schema/index'
import type { Static } from '../static/index'
import type { Ensure } from '../helpers/index'
import { CloneType } from '../clone/type'
import { Clone } from '../clone/value'
import { Kind } from '../symbols/index'

// ------------------------------------------------------------------
Expand All @@ -49,18 +48,12 @@ export interface TFunctionCall<T extends unknown[] = unknown[], U extends TSchem
[Kind]: 'Call'
static: StaticFunctionCall<T, U, this['params']>
functionCall: {
thisArg: unknown
parameters: [...T]
returns: U
}
}
/** `[JavaScript]` Creates a FunctionCall type */
export function FunctionCall<T extends unknown[], U extends TSchema>(parameters: [...T], returns: U, options?: SchemaOptions): TFunctionCall<T, U> {
return {
...options,
[Kind]: 'FunctionCall',
functionCall: {
parameters: Clone(parameters),
returns: CloneType(returns),
},
} as never
export function FunctionCall<T extends unknown[], U extends TSchema>(thisArg: unknown, parameters: [...T], returns: U, options?: SchemaOptions): TFunctionCall<T, U> {
return { ...options, [Kind]: 'FunctionCall', functionCall: { thisArg, parameters, returns: CloneType(returns) } } as never
}
1 change: 1 addition & 0 deletions src/type/guard/type.ts
Expand Up @@ -276,6 +276,7 @@ export function IsFunctionCall(value: unknown): value is TFunctionCall {
IsKindOf(value, 'FunctionCall') &&
ValueGuard.HasPropertyKey(value, 'functionCall') &&
ValueGuard.IsObject(value.functionCall) && (
ValueGuard.HasPropertyKey(value.functionCall, 'thisArg') &&
ValueGuard.HasPropertyKey(value.functionCall, 'parameters') &&
ValueGuard.HasPropertyKey(value.functionCall, 'returns') &&
ValueGuard.IsArray(value.functionCall.parameters) &&
Expand Down
4 changes: 2 additions & 2 deletions src/type/type/javascript.ts
Expand Up @@ -63,8 +63,8 @@ export class JavaScriptTypeBuilder extends JsonTypeBuilder {
return BigInt(options)
}
/** `[JavaScript]` Creates a FunctionCall type */
public FunctionCall<T extends unknown[], U extends TSchema>(parameters: [...T], returnType: U, options: SchemaOptions = {}): TFunctionCall<T, U> {
return FunctionCall(parameters, returnType, options)
public FunctionCall<T extends unknown[], U extends TSchema>(thisArg: unknown, parameters: [...T], returnType: U, options: SchemaOptions = {}): TFunctionCall<T, U> {
return FunctionCall(thisArg, parameters, returnType, options)
}
/** `[JavaScript]` Creates a ConstructorCall type */
public ConstructorCall<T extends unknown[], U extends TSchema>(parameters: [...T], returnType: U, options: SchemaOptions = {}): TConstructorCall<T, U> {
Expand Down
10 changes: 10 additions & 0 deletions src/value/check/check.ts
Expand Up @@ -44,6 +44,7 @@ import type { TBoolean } from '../../type/boolean/index'
import type { TDate } from '../../type/date/index'
import type { TConstructor } from '../../type/constructor/index'
import type { TFunction } from '../../type/function/index'
import type { TFunctionCall } from '../../type/function-call/index'
import type { TInteger } from '../../type/integer/index'
import type { TIntersect } from '../../type/intersect/index'
import type { TIterator } from '../../type/iterator/index'
Expand Down Expand Up @@ -185,6 +186,13 @@ function FromDate(schema: TDate, references: TSchema[], value: any): boolean {
function FromFunction(schema: TFunction, references: TSchema[], value: any): boolean {
return IsFunction(value)
}
function FromFunctionCall(schema: TFunctionCall, references: TSchema[], value: any): boolean {
try {
return IsFunction(value) && Visit(schema.functionCall.returns, references, value.apply(schema.functionCall.thisArg, schema.functionCall.parameters))
} catch {
return false
}
}
function FromInteger(schema: TInteger, references: TSchema[], value: any): boolean {
if (!IsInteger(value)) {
return false
Expand Down Expand Up @@ -434,6 +442,8 @@ function Visit<T extends TSchema>(schema: T, references: TSchema[], value: any):
return FromDate(schema_, references_, value)
case 'Function':
return FromFunction(schema_, references_, value)
case 'FunctionCall':
return FromFunctionCall(schema_, references_, value)
case 'Integer':
return FromInteger(schema_, references_, value)
case 'Intersect':
Expand Down
10 changes: 10 additions & 0 deletions src/value/create/create.ts
Expand Up @@ -45,6 +45,7 @@ import type { TBoolean } from '../../type/boolean/index'
import type { TDate } from '../../type/date/index'
import type { TConstructor } from '../../type/constructor/index'
import type { TFunction } from '../../type/function/index'
import type { TFunctionCall } from '../../type/function-call/index'
import type { TInteger } from '../../type/integer/index'
import type { TIntersect } from '../../type/intersect/index'
import type { TIterator } from '../../type/iterator/index'
Expand Down Expand Up @@ -165,6 +166,13 @@ function FromFunction(schema: TFunction, references: TSchema[]): any {
return () => Visit(schema.returns, references)
}
}
function FromFunctionCall(schema: TFunctionCall, references: TSchema[]): any {
if (HasPropertyKey(schema, 'default')) {
return FromDefault(schema.default)
} else {
return () => Visit(schema.functionCall.returns, references)
}
}
function FromInteger(schema: TInteger, references: TSchema[]): any {
if (HasPropertyKey(schema, 'default')) {
return FromDefault(schema.default)
Expand Down Expand Up @@ -409,6 +417,8 @@ function Visit(schema: TSchema, references: TSchema[]): unknown {
return FromDate(schema_, references_)
case 'Function':
return FromFunction(schema_, references_)
case 'FunctionCall':
return FromFunctionCall(schema_, references_)
case 'Integer':
return FromInteger(schema_, references_)
case 'Intersect':
Expand Down
2 changes: 1 addition & 1 deletion src/value/guard/guard.ts
Expand Up @@ -182,7 +182,7 @@ export function IsString(value: unknown): value is string {
return typeof value === 'string'
}
/** Returns true if this value is a function */
export function IsFunction(value: unknown): value is Function {
export function IsFunction(value: unknown): value is (...args: unknown[]) => unknown {
return typeof value === 'function'
}
/** Returns true if this value is a symbol */
Expand Down
7 changes: 7 additions & 0 deletions src/value/transform/has.ts
Expand Up @@ -34,6 +34,7 @@ import type { TArray } from '../../type/array/index'
import type { TAsyncIterator } from '../../type/async-iterator/index'
import type { TConstructor } from '../../type/constructor/index'
import type { TFunction } from '../../type/function/index'
import type { TFunctionCall } from '../../type/function-call/index'
import type { TIntersect } from '../../type/intersect/index'
import type { TIterator } from '../../type/iterator/index'
import type { TNot } from '../../type/not/index'
Expand Down Expand Up @@ -71,6 +72,10 @@ function FromFunction(schema: TFunction, references: TSchema[]) {
return IsTransform(schema) || Visit(schema.returns, references) || schema.parameters.some((schema) => Visit(schema, references))
}
// prettier-ignore
function FromFunctionCall(schema: TFunctionCall, references: TSchema[]) {
return IsTransform(schema) || Visit(schema.functionCall.returns, references)
}
// prettier-ignore
function FromIntersect(schema: TIntersect, references: TSchema[]) {
return IsTransform(schema) || IsTransform(schema.unevaluatedProperties) || schema.allOf.some((schema) => Visit(schema, references))
}
Expand Down Expand Up @@ -135,6 +140,8 @@ function Visit(schema: TSchema, references: TSchema[]): boolean {
return FromConstructor(schema_, references_)
case 'Function':
return FromFunction(schema_, references_)
case 'FunctionCall':
return FromFunctionCall(schema_, references_)
case 'Intersect':
return FromIntersect(schema_, references_)
case 'Iterator':
Expand Down

0 comments on commit adcd66f

Please sign in to comment.