From ff798cb2dd578584dbe181f9fc15528aff7685b1 Mon Sep 17 00:00:00 2001 From: Smoren Date: Sun, 10 Mar 2024 20:08:04 +0300 Subject: [PATCH] Refactor, type fixes. --- src/functions.ts | 10 +++++----- src/selectors.ts | 22 +++++++++++----------- src/types.ts | 6 +++--- src/utils.ts | 4 ++++ src/views.ts | 34 +++++++++++++++++++++++----------- tests/views/array-view.test.ts | 14 ++++++++++++-- 6 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/functions.ts b/src/functions.ts index 62b759b..8e05298 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -10,7 +10,7 @@ import { ArrayViewInterface } from "./types"; * with a subset of elements from the original array or ArrayView. * * @template T - * @param {Array | ArrayView} source - The source array or ArrayView to create a view from. + * @param {Array | ArrayViewInterface} source - The source array or ArrayView to create a view from. * @param {boolean} [readonly] - Optional flag to indicate whether the view should be readonly. * @returns {ArrayView} The created ArrayView instance. * @@ -61,7 +61,7 @@ export function slice(slice: string | Array | Slice): SliceS * * This function allows you to create a selector that masks elements based on a boolean mask array. * - * @param {Array | ArrayView} mask - The boolean mask array or ArrayView to create the selector from. + * @param {Array | ArrayViewInterface} mask - The boolean mask array or ArrayView to create the selector from. * * @returns {MaskSelector} The created MaskSelector instance. * @@ -73,7 +73,7 @@ export function slice(slice: string | Array | Slice): SliceS * console.log(filteredView); * // [1, 3, 4] */ -export function mask(mask: Array | ArrayView): MaskSelector { +export function mask(mask: Array | ArrayViewInterface): MaskSelector { return new MaskSelector(mask); } @@ -82,7 +82,7 @@ export function mask(mask: Array | ArrayView): MaskSelector { * * This function allows you to create a selector for specifying a list of indexes to include in the selection. * - * @param {Array | ArrayView} indexes - The array of indexes or IndexList to create the selector from. + * @param {Array | ArrayViewInterface} indexes - The array of indexes or IndexList to create the selector from. * * @returns {IndexListSelector} The created IndexListSelector instance. * @@ -94,6 +94,6 @@ export function mask(mask: Array | ArrayView): MaskSelector { * console.log(filteredView); * // [1, 3, 5] */ -export function select(indexes: Array | ArrayView): IndexListSelector { +export function select(indexes: Array | ArrayViewInterface): IndexListSelector { return new IndexListSelector(indexes); } diff --git a/src/selectors.ts b/src/selectors.ts index e95c0c2..b03a40b 100644 --- a/src/selectors.ts +++ b/src/selectors.ts @@ -1,6 +1,6 @@ import { ArrayMaskView, ArrayIndexListView, ArraySliceView, ArrayView } from "./views"; import { Slice } from "./structs"; -import { ArraySelectorInterface } from "./types"; +import { ArraySelectorInterface, ArrayViewInterface } from "./types"; /** * Represents an index list selector that selects elements based on the provided array of indexes. @@ -16,9 +16,9 @@ export class IndexListSelector implements ArraySelectorInterface { /** * Creates a new IndexListSelector instance with the provided array of indexes. * - * @param {Array | ArrayView} value - The array of indexes or array view containing indexes. + * @param {Array | ArrayViewInterface} value - The array of indexes or array view containing indexes. */ - constructor(value: Array | ArrayView) { + constructor(value: Array | ArrayViewInterface) { this.value = value instanceof Array ? value : value.toArray(); } @@ -27,12 +27,12 @@ export class IndexListSelector implements ArraySelectorInterface { * * @template T - The type of elements in the source array view. * - * @param {ArrayView} source - The source array view to select elements from. + * @param {ArrayViewInterface} source - The source array view to select elements from. * @param {boolean} [readonly] - Whether the selection should be read-only. * * @returns {ArrayIndexListView} The view containing the selected elements. */ - public select(source: ArrayView, readonly?: boolean): ArrayIndexListView { + public select(source: ArrayViewInterface, readonly?: boolean): ArrayIndexListView { return new ArrayIndexListView(source, { indexes: this.value, readonly: readonly ?? source.readonly }); } } @@ -51,9 +51,9 @@ export class MaskSelector implements ArraySelectorInterface { /** * Creates a new MaskSelector instance with the provided array of boolean mask values. * - * @param {Array | ArrayView} value - The array or array view of boolean mask values. + * @param {Array | ArrayViewInterface} value - The array or array view of boolean mask values. */ - constructor(value: Array | ArrayView) { + constructor(value: Array | ArrayViewInterface) { this.value = value instanceof Array ? value : value.toArray(); } @@ -62,12 +62,12 @@ export class MaskSelector implements ArraySelectorInterface { * * @template T - The type of elements in the source array view. * - * @param {ArrayView} source - The source array to select elements from. + * @param {ArrayViewInterface} source - The source array to select elements from. * @param {boolean} [readonly] - Whether the selection should be read-only. * * @returns {ArrayMaskView} The view containing the selected elements. */ - public select(source: ArrayView, readonly?: boolean): ArrayMaskView { + public select(source: ArrayViewInterface, readonly?: boolean): ArrayMaskView { return new ArrayMaskView(source, { mask: this.value, readonly: readonly ?? source.readonly }); } } @@ -95,12 +95,12 @@ export class SliceSelector extends Slice implements ArraySelectorInterface { * * @template T - The type of elements in the source array. * - * @param {ArrayView} source - The source array to select elements from. + * @param {ArrayViewInterface} source - The source array to select elements from. * @param {boolean} [readonly] - Whether the selection should be read-only. * * @returns {ArraySliceView} The view containing the selected elements. */ - public select(source: ArrayView, readonly?: boolean): ArraySliceView { + public select(source: ArrayViewInterface, readonly?: boolean): ArraySliceView { return new ArraySliceView(source, { slice: this, readonly: readonly ?? source.readonly }); } } diff --git a/src/types.ts b/src/types.ts index f484678..1bb281c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -91,11 +91,11 @@ export interface ArrayViewInterface { /** * Sets new values for the elements in the view. * - * @param {Array | ArrayViewInterface} newValues - The new values to set. + * @param {Array | ArrayViewInterface | T} newValue - The new values to set. * * @returns {ArrayViewInterface} this view. */ - set(newValues: Array | ArrayViewInterface): ArrayViewInterface; + set(newValue: Array | ArrayViewInterface | T): ArrayViewInterface; /** * Returns an iterator for the elements in the view. @@ -128,5 +128,5 @@ export interface ArraySelectorInterface { * @template T - The type of elements in the array. */ export type SliceableArray = Array & { - [index: string]: Array + [index: string]: Array; } diff --git a/src/utils.ts b/src/utils.ts index 18a8809..10936c0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -17,3 +17,7 @@ export function normalizeIndex(index: number, containerLength: number, throwErro } return index < 0 ? containerLength + index : index; } + +export function isCountable(target: any): boolean { + return target.length !== undefined; +} diff --git a/src/views.ts b/src/views.ts index 8d0767c..014f782 100644 --- a/src/views.ts +++ b/src/views.ts @@ -1,5 +1,5 @@ import { MaskSelector, SliceSelector } from "./selectors"; -import { normalizeIndex } from "./utils"; +import { isCountable, normalizeIndex } from "./utils"; import { KeyError, LengthError, ReadonlyError } from "./excpetions"; import { NormalizedSlice, Slice } from "./structs"; import type { ArrayViewInterface, ArraySelectorInterface, SliceableArray } from "./types"; @@ -57,7 +57,7 @@ export class ArrayView implements ArrayViewInterface { /** * Constructs a new ArrayView instance based on the provided source array or ArrayView. * - * @param {Array | ArrayView} source - The source array or ArrayView to create a view from. + * @param {Array | ArrayViewInterface} source - The source array or ArrayView to create a view from. * @param {object} options - Options for configuring the view. * @param {boolean} [options.readonly=false] - Optional flag to indicate whether the view should be readonly. * @@ -70,7 +70,7 @@ export class ArrayView implements ArrayViewInterface { const loc = Array.isArray(source) ? source : source.loc; this.source = Array.isArray(source) ? source : source.source; this.parentView = Array.isArray(source) ? undefined : source; - this.readonly = readonly ?? ((source instanceof ArrayView) ? (source as ArrayView).readonly : false); + this.readonly = readonly ?? (Array.isArray(source) ? false : (source as ArrayViewInterface).readonly); if ((source instanceof ArrayView) && source.readonly && !this.readonly) { throw new ReadonlyError("Cannot create non-readonly view for readonly source."); @@ -156,7 +156,10 @@ export class ArrayView implements ArrayViewInterface { } /** @inheritDoc */ - public applyWith(data: Array | ArrayView, mapper: (lhs: T, rhs: U, index: number) => T): ArrayView { + public applyWith( + data: Array | ArrayViewInterface, + mapper: (lhs: T, rhs: U, index: number) => T, + ): ArrayView { if (data.length !== this.length) { throw new LengthError(`Length of values array not equal to view length (${data.length} != ${this.length}).`); } @@ -171,7 +174,16 @@ export class ArrayView implements ArrayViewInterface { } /** @inheritDoc */ - public set(newValues: Array | ArrayView): ArrayView { + public set(newValue: Array | ArrayViewInterface | T): ArrayView { + if (!isCountable(newValue)) { + for (let i = 0; i < this.length; ++i) { + this.loc[i] = newValue as T; + } + return this; + } + + const newValues = newValue as Array | ArrayViewInterface; + if (newValues.length !== this.length) { throw new LengthError(`Length of values array not equal to view length (${newValues.length} != ${this.length}).`); } @@ -236,7 +248,7 @@ export class ArrayIndexListView extends ArrayView { /** * Constructs a new ArrayIndexListView instance with the specified source array or ArrayView and indexes array. * - * @param {Array | ArrayView} source - The source array or ArrayView to create a view from. + * @param {Array | ArrayViewInterface} source - The source array or ArrayView to create a view from. * @param {object} options - Options for configuring the view. * @param {number[]} options.indexes - The indexes array specifying the indexes of elements in the source array. * @param {boolean} [options.readonly] - Optional flag to indicate whether the view should be readonly. @@ -244,7 +256,7 @@ export class ArrayIndexListView extends ArrayView { * @constructor */ constructor( - source: Array | ArrayView, + source: Array | ArrayViewInterface, { indexes, readonly, @@ -297,7 +309,7 @@ export class ArrayMaskView extends ArrayIndexListView { /** * Constructs a new ArrayMaskView instance with the specified source array or ArrayView and boolean mask. * - * @param {Array | ArrayView} source - The source array or ArrayView to create a view from. + * @param {Array | ArrayViewInterface} source - The source array or ArrayView to create a view from. * @param {object} options - Options for configuring the view. * @param {boolean[]} options.mask - The boolean mask for including or excluding elements from the source array. * @param {boolean} [options.readonly] - Optional flag to indicate whether the view should be readonly. @@ -305,7 +317,7 @@ export class ArrayMaskView extends ArrayIndexListView { * @constructor */ constructor( - source: Array | ArrayView, + source: Array | ArrayViewInterface, { mask, readonly, @@ -343,7 +355,7 @@ export class ArraySliceView extends ArrayView { /** * Constructs a new ArraySliceView instance with the specified source array or ArrayView and slice range. * - * @param {Array | ArrayView} source - The source array or ArrayView to create a view from. + * @param {Array | ArrayViewInterface} source - The source array or ArrayView to create a view from. * @param {object} options - Options for configuring the view. * @param {Slice} options.slice - The slice range specifying the subset of elements to include in the view. * @param {boolean} [options.readonly] - Optional flag to indicate whether the view should be readonly. @@ -351,7 +363,7 @@ export class ArraySliceView extends ArrayView { * @constructor */ constructor( - source: Array | ArrayView, + source: Array | ArrayViewInterface, { slice, readonly, diff --git a/tests/views/array-view.test.ts b/tests/views/array-view.test.ts index ac5634c..de1cf6e 100644 --- a/tests/views/array-view.test.ts +++ b/tests/views/array-view.test.ts @@ -316,7 +316,7 @@ describe.each([ ( source: Array, viewGetter: (source: Array) => ArrayView, - toWrite: Array, + toWrite: Array | number, expected: Array, ) => { it("", () => { @@ -339,7 +339,7 @@ describe.each([ ( source: Array, viewGetter: (source: Array) => ArrayView, - toWrite: Array, + toWrite: Array | number, expected: Array, ) => { it("", () => { @@ -347,6 +347,7 @@ describe.each([ const v = viewGetter(source); // When + // @ts-ignore v.loc[':'] = toWrite; // Then @@ -439,6 +440,15 @@ function dataProviderForCombineWrite(): Array { [11, 99], [11, 2, 3, 4, 5, 6, 7, 8, 99, 10], ], + [ + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + (source: Array) => view(source) + .subview(slice(new Slice(undefined, undefined, 2))) + .subview(slice('::2')) + .subview('::2'), + 111, + [111, 2, 3, 4, 5, 6, 7, 8, 111, 10], + ], ]; }