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
16 changes: 10 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@typescript-package/collection",
"version": "0.0.1",
"version": "0.1.0",
"author": "wwwdev.io <dev@wwwdev.io>",
"description": "A lightweight TypeScript library for data collection.",
"license": "MIT",
Expand All @@ -9,7 +9,7 @@
"registry": "https://registry.npmjs.org"
},
"peerDependencies": {
"@typedly/collection": "^1.1.0"
"@typedly/collection": "^2.0.0"
},
"scripts": {
"prepublishOnly": "npm run pkg && npm run clean",
Expand Down
66 changes: 25 additions & 41 deletions src/adapter/lib/set.adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,72 +4,56 @@ import { CollectionAdapter } from '@typedly/collection';
* @description The Set collection adapter.
* @export
* @class SetAdapter
* @template Element The type of the elements in the Set.
* @template [Type=Set<Element>] The type of the underlying Set collection.
* @implements {CollectionAdapter<Element, Type>}
* @template E The type of the elements in the Set.
* @template [T=Set<E>] The type of the underlying Set collection.
* @implements {CollectionAdapter<E, T>}
*/
export class SetAdapter<
Element,
Type = Set<Element>
> implements CollectionAdapter<Element, Type> {
E,
T extends Set<E> = Set<E>
> implements CollectionAdapter<E, T> {
public version: string = '1.0.0';

get [Symbol.toStringTag](): string {
return 'SetAdapter';
}

get [Symbol.iterator](): Iterator<Element> {
return (this.#collection as unknown as Set<Element>)[Symbol.iterator]();
[Symbol.iterator](): Iterator<E> {
return this.#collection[Symbol.iterator]();
}


protected get collection(): Type {
protected get collection(): T {
return this.#collection;
}

public get size(): number {
return (this.collection as unknown as Set<Element>).size;
return this.collection.size;
}

public get value(): Type {
return this.collection as unknown as Type;
public get value(): T {
return this.collection as unknown as T;
}

#collection: Type;

constructor(...collection: Element[]) {
this.#collection = new Set(collection) as Type;
#collection: T;
constructor(...collection: E[]) {
this.#collection = new Set(collection) as T;
}

public add(element: Element): this {
return (this.collection as unknown as Set<Element>).add(element), this;
public add(...element: E[]): this {
return element.forEach(e => this.collection.add(e)), this;
}

public clear(): this {
return (this.collection as unknown as Set<Element>).clear(), this;
return this.collection.clear(), this;
}

public destroy(): this {
return this.clear(), (this.#collection = null as any), this;
}

public delete(element: Element): boolean {
return (this.collection as unknown as Set<Element>).delete(element);
public delete(...element: E[]): boolean {
return element.every(e => this.collection.delete(e));
}

public forEach(callbackfn: (element: Element, element2: Element, collection: CollectionAdapter<Element, Type>) => void, thisArg?: any): this {
return (this.collection as unknown as Set<Element>).forEach((value, value2) => callbackfn.call(thisArg, value, value2, this as any)), this;
public forEach(callbackfn: (element: E, element2: E, collection: CollectionAdapter<E, T>) => void, thisArg?: any): this {
return this.collection.forEach((value, value2) => callbackfn.call(thisArg, value, value2, this as any)), this;
}

public has(element: Element): boolean {
return (this.collection as unknown as Set<Element>).has(element);
public has(...element: E[]): boolean {
return element.every(e => this.collection.has(e));
}

public lock(): this {
return Object.freeze(this.collection), this;
}

public set(value: Type): this {
public set(value: T): this {
return (this.#collection = value), this;
}
}
50 changes: 5 additions & 45 deletions src/core/lib/collection.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,7 @@ export abstract class CollectionBase<
E,
T,
A extends CollectionAdapter<E, T>
> extends CollectionCore<E, T> {

public get [Symbol.toStringTag](): string {
return 'Collection';
}

public get [Symbol.iterator](): Iterator<E> {
return (this.#adapter.value as unknown as any)[Symbol.iterator]();
}

> extends CollectionCore<E, T, A> {
/**
* @description The protected getter and setter for the adapter.
* @protected
Expand All @@ -35,51 +26,20 @@ export abstract class CollectionBase<
return this.#adapter;
}

public get size() {
return this.#adapter.size;
}

public get value() {
return this.#adapter.value;
}

#adapter: A;

constructor(
adapter: new (...args: any[]) => A,
adapter: new (...elements: E[]) => A,
...elements: E[]
) {
super();
this.#adapter = new adapter(...elements) as unknown as A;
}

public add(...element: E[]): this {
return element.forEach(e => this.#adapter.add(e)), this;
}
public clear(): this {
return this.#adapter.clear(), this;
}
public clone(): CollectionCore<E, T> {
return new (this.constructor as any)(this.#adapter.value, this.#adapter);
}
public destroy(): this {
return this.clear(),
public override destroy(): this {
return super.clear(),
super.destroy(),
this.#adapter = null as any,
this;
}
public delete(...element: E[]): boolean {
return element.every(e => this.#adapter.delete(e));
}
public forEach(callbackfn: (element: E, element2: E, collection: CollectionCore<E, T>) => void, thisArg?: any): this {
return this.#adapter.forEach(callbackfn as any, thisArg), this;
}
public has(element: E): boolean {
return this.#adapter.has(element);
}
public lock(): this {
return this.#adapter.lock?.(), this;
}
public set(value: T): this {
return this.#adapter.set(value), this;
}
}
67 changes: 50 additions & 17 deletions src/core/lib/collection.core.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,58 @@
// Interface.
import { CollectionShape } from '@typedly/collection';
import { CollectionAdapter, CollectionShape } from '@typedly/collection';
/**
* @description The core abstract class for `Type` collections of elements `Element` type.
* @export
* @abstract
* @class CollectionCore
* @template Element type in collection.
* @template Type of the collection.
* @implements {CollectionShape<Element, Type>}
* @template E type in collection.
* @template T of the collection.
Comment on lines +8 to +9
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template parameter descriptions are incomplete. Consider making them more consistent with other files (e.g., @template E The type of elements in collection. and @template T The type of the collection.)

Copilot uses AI. Check for mistakes.
* @template {CollectionAdapter<E, T>} A Adapter type.
* @implements {CollectionShape<E, T>}
*/
export abstract class CollectionCore<Element, Type> implements CollectionShape<Element, Type> {
abstract get [Symbol.toStringTag](): string;
abstract get [Symbol.iterator](): Iterator<Element>;
abstract value: Type;
abstract add(...element: Element[]): this;
abstract clear(): this;
abstract delete(...element: Element[]): boolean;
abstract destroy(): this;
abstract forEach(callbackfn: (element: Element, element2: Element, collection: CollectionShape<Element, Type>) => void, thisArg?: any): void;
abstract has(element: Element): boolean;
abstract lock(): this;
abstract set(value: Type): this;
abstract readonly size: number;
export abstract class CollectionCore<
E,
T,
A extends CollectionAdapter<E, T>
> implements CollectionShape<E, T> {
get [Symbol.toStringTag](): string {
return 'Collection';
}

[Symbol.iterator](): Iterator<E> {
return this.adapter[Symbol.iterator]();
}

protected abstract get adapter(): A
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semicolon at the end of the abstract getter declaration. TypeScript requires semicolons for abstract property declarations.

Suggested change
protected abstract get adapter(): A
protected abstract get adapter(): A;

Copilot uses AI. Check for mistakes.

public get size(): number {
return this.adapter.size;
}
public get value(): T {
return this.adapter.value;
}
public add(...element: E[]): this {
return this.adapter.add(...element), this;
}
public clear(): this {
return this.adapter.clear(), this;
}
public delete(...element: E[]): boolean {
return this.adapter.delete(...element);
}
public destroy(): this {
return this.adapter.destroy?.(), this;
}
public forEach(callbackfn: (element: E, element2: E, collection: CollectionShape<E, T>) => void, thisArg?: any): void {
return this.adapter.forEach(callbackfn as any, thisArg);
}
public has(...element: E[]): boolean {
return this.adapter.has(...element);
}
public lock(): this {
return this.adapter.lock?.(), this;
}
public set(value: T): this {
return this.adapter.set(value), this;
}
}
4 changes: 2 additions & 2 deletions src/lib/collection.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import { CollectionAdapter } from "@typedly/collection";
* @export
* @class Collection
* @template E The type of elements in the collection.
* @template {new (...args: any[]) => CollectionAdapter<E, any>} A The type of the adapter.
* @template {new (...elements: E[]) => CollectionAdapter<E, any>} A The type of the adapter.
* @extends {CollectionBase<E, any, InstanceType<A>>}
*/
export class Collection<
E,
A extends new (...args: any[]) => CollectionAdapter<E, any>
A extends new (...elements: E[]) => CollectionAdapter<E, any>
> extends CollectionBase<E, any, InstanceType<A>> {
constructor(adapter: A, ...elements: E[]) {
super(adapter as any, ...elements);
Expand Down
4 changes: 4 additions & 0 deletions src/test/collection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ collection.add(27, 29, 31, 33);
// Deletes.
collection.delete(29, 31);

for (const element of collection) {
console.log(`element: `, element);
}
Comment on lines +11 to +13
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The iterator functionality added in this PR should have proper test coverage. Consider adding a test case that verifies the iterator returns the expected elements, such as: test('iterator yields all elements', () => { const elements = [...collection]; expect(elements).toContain(1); ... });

Copilot uses AI. Check for mistakes.

console.log(`size: `, collection.size); // Output: 5

describe("Collection SetAdapter", () => {
Comment on lines +11 to 17
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Console.log statements in test files can pollute test output. Consider either removing these statements or moving them into a proper test case if you want to verify the iterator functionality.

Suggested change
for (const element of collection) {
console.log(`element: `, element);
}
console.log(`size: `, collection.size); // Output: 5
describe("Collection SetAdapter", () => {
// Iterator functionality test
describe("Collection SetAdapter", () => {
test("iterator yields expected elements", () => {
const elements = Array.from(collection);
expect(elements.sort()).toEqual([1, 2, 3, 27, 33].sort());
});

Copilot uses AI. Check for mistakes.
Expand Down