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
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Javascript utility functions for web development
* [min-max](https://gen-tech.github.io/js-utils/modules/_min_max_.html)
* [noop](https://gen-tech.github.io/js-utils/modules/_noop_.html)
* [promise-timeout](https://gen-tech.github.io/js-utils/modules/_promise_timeout_.html)
* [replace](https://gen-tech.github.io/js-utils/modules/_replace_.html)
* [revert-promise](https://gen-tech.github.io/js-utils/modules/_revert_promise_.html)
* [unique-id](https://gen-tech.github.io/js-utils/modules/_unique_id_.html)

Expand Down
23 changes: 23 additions & 0 deletions src/as-proto/array-replace.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { expect } from 'chai';
import 'mocha';

import "./array-replace";
import { replace } from "../replace";

describe('Array Replace Proto Function', () => {
it('should work as same', () => {
const foo = [1, 2, 3, 1, 2, 3];

expect(foo.replace(2, 100)).to.eql(replace(foo, 2, 100));
expect(foo.replace(4, 100)).to.eql(replace(foo, 4, 100));

const itemOptions = {startingIndex: 2, deleteCount: 2, itemsToReplace: [100, 101]};
expect(foo.replace(itemOptions)).to.eql(replace(foo, itemOptions));

const mapOptions = {itemsToReplace: new Map([[2, 100], [3, 101]])};
expect(foo.replace(mapOptions)).to.eql(replace(foo, mapOptions));

const mapOptionsMulti = {itemsToReplace: new Map([[2, 100], [3, 101]]), multi: true};
expect(foo.replace(mapOptionsMulti)).to.eql(replace(foo, mapOptionsMulti));
});
});
79 changes: 79 additions & 0 deletions src/as-proto/array-replace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { replace, ReplaceItemsOptions, ReplaceByMapOptions } from "../replace";

declare global {
export interface Array<T> {
/**
* #### Replace
*
* Replaces an item with passed one of an array
*
* * * *
* Example:
* ```typescript
* import "@gen-tech/js-utils/dist/as-proto/array-replace";
*
* const array = ["a", "b", "c", "a", "b", "c"];
*
* array.replace("b", "x"); // ["a", "x", "c", "a", "b", "c"]
* ```
* * * *
* @param array Array to replace its item
* @param itemToRemove Item to remove
* @param itemToReplace Item to replace with
* @return New replaced array
*/
replace(itemToRemove: T, itemToReplace: T): T[];

/**
* #### Replace
*
* Deletes items and replaces new ones from passed starting index of an array
*
* * * *
* Example:
* ```typescript
* import "@gen-tech/js-utils/dist/as-proto/array-replace";
*
* const array = ["a", "b", "c", "a", "b", "c"];
*
* array.replace({startingIndex: 3, deleteCount: 1, itemsToReplace: ['x', 'y']}); // ["a", "b", "c", "x", "y", "b", "c"];
* ```
* * * *
* @param array Array to replace its item
* @param replaceOptions Replace options
* @template T Typeof array items
* @return New replaced array
*/
replace(replaceOptions: ReplaceItemsOptions<T>): T[];

/**
* #### Replace
*
* Deletes items and replaces new ones by passed matcher map
*
* * * *
* Example:
* ```typescript
* import "@gen-tech/js-utils/dist/as-proto/array-replace";
*
* const array = ["a", "b", "c", "a", "b", "c"];
* const map = new Map();
* map.set("a", "x")
* map.set("b", "y");
*
* array.replace({itemsToReplace: map}); // ["x", "y", "c", "a", "b", "c"];
* array.replace({itemsToReplace: map, multi: true}); // ["x", "y", "c", "x", "y", "c"];
* ```
* * * *
* @param array Array to replace its item
* @param replaceOptions Replace options
* @template T Typeof array items
* @return New replaced array
*/
replace(replaceOptions: ReplaceByMapOptions<T>): T[];
}
}

Array.prototype.replace = <any>function<T>(options: T | ReplaceItemsOptions<T> | ReplaceByMapOptions<T>, itemToReplace: T): T[] {
return replace.call(null, this, ...arguments);
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ export * from "./min-max";
export * from "./noop";
export * from "./open-promise";
export * from "./promise-timeout";
export * from "./replace";
export { revertPromise } from "./revert-promise";
export * from "./unique-id";
44 changes: 44 additions & 0 deletions src/replace.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { expect } from 'chai';
import 'mocha';

import { replace } from "./replace";

describe('Replace Function', () => {
let foo: number[];

beforeEach(() => {
foo = [1, 2, 3, 1, 2, 3];
});

it('should replace one item successfully', () => {
expect(replace(foo, 2, 100)).to.eql([1, 100, 3, 1, 2, 3]);
});

it('shouldn\'t replace nonfound item', () => {
expect(replace(foo, 4, 100)).to.eql([1, 2, 3, 1, 2, 3]);
});

it('should replace items from index 0 when startingIndex is not defined', () => {
expect(replace(foo, {itemsToReplace: [100]})).to.eql([100, 2, 3, 1, 2, 3]);
});

it('should add items when itemsToReplace array contains multiple elements', () => {
expect(replace(foo, {itemsToReplace: [100, 101, 102]})).to.eql([100, 101, 102, 2, 3, 1, 2, 3]);
});

it('should delete items as defined', () => {
expect(replace(foo, {itemsToReplace: [100], deleteCount: 2})).to.eql([100, 3, 1, 2, 3]);
});

it('should start replacing from startingIndex', () => {
expect(replace(foo, { startingIndex: 2, itemsToReplace: [100]})).to.eql([1, 2, 100, 1, 2, 3]);
});

it('should replace by using mode: `replace by map`', () => {
expect(replace(foo, {itemsToReplace: new Map([[2, 100]])})).to.eql([1, 100, 3, 1, 2, 3]);
});

it('should replace multiple when multi set as true', () => {
expect(replace(foo, {itemsToReplace: new Map([[2, 100]]), multi: true})).to.eql([1, 100, 3, 1, 100, 3]);
});
});
226 changes: 226 additions & 0 deletions src/replace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
/**
* Replace Items Options Interface
*
* @template T typeof the items of the array
*/
export interface ReplaceItemsOptions<T> {
/**
* Starting index of the array for replacement operation
*
* @default 0
*/
startingIndex?: number;

/**
* Determines how many items will be deleted from the array
*
* @default 1
*/
deleteCount?: number;

/**
* Items to replace
*
* @default []
*/
itemsToReplace?: T[];
}

/**
* Replace by Item Matcher Map Options Interface
*
* @template T typeof the items of the array
*/
export interface ReplaceByMapOptions<T> {
/**
* Items' Matcher Map to replace
*/
itemsToReplace: Map<T, T>;

/**
* Set as `true` to replace all items in the array if matches with the key of the matcher map while iterating
*
* @default false
*/
multi?: boolean;
}

/**
* Default Options for Replace Items Mode
*/
const REPLACE_ITEMS_DEFAULT_OPTIONS: Required<ReplaceItemsOptions<any>> = {
deleteCount: 1,
itemsToReplace: [],
startingIndex: 0
};

/**
* Default Options for Replace By Map Mode
*/
const REPLACE_BY_MAP_DEFAULT_OPTIONS: Required<ReplaceByMapOptions<any>> = {
itemsToReplace: new Map(),
multi: false
};

/**
* #### Replace
*
* Replaces an item with passed one of an array
*
* * * *
* Example:
* ```typescript
* import { replace } from "@gen-tech/js-utils";
*
* const array = ["a", "b", "c", "a", "b", "c"];
*
* replace(array, "b", "x"); // ["a", "x", "c", "a", "b", "c"]
* ```
* Array Prototype Example:
* ```typescript
* import "@gen-tech/js-utils/dist/as-proto/array-replace";
*
* const array = ["a", "b", "c", "a", "b", "c"];
*
* array.replace("b", "x"); // ["a", "x", "c", "a", "b", "c"]
* ```
* * * *
* @param array Array to replace its item
* @param itemToRemove Item to remove
* @param itemToReplace Item to replace with
* @template T Typeof array items
* @return New replaced array
*/
export function replace<T>(array: T[], itemToRemove: T, itemToReplace: T): T[];
/**
* #### Replace
*
* Deletes items and replaces new ones from passed starting index of an array
*
* * * *
* Example:
* ```typescript
* import { replace } from "@gen-tech/js-utils";
*
* const array = ["a", "b", "c", "a", "b", "c"];
*
* replace(array, {startingIndex: 3, deleteCount: 1, itemsToReplace: ['x', 'y']}); // ["a", "b", "c", "x", "y", "b", "c"];
* ```
* Array Prototype Example:
* ```typescript
* import "@gen-tech/js-utils/dist/as-proto/array-replace";
*
* const array = ["a", "b", "c", "a", "b", "c"];
*
* array.replace({startingIndex: 3, deleteCount: 1, itemsToReplace: ['x', 'y']}); // ["a", "b", "c", "x", "y", "b", "c"];
* ```
* * * *
* @param array Array to replace its item
* @param replaceOptions Replace options
* @template T Typeof array items
* @return New replaced array
*/
export function replace<T>(array: T[], replaceOptions: ReplaceItemsOptions<T>): T[];
/**
* #### Replace
*
* Deletes items and replaces new ones by passed matcher map
*
* * * *
* Example:
* ```typescript
* import { replace } from "@gen-tech/js-utils";
*
* const array = ["a", "b", "c", "a", "b", "c"];
* const map = new Map();
* map.set("a", "x")
* map.set("b", "y");
*
* replace(array, {itemsToReplace: map}); // ["x", "y", "c", "a", "b", "c"];
* replace(array, {itemsToReplace: map, multi: true}); // ["x", "y", "c", "x", "y", "c"];
* ```
* Array Prototype Example:
* ```typescript
* import "@gen-tech/js-utils/dist/as-proto/array-replace";
*
* const array = ["a", "b", "c", "a", "b", "c"];
* const map = new Map();
* map.set("a", "x")
* map.set("b", "y");
*
* array.replace({itemsToReplace: map}); // ["x", "y", "c", "a", "b", "c"];
* array.replace({itemsToReplace: map, multi: true}); // ["x", "y", "c", "x", "y", "c"];
* ```
* * * *
* @param array Array to replace its item
* @param replaceOptions Replace options
* @template T Typeof array items
* @return New replaced array
*/
export function replace<T>(array: T[], replaceOptions: ReplaceByMapOptions<T>): T[];
export function replace<T>(
array: T[],
options: T | ReplaceItemsOptions<T> | ReplaceByMapOptions<T>,
itemToReplace?: T
): T[] {
if (arguments.length > 2) {
options = <ReplaceItemsOptions<T>>{
startingIndex: array.indexOf(<T>options),
itemsToReplace: [itemToReplace]
};
}

if ((<ReplaceByMapOptions<T> | ReplaceItemsOptions<T>>options).itemsToReplace instanceof Array) {
return _replaceItems(array, <ReplaceItemsOptions<T>>options);
} else {
return _replaceByMap(array, <ReplaceByMapOptions<T>>options);
}
}

/**
* Replace items by 'replace items' mode
*
* @param array Array to replace items
* @param options Replace options
*/
function _replaceItems<T>(array: T[], options: ReplaceItemsOptions<T>): T[] {
const { startingIndex, deleteCount, itemsToReplace}: Required<ReplaceItemsOptions<T>> = Object.assign({}, REPLACE_ITEMS_DEFAULT_OPTIONS, options);

const newArray = [...array];

// If item not found or index number is negative; do nothing
if (startingIndex < 0) {
return newArray;
}

newArray.splice(startingIndex, deleteCount, ...itemsToReplace);

return newArray;
}

/**
* Replace items by 'replace by map' mode
*
* @param array Array to replace items
* @param options Replace options
*/
function _replaceByMap<T>(array: T[], options: ReplaceByMapOptions<T>): T[] {
const { itemsToReplace, multi }: Required<ReplaceByMapOptions<T>> = Object.assign({}, REPLACE_BY_MAP_DEFAULT_OPTIONS, options);
const iterationMethod = multi ? Array.prototype.forEach : Array.prototype.some;

const newArray = [...array];

itemsToReplace.forEach((value, key) => {
iterationMethod.call(newArray, (item, index) => {
const matches = item === key;

if (matches) {
newArray.splice(index, 1, value);
}

return matches;
});
});

return newArray;
}
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"allowSyntheticDefaultImports": true,
"declaration": true,
"noResolve": false,
"downlevelIteration": true,
"lib": [
"dom",
"es2015"
Expand Down