Skip to content

Commit

Permalink
feat: major API improvements accross all packages, performance improv…
Browse files Browse the repository at this point in the history
…ements for newer runtimes

Stream and AsyncStream have improved API. Reducer and AsyncReducer moved to the stream package and
have been improved. New immutable JS Array operations are used to improve performance. Documentation
updates.

BREAKING CHANGE: Many methods now take an options object instead of positional arguments for
readability
  • Loading branch information
Arvid Nicolaas committed Jan 23, 2024
1 parent 57f91ec commit 312e473
Show file tree
Hide file tree
Showing 287 changed files with 11,310 additions and 7,121 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ yarn-error.log
lerna-debug.log

**/.DS_Store

.nx
2 changes: 1 addition & 1 deletion config/tsconfig.common.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"module": "Node16",
"moduleResolution": "node16",
"verbatimModuleSyntax": true,
"lib": ["esnext"],
"lib": ["ES2023"],
"importHelpers": true,
"sourceMap": true,
"strict": true,
Expand Down
4 changes: 2 additions & 2 deletions deno_dist/actor/main/actor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { OptLazy, type Reducer } from '../../common/mod.ts';
import { OptLazy } from '../../common/mod.ts';
import type { Reducer } from '../../stream/mod.ts';

import type { ActionBase } from './internal.ts';

/**
*
*/
Expand Down
7 changes: 4 additions & 3 deletions deno_dist/actor/main/generate-uuid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ declare global {
/**
* Internal function to generate a UUID.
*/
export function generateUUID(): string {
const context = self;
export function generateUUID(
context: { crypto?: { randomUUID?: () => string } } = self
): string {
if (undefined !== context?.crypto?.randomUUID) {
return crypto.randomUUID();
return context.crypto.randomUUID();
}

// Public Domain/MIT
Expand Down
26 changes: 15 additions & 11 deletions deno_dist/actor/main/lookup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Reducer, type OptLazy } from '../../common/mod.ts';
import { OptLazy } from '../../common/mod.ts';
import { Reducer } from '../../stream/mod.ts';

import type { ActionBase } from './internal.ts';

Expand Down Expand Up @@ -49,18 +50,21 @@ export namespace Lookup {
): Reducer<ActionBase, S> {
const { actions, fallback } = lookup;

return Reducer.createOutput(initState, (state, action) => {
if (undefined !== actions && action.tag in actions) {
const lookupValue = actions[action.tag];
return Reducer.createOutput(
() => OptLazy(initState),
(state, action) => {
if (undefined !== actions && action.tag in actions) {
const lookupValue = actions[action.tag];

return applyLookupValue(state, action, lookupValue);
}
return applyLookupValue(state, action, lookupValue);
}

if (undefined !== fallback) {
return applyFallback(state, action, fallback);
}
if (undefined !== fallback) {
return applyFallback(state, action, fallback);
}

return state;
});
return state;
}
);
}
}
2 changes: 1 addition & 1 deletion deno_dist/actor/main/slice-config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OptLazy } from '../../common/mod.ts';
import { type OptLazy } from '../../common/mod.ts';

import { Lookup, type ActionBase, type Slice } from './internal.ts';

Expand Down
4 changes: 2 additions & 2 deletions deno_dist/actor/main/slice.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Reducer } from '../../common/mod.ts';
import { Reducer } from '../../stream/mod.ts';

import { Action, SliceConfig, type Actor } from './internal.ts';
import type { Tail } from './utils.ts';
Expand Down Expand Up @@ -83,7 +83,7 @@ export namespace Slice {
}

return {
reducer: Reducer.combineObj(reducers),
reducer: Reducer.combine(reducers) as any,
actions,
};
}
Expand Down
50 changes: 0 additions & 50 deletions deno_dist/actor/stream/index.ts

This file was deleted.

72 changes: 61 additions & 11 deletions deno_dist/base/arr.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { Update, TraverseState, type ArrayNonEmpty } from '../common/mod.ts';
import { TraverseState, Update, type ArrayNonEmpty } from '../common/mod.ts';

// Returns a copy of the array with the given value appended
export function append<T>(array: readonly T[], value: T): ArrayNonEmpty<T> {
if (`toSpliced` in (array as any)) {
return array.toSpliced(array.length, 0, value) as ArrayNonEmpty<T>;
}

const clone = array.slice();
clone.push(value);
return clone as ArrayNonEmpty<T>;
Expand All @@ -20,16 +24,27 @@ export function concat<T>(
// Returns an copy of the array between the start and end indices, with the elements in reversed order.
export function reverse<T>(
array: readonly T[],
start = 0,
end = array.length - 1
start?: number,
end?: number
): T[] {
const length = end - start + 1;
if ('toReversed' in (array as any)) {
const source =
undefined !== start || undefined !== end
? array.slice(start ?? 0, (end ?? array.length - 1) + 1)
: array;

return source.toReversed();
}

const _start = start ?? 0;
const _end = end ?? array.length - 1;
const length = _end - _start + 1;
const res = [] as T[];

let arrayIndex = start - 1;
let arrayIndex = _start - 1;
let resIndex = length - 1;

while (++arrayIndex <= end) res[resIndex--] = array[arrayIndex];
while (++arrayIndex <= _end) res[resIndex--] = array[arrayIndex];

return res;
}
Expand Down Expand Up @@ -67,6 +82,11 @@ export function map<T, R>(
f: (value: T, index: number) => R,
indexOffset = 0
): R[] {
if (indexOffset === 0) {
// without offset, can use standard array map
return array.map(f);
}

const result: R[] = [];

let index = indexOffset;
Expand Down Expand Up @@ -97,14 +117,17 @@ export function reverseMap<T, R>(

// Returns a copy of the given array with the given value added at the start
export function prepend<T>(array: readonly T[], value: T): ArrayNonEmpty<T> {
if (`toSpliced` in (array as any)) {
return array.toSpliced(0, 0, value) as ArrayNonEmpty<T>;
}
const clone = array.slice();
clone.unshift(value);
return clone as ArrayNonEmpty<T>;
}

// Returns the last element of the array
export function last<T>(arr: readonly T[]): T {
return arr[arr.length - 1];
return arr.at(-1)!;
}

// Returns a copy of the array where the element at given index is replaced by the given updater.
Expand All @@ -114,11 +137,20 @@ export function update<T>(
index: number,
updater: Update<T>
): readonly T[] {
if (index < 0 || index >= arr.length) return arr;
if (index < 0 || index >= arr.length) {
return arr;
}
const curValue = arr[index];

const newValue = Update(curValue, updater);
if (Object.is(newValue, curValue)) return arr;
if (Object.is(newValue, curValue)) {
return arr;
}

if (`with` in (arr as any)) {
return arr.with(index, newValue);
}

const newArr = arr.slice();
newArr[index] = newValue;
return newArr;
Expand All @@ -131,18 +163,32 @@ export function mod<T>(
index: number,
f: (value: T) => T
): readonly T[] {
if (index < 0 || index >= arr.length) return arr;
if (index < 0 || index >= arr.length) {
return arr;
}

const curValue = arr[index];
const newValue = f(curValue);
if (Object.is(newValue, curValue)) return arr;

if (Object.is(newValue, curValue)) {
return arr;
}

if (`with` in (arr as any)) {
return arr.with(index, newValue);
}

const newArr = arr.slice();
newArr[index] = newValue;
return newArr;
}

// Returns a copy of the array where at given index the given value is inserted
export function insert<T>(arr: readonly T[], index: number, value: T): T[] {
if (`toSpliced` in (arr as any)) {
return arr.toSpliced(index, 0, value);
}

const clone = arr.slice();
clone.splice(index, 0, value);
return clone;
Expand All @@ -165,6 +211,10 @@ export function splice<T>(
deleteCount: number,
...items: T[]
): T[] {
if (`toSpliced` in (arr as any)) {
return arr.toSpliced(start, deleteCount, ...items);
}

const clone = arr.slice();
clone.splice(start, deleteCount, ...items);
return clone;
Expand Down
14 changes: 8 additions & 6 deletions deno_dist/bimap/custom/implementation/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export class BiMapBuilder<K, V> implements BiMap.Builder<K, V> {
addEntries = (source: StreamSource<readonly [K, V]>): boolean => {
this.checkLock();

return Stream.from(source).filterPure(this.addEntry).count() > 0;
return Stream.from(source).filterPure({ pred: this.addEntry }).count() > 0;
};

removeKey = <UK, O>(key: RelatedTo<K, UK>, otherwise?: OptLazy<O>): V | O => {
Expand Down Expand Up @@ -162,7 +162,7 @@ export class BiMapBuilder<K, V> implements BiMap.Builder<K, V> {
return (
Stream.from(keys)
.mapPure(this.removeKey, notFound)
.countNotElement(notFound) > 0
.countElement(notFound, { negate: true }) > 0
);
};

Expand Down Expand Up @@ -200,19 +200,21 @@ export class BiMapBuilder<K, V> implements BiMap.Builder<K, V> {
return (
Stream.from(values)
.mapPure(this.removeValue, notFound)
.countNotElement(notFound) > 0
.countElement(notFound, { negate: true }) > 0
);
};

forEach = (
f: (entry: readonly [K, V], index: number, halt: () => void) => void,
state: TraverseState = TraverseState()
options: { state?: TraverseState } = {}
): void => {
const { state = TraverseState() } = options;

this._lock++;

if (!this.isEmpty && !state.halted) {
if (undefined !== this.source) this.source.forEach(f, state);
else this.keyValueMap.forEach(f, state);
if (undefined !== this.source) this.source.forEach(f, { state });
else this.keyValueMap.forEach(f, { state });
}

this._lock--;
Expand Down
3 changes: 1 addition & 2 deletions deno_dist/bimap/custom/implementation/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import type { BiMap } from '../../../bimap/mod.ts';

import type { RMap } from '../../../collection-types/map/index.ts';
import type { ArrayNonEmpty } from '../../../common/mod.ts';
import { Reducer } from '../../../common/mod.ts';
import type { StreamSource } from '../../../stream/mod.ts';
import { Reducer, type StreamSource } from '../../../stream/mod.ts';
import { isEmptyStreamSourceInstance } from '../../../stream/custom/index.ts';

export class BiMapContext<UK, UV, Tp extends BiMap.Types = BiMap.Types>
Expand Down
11 changes: 7 additions & 4 deletions deno_dist/bimap/custom/implementation/immutable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,18 +368,21 @@ export class BiMapNonEmptyImpl<K, V>

forEach(
f: (entry: readonly [K, V], index: number, halt: () => void) => void,
state: TraverseState = TraverseState()
options: { state?: TraverseState } = {}
): void {
const { state = TraverseState() } = options;

if (state.halted) return;
this.keyValueMap.forEach(f, state);
this.keyValueMap.forEach(f, { state });
}

filter(
pred: (entry: readonly [K, V], index: number, halt: () => void) => boolean
pred: (entry: readonly [K, V], index: number, halt: () => void) => boolean,
options: { negate?: boolean } = {}
): BiMap<K, V> {
const builder = this.context.builder();

builder.addEntries(this.stream().filter(pred));
builder.addEntries(this.stream().filter(pred, options));

if (builder.size === this.size) return this;

Expand Down
8 changes: 4 additions & 4 deletions deno_dist/bimap/custom/interface.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { BiMap } from '../../bimap/mod.ts';

import type { RMap } from '../../collection-types/mod.ts';
import type { ArrayNonEmpty, Reducer } from '../../common/mod.ts';
import type { StreamSource } from '../../stream/mod.ts';
import type { ArrayNonEmpty } from '../../common/mod.ts';
import type { Reducer, StreamSource } from '../../stream/mod.ts';

export interface BiMapFactory<UK = unknown, UV = unknown> {
/**
Expand Down Expand Up @@ -70,8 +70,8 @@ export interface BiMapCreators extends BiMapFactory {
* @typeparam UK - the upper key type for which the context can create instances
* @typeparam UV - the upper value type for which the context can create instances
* @param options - (optional) an object containing the following properties:<br/>
* - keyValueContext - (optional) the map context to use for key value mappings<br/>
* - valueKeyContext - (optional) the map context to use for value key mappings
* - keyValueContext: (optional) the map context to use for key value mappings<br/>
* - valueKeyContext: (optional) the map context to use for value key mappings
*/
createContext<UK, UV>(options?: {
keyValueContext?: RMap.Context<UK>;
Expand Down
Loading

0 comments on commit 312e473

Please sign in to comment.