Skip to content
Merged
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
5 changes: 4 additions & 1 deletion changelog/1.4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
---

### Version Updates
- [Revision 1.4.6](https://github.com/sinclairzx81/typebox/pull/1739)
- [#1727](https://github.com/sinclairzx81/typebox/pull/1727) Ensure Typed Arrays are Guarded in Value.Diff
- [#1728](https://github.com/sinclairzx81/typebox/pull/1728) Ensure Json Pointer Key Fragments are Encoded in Value.Diff
- [Revision 1.4.5](https://github.com/sinclairzx81/typebox/pull/1736)
- Tail Call Optimization for Recursive Generic Types.
- StaticNoInfer to Prevent Reverse Inference on Generic Function Signatures.
Expand All @@ -15,7 +18,7 @@
- [Revision 1.4.2](https://github.com/sinclairzx81/typebox/pull/1719)
- Ensure Pick and Omit Retain Property Modifiers
- [Revision 1.4.1](https://github.com/sinclairzx81/typebox/pull/1717)
- Faster FNV1A-64 Hashing [#1713](https://github.com/sinclairzx81/typebox/pull/1713)
- [#1713](https://github.com/sinclairzx81/typebox/pull/1713) Faster FNV1A-64 Hashing

<a name="overview"></a>

Expand Down
39 changes: 0 additions & 39 deletions src/schema/engine/_pathing.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/schema/engine/additionalProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ THE SOFTWARE.
// deno-fmt-ignore-file

import * as Schema from '../types/index.ts'
import * as Pointer from '../pointer/index.ts'
import * as Stack from './_stack.ts'
import * as Unique from './_unique.ts'
import * as Externals from './_externals.ts'
import * as Pathing from './_pathing.ts'
import { BuildContext, CheckContext, ErrorContext } from './_context.ts'
import { UnicodeRegExp } from './_regexp.ts'
import { EmitGuard as E, Guard as G } from '../../guard/index.ts'
Expand Down Expand Up @@ -135,7 +135,7 @@ export function ErrorAdditionalProperties(stack: Stack.XStack, context: ErrorCon
const additionalProperties: string[] = []
const isAdditionalProperties = G.EveryAll(G.Keys(value), 0, (key, _index) => {
const nextSchemaPath = `${schemaPath}/additionalProperties`
const nextInstancePath = `${instancePath}/${Pathing.EncodeFragment(key)}`
const nextInstancePath = `${instancePath}/${Pointer.EncodeFragment(key)}`
const isAdditionalProperty = regexp.test(key) ||
(ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema.additionalProperties, value[key]) && context.AddKey(key))

Expand Down
4 changes: 2 additions & 2 deletions src/schema/engine/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ THE SOFTWARE.
// deno-fmt-ignore-file

import * as Schema from '../types/index.ts'
import * as Pointer from '../pointer/index.ts'
import * as Stack from './_stack.ts'
import * as Pathing from './_pathing.ts'
import { BuildContext, CheckContext, ErrorContext } from './_context.ts'
import { EmitGuard as E, Guard as G } from '../../guard/index.ts'
import { BuildSchema, CheckSchema, ErrorSchema } from './schema.ts'
Expand Down Expand Up @@ -70,7 +70,7 @@ export function CheckDependencies(stack: Stack.XStack, context: CheckContext, sc
export function ErrorDependencies(stack: Stack.XStack, context: ErrorContext, schemaPath: string, instancePath: string, schema: Schema.XDependencies, value: Record<PropertyKey, unknown>): boolean {
const isLength = G.IsEqual(G.Keys(value).length, 0)
const isEvery = G.EveryAll(G.Entries(schema.dependencies), 0, ([key, schema]) => {
const nextSchemaPath = `${schemaPath}/dependencies/${Pathing.EncodeFragment(key)}`
const nextSchemaPath = `${schemaPath}/dependencies/${Pointer.EncodeFragment(key)}`
return !G.HasPropertyKey(value, key) || (
G.IsArray(schema)
? schema.every((dependency) => G.HasPropertyKey(value, dependency) ||
Expand Down
4 changes: 2 additions & 2 deletions src/schema/engine/dependentSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ THE SOFTWARE.
// deno-fmt-ignore-file

import * as Schema from '../types/index.ts'
import * as Pointer from '../pointer/index.ts'
import * as Stack from './_stack.ts'
import * as Pathing from './_pathing.ts'
import { BuildContext, CheckContext, ErrorContext } from './_context.ts'
import { Guard as G, EmitGuard as E } from '../../guard/index.ts'
import { BuildSchema, CheckSchema, ErrorSchema } from './schema.ts'
Expand Down Expand Up @@ -64,7 +64,7 @@ export function CheckDependentSchemas(stack: Stack.XStack, context: CheckContext
export function ErrorDependentSchemas(stack: Stack.XStack, context: ErrorContext, schemaPath: string, instancePath: string, schema: Schema.XDependentSchemas, value: Record<PropertyKey, unknown>): boolean {
const isLength = G.IsEqual(G.Keys(value).length, 0)
const isEvery = G.EveryAll(G.Entries(schema.dependentSchemas), 0, ([key, schema]) => {
const nextSchemaPath = `${schemaPath}/dependentSchemas/${Pathing.EncodeFragment(key)}`
const nextSchemaPath = `${schemaPath}/dependentSchemas/${Pointer.EncodeFragment(key)}`
return !G.HasPropertyKey(value, key) ||
ErrorSchema(stack, context, nextSchemaPath, instancePath, schema, value)
})
Expand Down
4 changes: 2 additions & 2 deletions src/schema/engine/dynamicRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ THE SOFTWARE.
// deno-fmt-ignore-file

import * as Schema from '../types/index.ts'
import * as Stack from './_stack.ts'
import * as Resolve from '../resolve/index.ts'
import * as Functions from './_functions.ts'
import { Resolve } from '../resolve/index.ts'
import * as Stack from './_stack.ts'
import { BuildContext, CheckContext, ErrorContext } from './_context.ts'
import { CheckSchema, ErrorSchema } from './schema.ts'

Expand Down
6 changes: 3 additions & 3 deletions src/schema/engine/patternProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ THE SOFTWARE.
// deno-fmt-ignore-file

import * as Schema from '../types/index.ts'
import * as Pointer from '../pointer/index.ts'
import * as Stack from './_stack.ts'
import * as Unique from './_unique.ts'
import * as Externals from './_externals.ts'
import * as Pathing from './_pathing.ts'
import { UnicodeRegExp } from './_regexp.ts'
import { BuildContext, CheckContext, ErrorContext } from './_context.ts'
import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from './schema.ts'
Expand Down Expand Up @@ -68,10 +68,10 @@ export function CheckPatternProperties(stack: Stack.XStack, context: CheckContex
// ------------------------------------------------------------------
export function ErrorPatternProperties(stack: Stack.XStack, context: ErrorContext, schemaPath: string, instancePath: string, schema: Schema.XPatternProperties, value: Record<PropertyKey, unknown>): boolean {
return G.EveryAll(G.Entries(schema.patternProperties), 0, ([pattern, schema]) => {
const nextSchemaPath = `${schemaPath}/patternProperties/${Pathing.EncodeFragment(pattern)}`
const nextSchemaPath = `${schemaPath}/patternProperties/${Pointer.EncodeFragment(pattern)}`
const regexp = UnicodeRegExp(pattern)
return G.EveryAll(G.Entries(value), 0, ([key, value]) => {
const nextInstancePath = `${instancePath}/${Pathing.EncodeFragment(key)}`
const nextInstancePath = `${instancePath}/${Pointer.EncodeFragment(key)}`
const notKey = !regexp.test(key)
return notKey || ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema, value) && context.AddKey(key)
})
Expand Down
6 changes: 3 additions & 3 deletions src/schema/engine/properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ THE SOFTWARE.
// deno-fmt-ignore-file

import * as Schema from '../types/index.ts'
import * as Pointer from '../pointer/index.ts'
import * as Stack from './_stack.ts'
import * as Pathing from './_pathing.ts'
import { BuildContext, CheckContext, ErrorContext } from './_context.ts'
import { BuildSchemaPushStack, CheckSchemaPushStack, ErrorSchemaPushStack } from './schema.ts'
import { InexactOptionalCheck, InexactOptionalBuild, IsExactOptional } from './_exact_optional.ts'
Expand Down Expand Up @@ -97,8 +97,8 @@ export function CheckProperties(stack: Stack.XStack, context: CheckContext, sche
export function ErrorProperties(stack: Stack.XStack, context: ErrorContext, schemaPath: string, instancePath: string, schema: Schema.XProperties, value: Record<PropertyKey, unknown>): boolean {
const required = Schema.IsRequired(schema) ? schema.required : []
const isProperties = G.EveryAll(G.Entries(schema.properties), 0, ([key, schema]) => {
const nextSchemaPath = `${schemaPath}/properties/${Pathing.EncodeFragment(key)}`
const nextInstancePath = `${instancePath}/${Pathing.EncodeFragment(key)}`
const nextSchemaPath = `${schemaPath}/properties/${Pointer.EncodeFragment(key)}`
const nextInstancePath = `${instancePath}/${Pointer.EncodeFragment(key)}`
// Defer error generation for IsExactOptional
const isProperty = () => (
!G.HasPropertyKey(value, key) || (ErrorSchemaPushStack(stack, context, nextSchemaPath, nextInstancePath, schema, value[key]) && context.AddKey(key))
Expand Down
4 changes: 2 additions & 2 deletions src/schema/engine/propertyNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ THE SOFTWARE.
// deno-fmt-ignore-file

import * as Schema from '../types/index.ts'
import * as Pointer from '../pointer/index.ts'
import * as Stack from './_stack.ts'
import * as Pathing from './_pathing.ts'
import * as Unique from './_unique.ts'
import { BuildContext, CheckContext, ErrorContext } from './_context.ts'
import { BuildSchema, CheckSchema, ErrorSchema } from './schema.ts'
Expand All @@ -55,7 +55,7 @@ export function CheckPropertyNames(stack: Stack.XStack, context: CheckContext, s
export function ErrorPropertyNames(stack: Stack.XStack, context: ErrorContext, schemaPath: string, instancePath: string, schema: Schema.XPropertyNames, value: Record<PropertyKey, unknown>): boolean {
const propertyNames: string[] = []
const isPropertyNames = G.EveryAll(G.Keys(value), 0, (key, _index) => {
const nextInstancePath = `${instancePath}/${Pathing.EncodeFragment(key)}`
const nextInstancePath = `${instancePath}/${Pointer.EncodeFragment(key)}`
const nextSchemaPath = `${schemaPath}/propertyNames`
const isPropertyName = ErrorSchema(stack, context, nextSchemaPath, nextInstancePath, schema.propertyNames, key)
if (!isPropertyName) propertyNames.push(key)
Expand Down
2 changes: 1 addition & 1 deletion src/schema/engine/recursiveRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ THE SOFTWARE.
// deno-fmt-ignore-file

import * as Schema from '../types/index.ts'
import * as Resolve from '../resolve/index.ts'
import * as Stack from './_stack.ts'
import * as Functions from './_functions.ts'
import { Resolve } from '../resolve/index.ts'
import { BuildContext, CheckContext, ErrorContext } from './_context.ts'
import { CheckSchema, ErrorSchema } from './schema.ts'

Expand Down
4 changes: 2 additions & 2 deletions src/schema/engine/ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ THE SOFTWARE.

// deno-fmt-ignore-file

import * as Functions from './_functions.ts'
import * as Schema from '../types/index.ts'
import * as Resolve from '../resolve/index.ts'
import * as Functions from './_functions.ts'
import * as Stack from './_stack.ts'
import { Resolve } from '../resolve/index.ts'
import { BuildContext, CheckContext, ErrorContext } from './_context.ts'
import { EmitGuard as E } from '../../guard/index.ts'
import { CheckSchema, ErrorSchema } from './schema.ts'
Expand Down
3 changes: 1 addition & 2 deletions src/schema/intern/intern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ THE SOFTWARE.

import { Arguments } from '../../system/arguments/index.ts'
import { Hashing, Memory } from '../../system/index.ts'

import * as Schema from '../types/index.ts'
import * as Stack from '../engine/_stack.ts'
import * as Resolve from '../resolve/index.ts'
import { type XStatic } from '../static/index.ts'
import { Guard } from '../../guard/index.ts'
import { Resolve } from '../resolve/index.ts'

// ----------------------------------------------------------------
// (Internal) RefContext
Expand Down
2 changes: 1 addition & 1 deletion src/schema/pointer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

export * from './pointer_get.ts'
export * as Pointer from './pointer.ts'
export * from './pointer.ts'
57 changes: 36 additions & 21 deletions src/schema/pointer/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,35 @@ function ThrowCannotSetRoot(): never {
Throw('Cannot set value')
}
// ------------------------------------------------------------------
// Indices
// EncodeFragment
// ------------------------------------------------------------------
export function Indices(pointer: string): string[] {
const indices = pointer.split('/').map(index => index.replace(/~1/g, '/').replace(/~0/g, '~'))
return indices[0] === '' ? indices.slice(1) : indices
/** Encodes a JSON Pointer fragment */
export function EncodeFragment(fragment: string): string {
return fragment.replace(/~/g, '~0').replace(/\//g, '~1')
}
// ------------------------------------------------------------------
// DecodeFragment
// ------------------------------------------------------------------
/** Decodes a JSON Pointer fragment */
export function DecodeFragment(fragment: string): string {
return fragment.replace(/~1/g, '/').replace(/~0/g, '~')
}
// ------------------------------------------------------------------
// Fragments
// ------------------------------------------------------------------
/** Returns the decoded fragments of a JSON Pointer */
export function Fragments(pointer: string): string[] {
const fragments = pointer.split('/').map(DecodeFragment)
return fragments[0] === '' ? fragments.slice(1) : fragments
}
// ------------------------------------------------------------------
// Has
// ------------------------------------------------------------------
export function Has(value: unknown, pointer: string): boolean {
let current = value
for (const index of Indices(pointer)) {
if (!Guard.IsObject(current) || !Guard.HasPropertyKey(current, index)) return false
current = current[index]
for (const fragment of Fragments(pointer)) {
if (!Guard.IsObject(current) || !Guard.HasPropertyKey(current, fragment)) return false
current = current[fragment]
}
return true
}
Expand All @@ -65,20 +80,20 @@ export function Has(value: unknown, pointer: string): boolean {
// ------------------------------------------------------------------
export function Get(value: unknown, pointer: string): unknown {
let current = value
for (const index of Indices(pointer)) {
if (!Guard.IsObject(current) || Guard.IsUnsafePropertyKey(index)) return undefined
current = current[index]
for (const fragment of Fragments(pointer)) {
if (!Guard.IsObject(current) || Guard.IsUnsafePropertyKey(fragment)) return undefined
current = current[fragment]
}
return current
}
// ------------------------------------------------------------------
// Get
// Parent
// ------------------------------------------------------------------
function Parent(value: unknown, indices: string[], last: string): Record<string, unknown> {
function Parent(value: unknown, fragments: string[], last: string): Record<string, unknown> {
let current = value
for (const index of indices) {
if (Guard.IsUnsafePropertyKey(index)) ThrowUnsafePropertyKey()
current = Guard.IsObject(current) ? current[index] : undefined
for (const fragment of fragments) {
if (Guard.IsUnsafePropertyKey(fragment)) ThrowUnsafePropertyKey()
current = Guard.IsObject(current) ? current[fragment] : undefined
}
if (Guard.IsUnsafePropertyKey(last)) ThrowUnsafePropertyKey()
if (!Guard.IsObject(current)) ThrowCannotSetRoot()
Expand All @@ -88,20 +103,20 @@ function Parent(value: unknown, indices: string[], last: string): Record<string,
// Set
// ------------------------------------------------------------------
export function Set(value: unknown, pointer: string, next: unknown): unknown {
const indices = Indices(pointer)
const last = indices.pop()
const fragments = Fragments(pointer)
const last = fragments.pop()
if (Guard.IsUndefined(last)) ThrowCannotSetRoot()
Parent(value, indices, last)[last] = next
Parent(value, fragments, last)[last] = next
return value
}
// ------------------------------------------------------------------
// Delete
// ------------------------------------------------------------------
export function Delete(value: unknown, pointer: string): unknown {
const indices = Indices(pointer)
const last = indices.pop()
const fragments = Fragments(pointer)
const last = fragments.pop()
if (Guard.IsUndefined(last)) ThrowCannotSetRoot()
const parent = Parent(value, indices, last)
const parent = Parent(value, fragments, last)
if (Guard.IsArray(parent) && /^(0|[1-9]\d*)$/.test(last)) {
parent.splice(Number(last), 1)
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/schema/resolve/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ THE SOFTWARE.

---------------------------------------------------------------------------*/

export * as Resolve from './resolve.ts'
export * from './resolve.ts'
2 changes: 1 addition & 1 deletion src/schema/resolve/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { Guard } from '../../guard/index.ts'
import { Pointer } from '../pointer/index.ts'
import * as Pointer from '../pointer/index.ts'
import * as Schema from '../types/index.ts'
import * as Stack from '../engine/_stack.ts'

Expand Down
14 changes: 12 additions & 2 deletions src/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,24 @@ THE SOFTWARE.

---------------------------------------------------------------------------*/

// ------------------------------------------------------------------
// Namespaces
// ------------------------------------------------------------------
export * as Pointer from './pointer/index.ts'
export * as Resolve from './resolve/index.ts'

// ------------------------------------------------------------------
// Internals
// ------------------------------------------------------------------
export * from './engine/index.ts'
export * from './intern/index.ts'
export * from './meta/index.ts'
export * from './pointer/index.ts'
export * from './resolve/index.ts'
export * from './static/index.ts'
export * from './types/index.ts'

// ------------------------------------------------------------------
// Functions
// ------------------------------------------------------------------
export * from './build.ts'
export * from './compile.ts'
export * from './check.ts'
Expand Down
Loading
Loading