Skip to content

Commit

Permalink
Revision 0.32.0
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed Nov 29, 2023
1 parent 8594a85 commit 5399520
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 108 deletions.
4 changes: 3 additions & 1 deletion src/value/deref/deref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { TSchema, TRef, TThis } from '../../type/index'
import type { TSchema } from '../../type/schema/index'
import type { TRef } from '../../type/ref/index'
import type { TThis } from '../../type/recursive/index'

export class TypeDereferenceError extends Error {
constructor(public readonly schema: TRef | TThis) {
Expand Down
12 changes: 6 additions & 6 deletions src/value/equal/equal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { IsPlainObject, IsDate, IsArray, IsTypedArray, IsValueType } from '../guard/guard'
import type { ObjectType, ArrayType, TypedArrayType, ValueType } from '../guard/guard'
import { IsPlainObject, IsDate, IsArray, IsTypedArray, IsValueType } from '../guard/index'
import type { ObjectType, ArrayType, TypedArrayType, ValueType } from '../guard/index'

// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Equality Checks
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
function ObjectType(left: ObjectType, right: unknown): boolean {
if (!IsPlainObject(right)) return false
const leftKeys = [...Object.keys(left), ...Object.getOwnPropertySymbols(left)]
Expand All @@ -53,9 +53,9 @@ function TypedArrayType(left: TypedArrayType, right: unknown): any {
function ValueType(left: ValueType, right: unknown): any {
return left === right
}
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Equal
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
/** Returns true if the left value deep-equals the right */
export function Equal<T>(left: T, right: unknown): right is T {
if (IsPlainObject(left)) return ObjectType(left, right)
Expand Down
4 changes: 2 additions & 2 deletions src/value/guard/guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Types
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
export type ObjectType = Record<PropertyKey, unknown>
export type ArrayType = unknown[]
export type ValueType = null | undefined | symbol | bigint | number | boolean | string
Expand Down
26 changes: 13 additions & 13 deletions src/value/hash/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { IsArray, IsBoolean, IsBigInt, IsDate, IsNull, IsNumber, IsPlainObject, IsString, IsSymbol, IsUint8Array, IsUndefined } from '../guard/guard'
import { IsArray, IsBoolean, IsBigInt, IsDate, IsNull, IsNumber, IsPlainObject, IsString, IsSymbol, IsUint8Array, IsUndefined } from '../guard/index'

// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Errors
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
export class ValueHashError extends Error {
constructor(public readonly value: unknown) {
super(`Unable to hash value`)
}
}
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// ByteMarker
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
export enum ByteMarker {
Undefined,
Null,
Expand All @@ -52,27 +52,27 @@ export enum ByteMarker {
Symbol,
BigInt,
}
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// State
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
let Accumulator = BigInt('14695981039346656037')
const [Prime, Size] = [BigInt('1099511628211'), BigInt('2') ** BigInt('64')]
const Bytes = Array.from({ length: 256 }).map((_, i) => BigInt(i))
const F64 = new Float64Array(1)
const F64In = new DataView(F64.buffer)
const F64Out = new Uint8Array(F64.buffer)
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// NumberToBytes
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
function* NumberToBytes(value: number): IterableIterator<number> {
const byteCount = value === 0 ? 1 : Math.ceil(Math.floor(Math.log2(value) + 1) / 8)
for (let i = 0; i < byteCount; i++) {
yield (value >> (8 * (byteCount - 1 - i))) & 0xff
}
}
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Hashing Functions
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
function ArrayType(value: Array<unknown>) {
FNV1A64(ByteMarker.Array)
for (const item of value) {
Expand Down Expand Up @@ -150,9 +150,9 @@ function FNV1A64(byte: number) {
Accumulator = Accumulator ^ Bytes[byte]
Accumulator = (Accumulator * Prime) % Size
}
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Hash
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
/** Creates a FNV1A-64 non cryptographic hash of the given value */
export function Hash(value: unknown) {
Accumulator = BigInt('14695981039346656037')
Expand Down
6 changes: 3 additions & 3 deletions src/value/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

export { ValueError, ValueErrorType, ValueErrorIterator } from '../errors/index'
export { Edit, Insert, Update, Delete } from './delta/delta'
export { Mutable } from './mutate/mutate'
export { ValuePointer } from './pointer/pointer'
export { Edit, Insert, Update, Delete } from './delta/index'
export { Mutable } from './mutate/index'
export { ValuePointer } from './pointer/index'
export { Value } from './value'
24 changes: 12 additions & 12 deletions src/value/mutate/mutate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { IsPlainObject, IsArray, IsTypedArray, IsValueType, type TypedArrayType } from '../guard/guard'
import { ValuePointer } from '../pointer/pointer'
import { Clone } from '../clone/clone'
import { IsPlainObject, IsArray, IsTypedArray, IsValueType, type TypedArrayType } from '../guard/index'
import { ValuePointer } from '../pointer/index'
import { Clone } from '../clone/index'

// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Errors
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
export class ValueMutateTypeMismatchError extends Error {
constructor() {
super('Cannot assign due type mismatch of assignable values')
Expand All @@ -43,9 +43,9 @@ export class ValueMutateInvalidRootMutationError extends Error {
super('Only object and array types can be mutated at the root level')
}
}
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Mutators
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
export type Mutable = { [key: string]: unknown } | unknown[]
function ObjectType(root: Mutable, path: string, current: unknown, next: Record<string, unknown>) {
if (!IsPlainObject(current)) {
Expand Down Expand Up @@ -97,9 +97,9 @@ function Visit(root: Mutable, path: string, current: unknown, next: unknown) {
if (IsPlainObject(next)) return ObjectType(root, path, current, next)
if (IsValueType(next)) return ValueType(root, path, current, next)
}
// --------------------------------------------------------------------------
// Mutate
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// IsNonMutableValue
// ------------------------------------------------------------------
function IsNonMutableValue(value: unknown): value is Mutable {
return IsTypedArray(value) || IsValueType(value)
}
Expand All @@ -110,9 +110,9 @@ function IsMismatchedValue(current: unknown, next: unknown) {
(IsArray(current) && IsPlainObject(next))
)
}
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Mutate
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
/** Performs a deep mutable value assignment while retaining internal references */
export function Mutate(current: Mutable, next: Mutable): void {
if (IsNonMutableValue(current) || IsNonMutableValue(next)) throw new ValueMutateInvalidRootMutationError()
Expand Down
2 changes: 1 addition & 1 deletion src/value/pointer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

export * from './pointer'
export * as ValuePointer from './pointer'
144 changes: 74 additions & 70 deletions src/value/pointer/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// Errors
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
export class ValuePointerRootSetError extends Error {
constructor(public readonly value: unknown, public readonly path: string, public readonly update: unknown) {
super('Cannot set root value')
Expand All @@ -39,83 +39,87 @@ export class ValuePointerRootDeleteError extends Error {
super('Cannot delete root value')
}
}
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
// ValuePointer
// --------------------------------------------------------------------------
// ------------------------------------------------------------------
/** Provides functionality to update values through RFC6901 string pointers */
export namespace ValuePointer {
function Escape(component: string) {
return component.indexOf('~') === -1 ? component : component.replace(/~1/g, '/').replace(/~0/g, '~')
}
/** Formats the given pointer into navigable key components */
export function* Format(pointer: string): IterableIterator<string> {
if (pointer === '') return
let [start, end] = [0, 0]
for (let i = 0; i < pointer.length; i++) {
const char = pointer.charAt(i)
if (char === '/') {
if (i === 0) {
start = i + 1
} else {
end = i
yield Escape(pointer.slice(start, end))
start = i + 1
}
// prettier-ignore
function Escape(component: string) {
return component.indexOf('~') === -1 ? component : component.replace(/~1/g, '/').replace(/~0/g, '~')
}
/** Formats the given pointer into navigable key components */
// prettier-ignore
export function* Format(pointer: string): IterableIterator<string> {
if (pointer === '') return
let [start, end] = [0, 0]
for (let i = 0; i < pointer.length; i++) {
const char = pointer.charAt(i)
if (char === '/') {
if (i === 0) {
start = i + 1
} else {
end = i
yield Escape(pointer.slice(start, end))
start = i + 1
}
} else {
end = i
}
yield Escape(pointer.slice(start))
}
/** Sets the value at the given pointer. If the value at the pointer does not exist it is created */
export function Set(value: any, pointer: string, update: unknown): void {
if (pointer === '') throw new ValuePointerRootSetError(value, pointer, update)
let [owner, next, key] = [null as any, value, '']
for (const component of Format(pointer)) {
if (next[component] === undefined) next[component] = {}
owner = next
next = next[component]
key = component
}
owner[key] = update
yield Escape(pointer.slice(start))
}
/** Sets the value at the given pointer. If the value at the pointer does not exist it is created */
// prettier-ignore
export function Set(value: any, pointer: string, update: unknown): void {
if (pointer === '') throw new ValuePointerRootSetError(value, pointer, update)
let [owner, next, key] = [null as any, value, '']
for (const component of Format(pointer)) {
if (next[component] === undefined) next[component] = {}
owner = next
next = next[component]
key = component
}
/** Deletes a value at the given pointer */
export function Delete(value: any, pointer: string): void {
if (pointer === '') throw new ValuePointerRootDeleteError(value, pointer)
let [owner, next, key] = [null as any, value as any, '']
for (const component of Format(pointer)) {
if (next[component] === undefined || next[component] === null) return
owner = next
next = next[component]
key = component
}
if (Array.isArray(owner)) {
const index = parseInt(key)
owner.splice(index, 1)
} else {
delete owner[key]
}
owner[key] = update
}
/** Deletes a value at the given pointer */
// prettier-ignore
export function Delete(value: any, pointer: string): void {
if (pointer === '') throw new ValuePointerRootDeleteError(value, pointer)
let [owner, next, key] = [null as any, value as any, '']
for (const component of Format(pointer)) {
if (next[component] === undefined || next[component] === null) return
owner = next
next = next[component]
key = component
}
/** Returns true if a value exists at the given pointer */
export function Has(value: any, pointer: string): boolean {
if (pointer === '') return true
let [owner, next, key] = [null as any, value as any, '']
for (const component of Format(pointer)) {
if (next[component] === undefined) return false
owner = next
next = next[component]
key = component
}
return Object.getOwnPropertyNames(owner).includes(key)
if (Array.isArray(owner)) {
const index = parseInt(key)
owner.splice(index, 1)
} else {
delete owner[key]
}
/** Gets the value at the given pointer */
export function Get(value: any, pointer: string): any {
if (pointer === '') return value
let current = value
for (const component of Format(pointer)) {
if (current[component] === undefined) return undefined
current = current[component]
}
return current
}
/** Returns true if a value exists at the given pointer */
// prettier-ignore
export function Has(value: any, pointer: string): boolean {
if (pointer === '') return true
let [owner, next, key] = [null as any, value as any, '']
for (const component of Format(pointer)) {
if (next[component] === undefined) return false
owner = next
next = next[component]
key = component
}
return Object.getOwnPropertyNames(owner).includes(key)
}
/** Gets the value at the given pointer */
// prettier-ignore
export function Get(value: any, pointer: string): any {
if (pointer === '') return value
let current = value
for (const component of Format(pointer)) {
if (current[component] === undefined) return undefined
current = current[component]
}
return current
}

0 comments on commit 5399520

Please sign in to comment.