From 3fcb98e8e04d3160cda85dc97f7980c5ce10c579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20=C5=9Eahin=20=C3=96z=C3=A7elik?= Date: Mon, 29 Oct 2018 00:47:04 +0300 Subject: [PATCH 1/2] sketches --- src/replace.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/replace.ts diff --git a/src/replace.ts b/src/replace.ts new file mode 100644 index 0000000..4e0b9fd --- /dev/null +++ b/src/replace.ts @@ -0,0 +1,15 @@ +import { start } from 'repl'; + +function _replace(array: T[], startingIndex: number, deleteCount: number, ...itemsToReplace: T[]): T[] { + const newArray = [...array]; + + newArray.splice(startingIndex, deleteCount, ...itemsToReplace); + + return newArray; +} + +export function replace(array: T[], itemToRemove: T, itemToReplace: T): T[]; +export function replace(array: T[], itemToRemove: T, deleteCount: number, ...itemsToReplace: T[]): T[]; +export function replace(array: T[], startingIndex: number, deleteCount: number, ...itemsToReplace: T[]): T[] { + const _startingIndex = arguments.length === 3 ? array.findIndex(start) +} From 63706ffa23eee34147f30b4c54c1f2707e964616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20=C5=9Eahin=20=C3=96z=C3=A7elik?= Date: Sun, 4 Nov 2018 19:49:09 +0300 Subject: [PATCH 2/2] array replace completed --- readme.md | 1 + src/as-proto/array-replace.spec.ts | 23 +++ src/as-proto/array-replace.ts | 79 ++++++++++ src/index.ts | 2 + src/replace.spec.ts | 44 ++++++ src/replace.ts | 223 ++++++++++++++++++++++++++++- tsconfig.json | 1 + 7 files changed, 367 insertions(+), 6 deletions(-) create mode 100644 src/as-proto/array-replace.spec.ts create mode 100644 src/as-proto/array-replace.ts create mode 100644 src/replace.spec.ts diff --git a/readme.md b/readme.md index 4946ee3..becd297 100644 --- a/readme.md +++ b/readme.md @@ -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) diff --git a/src/as-proto/array-replace.spec.ts b/src/as-proto/array-replace.spec.ts new file mode 100644 index 0000000..0ee6411 --- /dev/null +++ b/src/as-proto/array-replace.spec.ts @@ -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)); + }); +}); diff --git a/src/as-proto/array-replace.ts b/src/as-proto/array-replace.ts new file mode 100644 index 0000000..883f9c7 --- /dev/null +++ b/src/as-proto/array-replace.ts @@ -0,0 +1,79 @@ +import { replace, ReplaceItemsOptions, ReplaceByMapOptions } from "../replace"; + +declare global { + export interface Array { + /** + * #### 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[]; + + /** + * #### 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[]; + } +} + +Array.prototype.replace = function(options: T | ReplaceItemsOptions | ReplaceByMapOptions, itemToReplace: T): T[] { + return replace.call(null, this, ...arguments); +} diff --git a/src/index.ts b/src/index.ts index 6d54de4..8a35354 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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"; diff --git a/src/replace.spec.ts b/src/replace.spec.ts new file mode 100644 index 0000000..cf6c42f --- /dev/null +++ b/src/replace.spec.ts @@ -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]); + }); +}); diff --git a/src/replace.ts b/src/replace.ts index 4e0b9fd..822d6b5 100644 --- a/src/replace.ts +++ b/src/replace.ts @@ -1,15 +1,226 @@ -import { start } from 'repl'; +/** + * Replace Items Options Interface + * + * @template T typeof the items of the array + */ +export interface ReplaceItemsOptions { + /** + * 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 { + /** + * Items' Matcher Map to replace + */ + itemsToReplace: Map; + + /** + * 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> = { + deleteCount: 1, + itemsToReplace: [], + startingIndex: 0 +}; + +/** + * Default Options for Replace By Map Mode + */ +const REPLACE_BY_MAP_DEFAULT_OPTIONS: Required> = { + 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(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(array: T[], replaceOptions: ReplaceItemsOptions): 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(array: T[], replaceOptions: ReplaceByMapOptions): T[]; +export function replace( + array: T[], + options: T | ReplaceItemsOptions | ReplaceByMapOptions, + itemToReplace?: T +): T[] { + if (arguments.length > 2) { + options = >{ + startingIndex: array.indexOf(options), + itemsToReplace: [itemToReplace] + }; + } + + if (( | ReplaceItemsOptions>options).itemsToReplace instanceof Array) { + return _replaceItems(array, >options); + } else { + return _replaceByMap(array, >options); + } +} + +/** + * Replace items by 'replace items' mode + * + * @param array Array to replace items + * @param options Replace options + */ +function _replaceItems(array: T[], options: ReplaceItemsOptions): T[] { + const { startingIndex, deleteCount, itemsToReplace}: Required> = Object.assign({}, REPLACE_ITEMS_DEFAULT_OPTIONS, options); -function _replace(array: T[], startingIndex: number, deleteCount: number, ...itemsToReplace: T[]): T[] { 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; } -export function replace(array: T[], itemToRemove: T, itemToReplace: T): T[]; -export function replace(array: T[], itemToRemove: T, deleteCount: number, ...itemsToReplace: T[]): T[]; -export function replace(array: T[], startingIndex: number, deleteCount: number, ...itemsToReplace: T[]): T[] { - const _startingIndex = arguments.length === 3 ? array.findIndex(start) +/** + * Replace items by 'replace by map' mode + * + * @param array Array to replace items + * @param options Replace options + */ +function _replaceByMap(array: T[], options: ReplaceByMapOptions): T[] { + const { itemsToReplace, multi }: Required> = 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; } diff --git a/tsconfig.json b/tsconfig.json index a1e1c8f..bd826f7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,6 +12,7 @@ "allowSyntheticDefaultImports": true, "declaration": true, "noResolve": false, + "downlevelIteration": true, "lib": [ "dom", "es2015"