From 0bc519705518e37bb57c8de9b4052252730443e0 Mon Sep 17 00:00:00 2001 From: sinclair Date: Wed, 29 Nov 2023 00:09:47 +0900 Subject: [PATCH] Revision 0.32.0 --- src/index.ts | 1 + src/type/builder/javascript.ts | 5 + src/type/builder/type.ts | 1 + src/type/const/const.ts | 128 ++++++++++++++++++++++++++ src/type/const/index.ts | 29 ++++++ src/type/guard/value.ts | 16 ++++ src/type/index.ts | 1 + src/type/template-literal/generate.ts | 8 +- src/type/template-literal/parser.ts | 8 +- todo.md | 8 +- 10 files changed, 194 insertions(+), 11 deletions(-) create mode 100644 src/type/const/const.ts create mode 100644 src/type/const/index.ts diff --git a/src/index.ts b/src/index.ts index 1316d723a..fdc4c6ae6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -45,6 +45,7 @@ export { BigInt, type TBigInt, BigIntOptions } from './type/bigint/index' export { Boolean, type TBoolean } from './type/boolean/index' export { Capitalize, type TCapitalize } from './type/intrinsic/index' export { Composite, type TComposite } from './type/composite/index' +export { Const, type TConst } from './type/const/index' export { Constructor, type TConstructor } from './type/constructor/index' export { ConstructorParameters, type TConstructorParameters } from './type/constructor-parameters/index' export { Date, type TDate, type DateOptions } from './type/date/index' diff --git a/src/type/builder/javascript.ts b/src/type/builder/javascript.ts index f31f4a6f0..dcc8ac55c 100644 --- a/src/type/builder/javascript.ts +++ b/src/type/builder/javascript.ts @@ -30,6 +30,7 @@ import { JsonTypeBuilder } from './json' import { AsyncIterator, type TAsyncIterator } from '../async-iterator/index' import { Awaited, type TAwaited } from '../awaited/index' import { BigInt, type TBigInt, type BigIntOptions } from '../bigint/index' +import { Const, type TConst } from '../const/index' import { Constructor, type TConstructor } from '../constructor/index' import { ConstructorParameters, type TConstructorParameters } from '../constructor-parameters/index' import { Date, type TDate, type DateOptions } from '../date/index' @@ -60,6 +61,10 @@ export class JavaScriptTypeBuilder extends JsonTypeBuilder { public BigInt(options: BigIntOptions = {}): TBigInt { return BigInt(options) } + /** `[JavaScript]` Creates a readonly const type from the given value. */ + public Const(value: T, options: SchemaOptions = {}): TConst { + return Const(value, options) + } /** `[JavaScript]` Extracts the ConstructorParameters from the given Constructor type */ public ConstructorParameters>(schema: T, options: SchemaOptions = {}): TConstructorParameters { return ConstructorParameters(schema, options) diff --git a/src/type/builder/type.ts b/src/type/builder/type.ts index 7b575c6e4..4671ededb 100644 --- a/src/type/builder/type.ts +++ b/src/type/builder/type.ts @@ -36,6 +36,7 @@ export { Awaited } from '../awaited/index' export { BigInt } from '../bigint/index' export { Boolean } from '../boolean/index' export { Composite } from '../composite/index' +export { Const } from '../const/index' export { Constructor } from '../constructor/index' export { ConstructorParameters } from '../constructor-parameters/index' export { Date } from '../date/index' diff --git a/src/type/const/const.ts b/src/type/const/const.ts new file mode 100644 index 000000000..4c1513677 --- /dev/null +++ b/src/type/const/const.ts @@ -0,0 +1,128 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { AssertProperties, AssertRest, Evaluate } from '../helpers/index' +import type { TSchema, SchemaOptions } from '../schema/index' +import type { TProperties } from '../object/index' +import { IsArray, IsNumber, IsBigInt, IsUint8Array, IsDate, IsIterator, IsObject, IsAsyncIterator, IsFunction, IsUndefined, IsNull, IsSymbol, IsBoolean, IsString } from '../guard/value' +import { AsyncIterator, type TAsyncIterator } from '../async-iterator/index' +import { BigInt, type TBigInt } from '../bigint/index' +import { Date, type TDate } from '../date/index' +import { Function, type TFunction } from '../function/index' +import { Literal, type TLiteral } from '../literal/index' +import { Iterator, type TIterator } from '../iterator/index' +import { Never, type TNever } from '../never/index' +import { Null, type TNull } from '../null/index' +import { Object, type TObject } from '../object/index' +import { Symbol, type TSymbol } from '../symbol/index' +import { Tuple, type TTuple } from '../tuple/index' +import { Readonly, type TReadonly } from '../readonly/index' +import { Undefined, type TUndefined } from '../undefined/index' +import { Uint8Array, type TUint8Array } from '../uint8array/index' +import { Unknown, type TUnknown } from '../unknown/index' +import { TypeClone } from '../clone/index' + +// ------------------------------------------------------------------ +// FromArray +// ------------------------------------------------------------------ +// prettier-ignore +export type FromArray = + T extends readonly [infer L, ...infer R] + ? [FromValue, ...FromArray] + : T +// prettier-ignore +function FromArray(T: [...T]): FromArray { + const [L, ...R] = T + return ( + T.length > 0 + ? [FromValue(L), ...FromArray(R)] + : [] + ) as FromArray +} +// ------------------------------------------------------------------ +// FromProperties +// ------------------------------------------------------------------ +// prettier-ignore +export type FromProperties> = { + -readonly [K in keyof T]: TReadonly> +} +// prettier-ignore +function FromProperties>(value: T): FromProperties { + return globalThis.Object.getOwnPropertyNames(value).reduce((acc, key) => { + return { ...acc, [key]: Readonly(FromValue(value[key])) } + }, {} as TProperties) as unknown as FromProperties +} +// ------------------------------------------------------------------ +// FromValue +// ------------------------------------------------------------------ +// prettier-ignore +export type FromValue = + T extends readonly unknown[] ? TTuple>> : + T extends Uint8Array ? TUint8Array : + T extends Date ? TDate : + T extends Record ? TObject>>> : + T extends AsyncIterableIterator ? TAsyncIterator : + T extends IterableIterator ? TIterator : + T extends Function ? TFunction<[], TUnknown> : + T extends undefined ? TUndefined : + T extends null ? TNull : + T extends symbol ? TSymbol : + T extends number ? TLiteral : + T extends boolean ? TLiteral : + T extends string ? TLiteral : + T extends bigint ? TBigInt : + TNever +// prettier-ignore +function FromValue(value: T): FromValue { + return ( + IsArray(value) ? Tuple(FromArray(value) as TSchema[]) : + IsUint8Array(value) ? Uint8Array() : + IsDate(value) ? Date() : + IsObject(value) ? Object(FromProperties(value) as TProperties) : + IsAsyncIterator(value) ? AsyncIterator(Unknown()) : + IsIterator(value) ? Iterator(Unknown()) : + IsFunction(value) ? Function([], Unknown()) : + IsUndefined(value) ? Undefined() : + IsNull(value) ? Null() : + IsSymbol(value) ? Symbol() : + IsBigInt(value) ? BigInt() : + IsNumber(value) ? Literal(value) : + IsBoolean(value) ? Literal(value) : + IsString(value) ? Literal(value) : + Never() + ) as unknown as FromValue +} +// ------------------------------------------------------------------ +// TConst +// ------------------------------------------------------------------ +export type TConst = FromValue + +/** `[JavaScript]` Creates a readonly const type from the given value. */ +export function Const(T: T, options: SchemaOptions = {}): TConst { + return TypeClone.CloneType(FromValue(T), options) as TConst +} diff --git a/src/type/const/index.ts b/src/type/const/index.ts new file mode 100644 index 000000000..e326da86c --- /dev/null +++ b/src/type/const/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox + +The MIT License (MIT) + +Copyright (c) 2017-2023 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './const' diff --git a/src/type/guard/value.ts b/src/type/guard/value.ts index 9ea64b1fe..ece58e873 100644 --- a/src/type/guard/value.ts +++ b/src/type/guard/value.ts @@ -26,6 +26,10 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ +/** Returns true if this value is an async iterator */ +export function IsAsyncIterator(value: unknown): value is AsyncIterableIterator { + return IsObject(value) && Symbol.asyncIterator in value +} /** Returns true if this value is an array */ export function IsArray(value: unknown): value is unknown[] { return Array.isArray(value) @@ -42,6 +46,14 @@ export function IsBoolean(value: unknown): value is boolean { export function IsDate(value: unknown): value is Date { return value instanceof globalThis.Date } +/** Returns true if this value is a function */ +export function IsFunction(value: unknown): value is Function { + return typeof value === 'function' +} +/** Returns true if this value is an iterator */ +export function IsIterator(value: unknown): value is IterableIterator { + return IsObject(value) && Symbol.iterator in value +} /** Returns true if this value is null */ export function IsNull(value: unknown): value is null { return value === null @@ -58,6 +70,10 @@ export function IsObject(value: unknown): value is Record export function IsString(value: unknown): value is string { return typeof value === 'string' } +/** Returns true if this value is symbol */ +export function IsSymbol(value: unknown): value is symbol { + return typeof value === 'symbol' +} /** Returns true if this value is a Uint8Array */ export function IsUint8Array(value: unknown): value is Uint8Array { return value instanceof globalThis.Uint8Array diff --git a/src/type/index.ts b/src/type/index.ts index 7cf39c7a7..09dcd54be 100644 --- a/src/type/index.ts +++ b/src/type/index.ts @@ -35,6 +35,7 @@ export * from './boolean/index' export * from './builder/index' export * from './clone/index' export * from './composite/index' +export * from './const/index' export * from './constructor/index' export * from './constructor-parameters/index' export * from './date/index' diff --git a/src/type/template-literal/generate.ts b/src/type/template-literal/generate.ts index b913f6cdc..d002845ec 100644 --- a/src/type/template-literal/generate.ts +++ b/src/type/template-literal/generate.ts @@ -28,7 +28,7 @@ THE SOFTWARE. import type { TTemplateLiteral, TTemplateLiteralKind } from './index' import type { TLiteral, TLiteralValue } from '../literal/index' -import type { Expression, And, Or, Const } from './parser' +import type { Expression, ExpressionAnd, ExpressionOr, ExpressionConst } from './parser' import type { TUnion } from '../union/index' // ------------------------------------------------------------------ @@ -88,15 +88,15 @@ function* GenerateReduce(buffer: string[][]): IterableIterator { } } // prettier-ignore -function* GenerateAnd(expression: And): IterableIterator { +function* GenerateAnd(expression: ExpressionAnd): IterableIterator { return yield* GenerateReduce(expression.expr.map((expr) => [...TemplateLiteralGenerate(expr)])) } // prettier-ignore -function* GenerateOr(expression: Or): IterableIterator { +function* GenerateOr(expression: ExpressionOr): IterableIterator { for (const expr of expression.expr) yield* TemplateLiteralGenerate(expr) } // prettier-ignore -function* GenerateConst(expression: Const): IterableIterator { +function* GenerateConst(expression: ExpressionConst): IterableIterator { return yield expression.const } // ------------------------------------------------------------------ diff --git a/src/type/template-literal/parser.ts b/src/type/template-literal/parser.ts index 401abec6b..02439de34 100644 --- a/src/type/template-literal/parser.ts +++ b/src/type/template-literal/parser.ts @@ -34,10 +34,10 @@ export class TemplateLiteralParserError extends Error {} // TemplateLiteralParse // ------------------------------------------------------------------ // prettier-ignore -export type Expression = And | Or | Const -export type Const = { type: 'const'; const: string } -export type And = { type: 'and'; expr: Expression[] } -export type Or = { type: 'or'; expr: Expression[] } +export type Expression = ExpressionAnd | ExpressionOr | ExpressionConst +export type ExpressionConst = { type: 'const'; const: string } +export type ExpressionAnd = { type: 'and'; expr: Expression[] } +export type ExpressionOr = { type: 'or'; expr: Expression[] } // prettier-ignore function IsNonEscaped(pattern: string, index: number, char: string) { return pattern[index] === char && pattern.charCodeAt(index - 1) !== 92 diff --git a/todo.md b/todo.md index 15f842e1a..ae9451792 100644 --- a/todo.md +++ b/todo.md @@ -2,6 +2,8 @@ for general composition (i think) but not for key generation. - Investigate Transform Issue: https://github.com/sinclairzx81/typebox/issues/554 - Clean up Composite (Should technically support Intersect and Union) -- Exclude, Extract and Extends could use a clean up -- Look for invalid import references -- The Symbols Change May be a bit too breaking. Move Kind, Hint, and others to the top (again) \ No newline at end of file +- [x] Exclude, Extract and Extends could use a clean up +- [x] Look for invalid import references +- [x] The Symbols Change May be a bit too breaking. Move Kind, Hint, and others to the top (again) +- [ ] Implement static tests for Type.Const() +- [ ] Implement experimental Type.Mapped(). This will only be usable on the Workbench \ No newline at end of file