Skip to content

Commit

Permalink
Revision 0.30.0 Compression
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed Jul 26, 2023
1 parent f56fb74 commit ee72178
Show file tree
Hide file tree
Showing 21 changed files with 2,003 additions and 1,928 deletions.
74 changes: 60 additions & 14 deletions example/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,39 @@ import { Type, TypeGuard, Kind, Static, TSchema } from '@sinclair/typebox'
// - Add Readonly Symbol
// - Add Optional Symbol
// TypeExtends:
// - implemented StructuralRight()
// - implemented StructuralRight() - (done)
// deprecate Type.RegExp()
// - Deprecated Type.RegEx()
// - Add Type.RegExp()
// - Deprecated Type.RegEx() - (done)
// - Add Type.RegExp() - (done)
// Array: contains, minContains, maxContains
// - typecompiler - (done)
// - value - (done)
// - error - (done)
// - create - (done)
// - tests - (done)
// - typecompiler - (done)
// - value - (done)
// - error - (done)
// - create - (done)
// - tests - (done)
// Iterators: Type.Iterator & Type.IteratorAsync
// - typecompiler - (done)
// - value - (done)
// - error - (done)
// - create - (done)
// - cast - (done)
// - tests - (done - not create)
// - typecompiler - (done)
// - value - (done)
// - error - (done)
// - create - (done)
// - cast - (done)
// - tests - (done - not create)
// Value
// - remove namespaces - (done)
// - retain value pointer - (done)
// - add common value guard utility - (done)
// - figure out what to do with non-nomimal-object

// 0.29.0
// ┌──────────────────────┬────────────┬────────────┬─────────────┐
// │ (index) │ Compiled │ Minified │ Compression │
// ├──────────────────────┼────────────┼────────────┼─────────────┤
// │ typebox/compiler │ '130.3 kb' │ ' 58.2 kb' │ '2.24 x' │
// │ typebox/errors │ '113.3 kb' │ ' 49.8 kb' │ '2.27 x' │
// │ typebox/system │ ' 78.8 kb' │ ' 32.2 kb' │ '2.45 x' │
// │ typebox/value │ '180.0 kb' │ ' 77.7 kb' │ '2.32 x' │
// │ typebox │ ' 77.7 kb' │ ' 31.7 kb' │ '2.45 x' │
// └──────────────────────┴────────────┴────────────┴─────────────┘

// ┌──────────────────────┬────────────┬────────────┬─────────────┐
// │ (index) │ Compiled │ Minified │ Compression │
Expand All @@ -35,3 +51,33 @@ import { Type, TypeGuard, Kind, Static, TSchema } from '@sinclair/typebox'
// │ typebox/value │ '181.7 kb' │ ' 79.2 kb' │ '2.29 x' │
// │ typebox │ ' 74.3 kb' │ ' 30.8 kb' │ '2.41 x' │
// └──────────────────────┴────────────┴────────────┴─────────────┘

// ┌──────────────────────┬────────────┬────────────┬─────────────┐
// │ (index) │ Compiled │ Minified │ Compression │
// ├──────────────────────┼────────────┼────────────┼─────────────┤
// │ typebox/compiler │ '129.4 kb' │ ' 58.7 kb' │ '2.20 x' │
// │ typebox/errors │ '111.1 kb' │ ' 49.8 kb' │ '2.23 x' │
// │ typebox/system │ ' 75.4 kb' │ ' 31.3 kb' │ '2.41 x' │
// │ typebox/value │ '175.6 kb' │ ' 77.9 kb' │ '2.25 x' │
// │ typebox │ ' 74.3 kb' │ ' 30.8 kb' │ '2.41 x' │
// └──────────────────────┴────────────┴────────────┴─────────────┘

// ┌──────────────────────┬────────────┬────────────┬─────────────┐
// │ (index) │ Compiled │ Minified │ Compression │
// ├──────────────────────┼────────────┼────────────┼─────────────┤
// │ typebox/compiler │ '129.4 kb' │ ' 58.7 kb' │ '2.20 x' │
// │ typebox/errors │ '111.1 kb' │ ' 49.8 kb' │ '2.23 x' │
// │ typebox/system │ ' 75.4 kb' │ ' 31.3 kb' │ '2.41 x' │
// │ typebox/value │ '175.5 kb' │ ' 77.7 kb' │ '2.26 x' │
// │ typebox │ ' 74.3 kb' │ ' 30.8 kb' │ '2.41 x' │
// └──────────────────────┴────────────┴────────────┴─────────────┘

// ┌──────────────────────┬────────────┬────────────┬─────────────┐
// │ (index) │ Compiled │ Minified │ Compression │
// ├──────────────────────┼────────────┼────────────┼─────────────┤
// │ typebox/compiler │ '130.3 kb' │ ' 59.1 kb' │ '2.20 x' │
// │ typebox/errors │ '112.0 kb' │ ' 50.2 kb' │ '2.23 x' │
// │ typebox/system │ ' 75.4 kb' │ ' 31.3 kb' │ '2.41 x' │
// │ typebox/value │ '175.2 kb' │ ' 77.0 kb' │ '2.28 x' │
// │ typebox │ ' 74.3 kb' │ ' 30.8 kb' │ '2.41 x' │
// └──────────────────────┴────────────┴────────────┴─────────────┘
11 changes: 11 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@
"./compiler": "./compiler/index.js",
"./errors": "./errors/index.js",
"./system": "./system/index.js",
"./value/cast": "./value/cast.js",
"./value/check": "./value/check.js",
"./value/clone": "./value/clone.js",
"./value/convert": "./value/convert.js",
"./value/create": "./value/create.js",
"./value/delta": "./value/delta.js",
"./value/equal": "./value/equal.js",
"./value/guard": "./value/guard.js",
"./value/hash": "./value/hash.js",
"./value/mutate": "./value/mutate.js",
"./value/pointer": "./value/pointer.js",
"./value": "./value/index.js",
".": "./typebox.js"
},
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ THE SOFTWARE.
import * as Types from '../typebox'
import { ValueErrors, ValueErrorIterator } from '../errors/index'
import { TypeSystem } from '../system/index'
import { ValueHash } from '../value/hash'
import * as ValueHash from '../value/hash'

// -------------------------------------------------------------------
// CheckFunction
Expand Down Expand Up @@ -554,7 +554,7 @@ export namespace TypeCompiler {
return checkFunc(value)
}
function valueHashFunction(value: unknown) {
return ValueHash.Create(value)
return ValueHash.Hash(value)
}
const checkFunction = compiledFunction(typeRegistryFunction, formatRegistryFunction, valueHashFunction)
return new TypeCheck(schema, references, checkFunction, code)
Expand Down
63 changes: 27 additions & 36 deletions src/errors/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/
import * as Types from '../typebox'
import * as ValueHash from '../value/hash'
import * as ValueGuard from '../value/guard'
import { TypeSystem } from '../system/index'
import { ValueHash } from '../value/hash'

// -------------------------------------------------------------------
// ValueErrorType
Expand Down Expand Up @@ -140,15 +141,6 @@ export namespace ValueErrors {
// ----------------------------------------------------------------------
// Guards
// ----------------------------------------------------------------------
function IsBigInt(value: unknown): value is bigint {
return typeof value === 'bigint'
}
function IsInteger(value: unknown): value is number {
return globalThis.Number.isInteger(value)
}
function IsString(value: unknown): value is string {
return typeof value === 'string'
}
function IsDefined<T>(value: unknown): value is T {
return value !== undefined
}
Expand All @@ -159,27 +151,26 @@ export namespace ValueErrors {
return TypeSystem.ExactOptionalPropertyTypes ? key in value : value[key] !== undefined
}
function IsObject(value: unknown): value is Record<keyof any, unknown> {
const result = typeof value === 'object' && value !== null
return TypeSystem.AllowArrayObjects ? result : result && !globalThis.Array.isArray(value)
const isObject = ValueGuard.IsObject(value)
return TypeSystem.AllowArrayObjects ? isObject : isObject && !ValueGuard.IsArray(value)
}
function IsRecordObject(value: unknown): value is Record<keyof any, unknown> {
return IsObject(value) && !(value instanceof globalThis.Date) && !(value instanceof globalThis.Uint8Array)
}
function IsNumber(value: unknown): value is number {
const result = typeof value === 'number'
return TypeSystem.AllowNaN ? result : result && globalThis.Number.isFinite(value)
const isNumber = ValueGuard.IsNumber(value)
return TypeSystem.AllowNaN ? isNumber : isNumber && globalThis.Number.isFinite(value)
}
function IsVoid(value: unknown): value is void {
const result = value === undefined
return TypeSystem.AllowVoidNull ? result || value === null : result
const isUndefined = ValueGuard.IsUndefined(value)
return TypeSystem.AllowVoidNull ? isUndefined || value === null : isUndefined
}

// ----------------------------------------------------------------------
// Types
// ----------------------------------------------------------------------
function* Any(schema: Types.TAny, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {}
function* Array(schema: Types.TArray, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!globalThis.Array.isArray(value)) {
if (!ValueGuard.IsArray(value)) {
return yield { type: ValueErrorType.Array, schema, path, value, message: `Expected array` }
}
if (IsDefined<number>(schema.minItems) && !(value.length >= schema.minItems)) {
Expand All @@ -193,32 +184,32 @@ export namespace ValueErrors {
yield* Visit(schema.items, references, `${path}/${i}`, value[i])
}
// prettier-ignore
if (schema.uniqueItems === true && !((function () { const set = new Set(); for (const element of value) { const hashed = ValueHash.Create(element); if (set.has(hashed)) { return false } else { set.add(hashed) } } return true })())) {
if (schema.uniqueItems === true && !((function () { const set = new Set(); for (const element of value) { const hashed = ValueHash.Hash(element); if (set.has(hashed)) { return false } else { set.add(hashed) } } return true })())) {
yield { type: ValueErrorType.ArrayUniqueItems, schema, path, value, message: `Expected array elements to be unique` }
}
// contains
if (!(IsDefined(schema.contains) || IsNumber(schema.minContains) || IsNumber(schema.maxContains))) {
return
}
const containsSchema = IsDefined<Types.TSchema>(schema.contains) ? schema.contains : Types.Type.Never()
const containsCount = value.reduce((acc, value, index) => (Visit(containsSchema, references, `${path}${index}`, value).next().done === true ? acc + 1 : acc), 0)
const containsCount = value.reduce((acc: number, value, index) => (Visit(containsSchema, references, `${path}${index}`, value).next().done === true ? acc + 1 : acc), 0)
if (containsCount === 0) {
yield { type: ValueErrorType.ArrayContains, schema, path, value, message: `Expected array to contain at least one matching type` }
}
if (IsNumber(schema.minContains) && containsCount < schema.minContains) {
if (ValueGuard.IsNumber(schema.minContains) && containsCount < schema.minContains) {
yield { type: ValueErrorType.ArrayMinContains, schema, path, value, message: `Expected array to contain at least ${schema.minContains} matching types` }
}
if (IsNumber(schema.maxContains) && containsCount > schema.maxContains) {
if (ValueGuard.IsNumber(schema.maxContains) && containsCount > schema.maxContains) {
yield { type: ValueErrorType.ArrayMaxContains, schema, path, value, message: `Expected array to contain no more than ${schema.maxContains} matching types` }
}
}
function* AsyncIterator(schema: Types.TAsyncIterator, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!(IsObject(value) && globalThis.Symbol.asyncIterator in value)) {
if (!ValueGuard.IsAsyncIterator(value)) {
yield { type: ValueErrorType.AsyncIterator, schema, path, value, message: `Expected value to be an async iterator` }
}
}
function* BigInt(schema: Types.TBigInt, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsBigInt(value)) {
if (!ValueGuard.IsBigInt(value)) {
return yield { type: ValueErrorType.BigInt, schema, path, value, message: `Expected bigint` }
}
if (IsDefined<bigint>(schema.multipleOf) && !(value % schema.multipleOf === globalThis.BigInt(0))) {
Expand All @@ -238,15 +229,15 @@ export namespace ValueErrors {
}
}
function* Boolean(schema: Types.TBoolean, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!(typeof value === 'boolean')) {
if (!ValueGuard.IsBoolean(value)) {
return yield { type: ValueErrorType.Boolean, schema, path, value, message: `Expected boolean` }
}
}
function* Constructor(schema: Types.TConstructor, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
yield* Visit(schema.returns, references, path, value.prototype)
}
function* Date(schema: Types.TDate, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!(value instanceof globalThis.Date)) {
if (!ValueGuard.IsDate(value)) {
return yield { type: ValueErrorType.Date, schema, path, value, message: `Expected Date object` }
}
if (!globalThis.isFinite(value.getTime())) {
Expand All @@ -266,12 +257,12 @@ export namespace ValueErrors {
}
}
function* Function(schema: Types.TFunction, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!(typeof value === 'function')) {
if (!ValueGuard.IsFunction(value)) {
return yield { type: ValueErrorType.Function, schema, path, value, message: `Expected function` }
}
}
function* Integer(schema: Types.TInteger, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsInteger(value)) {
if (!ValueGuard.IsInteger(value)) {
return yield { type: ValueErrorType.Integer, schema, path, value, message: `Expected integer` }
}
if (IsDefined<number>(schema.multipleOf) && !(value % schema.multipleOf === 0)) {
Expand Down Expand Up @@ -341,7 +332,7 @@ export namespace ValueErrors {
}
}
function* Null(schema: Types.TNull, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!(value === null)) {
if (!ValueGuard.IsNull(value)) {
return yield { type: ValueErrorType.Null, schema, path, value, message: `Expected null` }
}
}
Expand Down Expand Up @@ -410,7 +401,7 @@ export namespace ValueErrors {
}
}
function* Promise(schema: Types.TPromise, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!(typeof value === 'object' && typeof value.then === 'function')) {
if (!ValueGuard.IsPromise(value)) {
yield { type: ValueErrorType.Promise, schema, path, value, message: `Expected Promise` }
}
}
Expand Down Expand Up @@ -448,7 +439,7 @@ export namespace ValueErrors {
yield* Visit(target, references, path, value)
}
function* String(schema: Types.TString, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsString(value)) {
if (!ValueGuard.IsString(value)) {
return yield { type: ValueErrorType.String, schema, path, value, message: 'Expected string' }
}
if (IsDefined<number>(schema.minLength) && !(value.length >= schema.minLength)) {
Expand All @@ -457,13 +448,13 @@ export namespace ValueErrors {
if (IsDefined<number>(schema.maxLength) && !(value.length <= schema.maxLength)) {
yield { type: ValueErrorType.StringMaxLength, schema, path, value, message: `Expected string length less or equal to ${schema.maxLength}` }
}
if (schema.pattern !== undefined) {
if (ValueGuard.IsString(schema.pattern)) {
const regex = new RegExp(schema.pattern)
if (!regex.test(value)) {
yield { type: ValueErrorType.StringPattern, schema, path, value, message: `Expected string to match pattern ${schema.pattern}` }
}
}
if (schema.format !== undefined) {
if (ValueGuard.IsString(schema.format)) {
if (!Types.FormatRegistry.Has(schema.format)) {
yield { type: ValueErrorType.StringFormatUnknown, schema, path, value, message: `Unknown string format '${schema.format}'` }
} else {
Expand All @@ -475,12 +466,12 @@ export namespace ValueErrors {
}
}
function* Symbol(schema: Types.TSymbol, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!(typeof value === 'symbol')) {
if (!ValueGuard.IsSymbol(value)) {
return yield { type: ValueErrorType.Symbol, schema, path, value, message: 'Expected symbol' }
}
}
function* TemplateLiteral(schema: Types.TTemplateLiteral, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsString(value)) {
if (!ValueGuard.IsString(value)) {
return yield { type: ValueErrorType.String, schema, path, value, message: 'Expected string' }
}
const regex = new RegExp(schema.pattern)
Expand Down Expand Up @@ -531,7 +522,7 @@ export namespace ValueErrors {
}
}
function* Uint8Array(schema: Types.TUint8Array, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!(value instanceof globalThis.Uint8Array)) {
if (!ValueGuard.IsUint8Array(value)) {
return yield { type: ValueErrorType.Uint8Array, schema, path, value, message: `Expected Uint8Array` }
}
if (IsDefined<number>(schema.maxByteLength) && !(value.length <= schema.maxByteLength)) {
Expand Down
Loading

0 comments on commit ee72178

Please sign in to comment.