diff --git a/packages/overlayscrollbars/src/environment/environment.ts b/packages/overlayscrollbars/src/environment/environment.ts index e956f7c..7161567 100644 --- a/packages/overlayscrollbars/src/environment/environment.ts +++ b/packages/overlayscrollbars/src/environment/environment.ts @@ -4,7 +4,7 @@ import { style, appendChildren, clientSize, - offset, + absoluteCoordinates, offsetSize, scrollLeft, jsAPI, @@ -45,10 +45,10 @@ const rtlScrollBehavior = (parentElm: HTMLElement, childElm: HTMLElement): { i: style(parentElm, { overflowX: strHidden, overflowY: strHidden }); scrollLeft(parentElm, 0); - const parentOffset = offset(parentElm); - const childOffset = offset(childElm); + const parentOffset = absoluteCoordinates(parentElm); + const childOffset = absoluteCoordinates(childElm); scrollLeft(parentElm, -999); // https://github.com/KingSora/OverlayScrollbars/issues/187 - const childOffsetAfterScroll = offset(childElm); + const childOffsetAfterScroll = absoluteCoordinates(childElm); return { /** * origin direction = determines if the zero scroll position is on the left or right side diff --git a/packages/overlayscrollbars/src/environment/index.ts b/packages/overlayscrollbars/src/environment/index.ts index c0f4de3..247d7e7 100644 --- a/packages/overlayscrollbars/src/environment/index.ts +++ b/packages/overlayscrollbars/src/environment/index.ts @@ -1 +1,4 @@ +import { Environment } from 'environment/environment'; + export * from 'environment/environment'; +export type OSEnvironment = Omit; diff --git a/packages/overlayscrollbars/src/support/compatibility/vendors.ts b/packages/overlayscrollbars/src/support/compatibility/vendors.ts index c7f3d6c..6ca3b02 100644 --- a/packages/overlayscrollbars/src/support/compatibility/vendors.ts +++ b/packages/overlayscrollbars/src/support/compatibility/vendors.ts @@ -81,7 +81,7 @@ export const cssPropertyValue = (property: string, values: string, suffix?: stri * Get the requested JS function, object or constructor with vendor prefix if it isn't supported without or undefined if unsupported. * @param name The name of the JS function, object or constructor. */ -export const jsAPI = (name: string): any => { +export const jsAPI = (name: string): T | undefined => { let result: any = jsCache[name] || window[name]; if (hasOwnProperty(jsCache, name)) { diff --git a/packages/overlayscrollbars/src/support/dom/create.ts b/packages/overlayscrollbars/src/support/dom/create.ts index d39c5fc..3a704ca 100644 --- a/packages/overlayscrollbars/src/support/dom/create.ts +++ b/packages/overlayscrollbars/src/support/dom/create.ts @@ -2,8 +2,15 @@ import { each } from 'support/utils/array'; import { contents } from 'support/dom/traversal'; import { removeElements } from 'support/dom/manipulation'; +/** + * Creates a div DOM node. + */ export const createDiv = (): HTMLDivElement => document.createElement('div'); +/** + * Creates DOM nodes modeled after the passed html string and returns the root dom nodes as a array. + * @param html The html string after which the DOM nodes shall be created. + */ export const createDOM = (html: string): ReadonlyArray => { const createdDiv = createDiv(); createdDiv.innerHTML = html.trim(); diff --git a/packages/overlayscrollbars/src/support/dom/dimensions.ts b/packages/overlayscrollbars/src/support/dom/dimensions.ts index da8f56d..a26fb1a 100644 --- a/packages/overlayscrollbars/src/support/dom/dimensions.ts +++ b/packages/overlayscrollbars/src/support/dom/dimensions.ts @@ -5,11 +5,18 @@ const zeroObj: WH = { h: 0, }; +/** + * Returns the window inner- width and height. + */ export const windowSize = (): WH => ({ w: window.innerWidth, h: window.innerHeight, }); +/** + * Returns the offset- width and height of the passed element. If the element is null the width and height values are 0. + * @param elm The element of which the offset- width and height shall be returned. + */ export const offsetSize = (elm: HTMLElement | null): WH => elm ? { @@ -18,6 +25,10 @@ export const offsetSize = (elm: HTMLElement | null): WH => } : zeroObj; +/** + * Returns the client- width and height of the passed element. If the element is null the width and height values are 0. + * @param elm The element of which the client- width and height shall be returned. + */ export const clientSize = (elm: HTMLElement | null): WH => elm ? { @@ -26,4 +37,8 @@ export const clientSize = (elm: HTMLElement | null): WH => } : zeroObj; +/** + * Returns the BoundingClientRect of the passed element. + * @param elm The element of which the BoundingClientRect shall be returned. + */ export const getBoundingClientRect = (elm: HTMLElement): DOMRect => elm.getBoundingClientRect(); diff --git a/packages/overlayscrollbars/src/support/dom/manipulation.ts b/packages/overlayscrollbars/src/support/dom/manipulation.ts index adc96c2..fc8831f 100644 --- a/packages/overlayscrollbars/src/support/dom/manipulation.ts +++ b/packages/overlayscrollbars/src/support/dom/manipulation.ts @@ -89,9 +89,9 @@ export const removeElements = (nodes: NodeCollection): void => { if (isArrayLike(nodes)) { each(from(nodes), (e) => removeElements(e)); } else if (nodes) { - const { parentNode } = nodes; - if (parentNode) { - parentNode.removeChild(nodes); + const parentElm = parent(nodes); + if (parentElm) { + parentElm.removeChild(nodes); } } }; diff --git a/packages/overlayscrollbars/src/support/dom/offset.ts b/packages/overlayscrollbars/src/support/dom/offset.ts index 16e54d9..854c49d 100644 --- a/packages/overlayscrollbars/src/support/dom/offset.ts +++ b/packages/overlayscrollbars/src/support/dom/offset.ts @@ -6,7 +6,11 @@ const zeroObj: XY = { y: 0, }; -export const offset = (elm: HTMLElement | null): XY => { +/** + * Returns the offset- left and top coordinates of the passed element relative to the document. If the element is null the top and left values are 0. + * @param elm The element of which the offset- top and left coordinates shall be returned. + */ +export const absoluteCoordinates = (elm: HTMLElement | null): XY => { const rect = elm ? getBoundingClientRect(elm) : 0; return rect ? { @@ -16,7 +20,11 @@ export const offset = (elm: HTMLElement | null): XY => { : zeroObj; }; -export const position = (elm: HTMLElement | null): XY => +/** + * Returns the offset- left and top coordinates of the passed element. If the element is null the top and left values are 0. + * @param elm The element of which the offset- top and left coordinates shall be returned. + */ +export const offsetCoordinates = (elm: HTMLElement | null): XY => elm ? { x: elm.offsetLeft, diff --git a/packages/overlayscrollbars/src/support/dom/style.ts b/packages/overlayscrollbars/src/support/dom/style.ts index cc00b06..9913163 100644 --- a/packages/overlayscrollbars/src/support/dom/style.ts +++ b/packages/overlayscrollbars/src/support/dom/style.ts @@ -31,6 +31,11 @@ const setCSSVal = (elm: HTMLElement | null, prop: string, val: string | number): } catch (e) {} }; +/** + * Gets or sets the passed styles to the passed element. + * @param elm The element to which the styles shall be applied to / be read from. + * @param styles The styles which shall be set or read. + */ export function style(elm: HTMLElement | null, styles: CssStyles): void; export function style(elm: HTMLElement | null, styles: string): string; export function style(elm: HTMLElement | null, styles: Array | string): { [key: string]: string }; @@ -54,10 +59,18 @@ export function style(elm: HTMLElement | null, styles: CssStyles | Array each(keys(styles), (key) => setCSSVal(elm, key, styles[key])); } +/** + * Hides the passed element (display: none). + * @param elm The element which shall be hidden. + */ export const hide = (elm: HTMLElement | null): void => { style(elm, { display: 'none' }); }; +/** + * Shows the passed element (display: block). + * @param elm The element which shall be shown. + */ export const show = (elm: HTMLElement | null): void => { style(elm, { display: 'block' }); }; diff --git a/packages/overlayscrollbars/src/support/dom/traversal.ts b/packages/overlayscrollbars/src/support/dom/traversal.ts index 41a601d..df61979 100644 --- a/packages/overlayscrollbars/src/support/dom/traversal.ts +++ b/packages/overlayscrollbars/src/support/dom/traversal.ts @@ -2,6 +2,11 @@ import { each, from } from 'support/utils/array'; const elementIsVisible = (elm: HTMLElement): boolean => !!(elm.offsetWidth || elm.offsetHeight || elm.getClientRects().length); +/** + * Find all elements with the passed selector, outgoing (and including) the passed element or the document if no element was provided. + * @param selector The selector which has to be searched by. + * @param elm The element from which the search shall be outgoing. + */ export const find = (selector: string, elm?: Element | null): ReadonlyArray => { const arr: Array = []; @@ -12,8 +17,18 @@ export const find = (selector: string, elm?: Element | null): ReadonlyArray (elm || document).querySelector(selector); +/** + * Determines whether the passed element is matching with the passed selector. + * @param elm The element which has to be compared with the passed selector. + * @param selector The selector which has to be compared with the passed element. Additional selectors: ':visible' and ':hidden'. + */ export const is = (elm: Element | null, selector: string): boolean => { if (elm) { if (selector === ':visible') { @@ -29,6 +44,11 @@ export const is = (elm: Element | null, selector: string): boolean => { return false; }; +/** + * Returns the children (no text-nodes or comments) of the passed element which are matching the passed selector. An empty array is returned if the passed element is null. + * @param elm The element of which the children shall be returned. + * @param selector The selector which must match with the children elements. + */ export const children = (elm: Element | null, selector?: string): ReadonlyArray => { const childs: Array = []; @@ -45,6 +65,14 @@ export const children = (elm: Element | null, selector?: string): ReadonlyArray< return childs; }; +/** + * Returns the childNodes (incl. text-nodes or comments etc.) of the passed element. An empty array is returned if the passed element is null. + * @param elm The element of which the childNodes shall be returned. + */ export const contents = (elm: Element | null): ReadonlyArray => (elm ? from(elm.childNodes) : []); +/** + * Returns the parent element of the passed element, or null if the passed element is null. + * @param elm The element of which the parent element shall be returned. + */ export const parent = (elm: Node | null): Node | null => (elm ? elm.parentElement : null); diff --git a/packages/overlayscrollbars/src/support/utils/array.ts b/packages/overlayscrollbars/src/support/utils/array.ts index 3b2248e..e07fe0e 100644 --- a/packages/overlayscrollbars/src/support/utils/array.ts +++ b/packages/overlayscrollbars/src/support/utils/array.ts @@ -51,6 +51,10 @@ export function each( */ export const indexOf = (arr: Array, item: T, fromIndex?: number): number => arr.indexOf(item, fromIndex); +/** + * Creates a shallow-copied Array instance from an array-like or iterable object. + * @param arr The object from which the array instance shall be created. + */ export const from = (arr: ArrayLike) => { if (Array.from) { return Array.from(arr); diff --git a/packages/overlayscrollbars/src/support/utils/object.ts b/packages/overlayscrollbars/src/support/utils/object.ts index 292f59d..46416bf 100644 --- a/packages/overlayscrollbars/src/support/utils/object.ts +++ b/packages/overlayscrollbars/src/support/utils/object.ts @@ -15,12 +15,12 @@ export const hasOwnProperty = (obj: any, prop: string | number | symbol): boolea export const keys = (obj: any): Array => (obj ? Object.keys(obj) : []); // https://github.com/jquery/jquery/blob/master/src/core.js#L116 -export function extend(target: T, object1: U): T & U; -export function extend(target: T, object1: U, object2: V): T & U & V; -export function extend(target: T, object1: U, object2: V, object3: W): T & U & V & W; -export function extend(target: T, object1: U, object2: V, object3: W, object4: X): T & U & V & W & X; -export function extend(target: T, object1: U, object2: V, object3: W, object4: X, object5: Y): T & U & V & W & X & Y; -export function extend( +export function assignDeep(target: T, object1: U): T & U; +export function assignDeep(target: T, object1: U, object2: V): T & U & V; +export function assignDeep(target: T, object1: U, object2: V, object3: W): T & U & V & W; +export function assignDeep(target: T, object1: U, object2: V, object3: W, object4: X): T & U & V & W & X; +export function assignDeep(target: T, object1: U, object2: V, object3: W, object4: X, object5: Y): T & U & V & W & X & Y; +export function assignDeep( target: T, object1?: U, object2?: V, @@ -62,10 +62,8 @@ export function extend( } // Never move original objects, clone them - target[key] = extend(clone, copy) as any; - - // Don't bring in undefined values - } else if (copy !== undefined) { + target[key] = assignDeep(clone, copy) as any; + } else { target[key] = copy; } }); diff --git a/packages/overlayscrollbars/tests/support/dom/offset.test.ts b/packages/overlayscrollbars/tests/support/dom/offset.test.ts index 78245a4..42c7f90 100644 --- a/packages/overlayscrollbars/tests/support/dom/offset.test.ts +++ b/packages/overlayscrollbars/tests/support/dom/offset.test.ts @@ -1,33 +1,33 @@ import { isNumber, isPlainObject } from 'support/utils/types'; -import { offset, position } from 'support/dom/offset'; +import { absoluteCoordinates, offsetCoordinates } from 'support/dom/offset'; describe('dom offset', () => { - describe('offset', () => { + describe('absoluteCoordinates', () => { test('DOM element', () => { - const result = offset(document.body); + const result = absoluteCoordinates(document.body); expect(isPlainObject(result)).toBe(true); expect(isNumber(result.x)).toBe(true); expect(isNumber(result.y)).toBe(true); }); test('null', () => { - const result = offset(null); + const result = absoluteCoordinates(null); expect(isPlainObject(result)).toBe(true); expect(result.x).toBe(0); expect(result.y).toBe(0); }); }); - describe('position', () => { + describe('offsetCoordinates', () => { test('DOM element', () => { - const result = position(document.body); + const result = offsetCoordinates(document.body); expect(isPlainObject(result)).toBe(true); expect(isNumber(result.x)).toBe(true); expect(isNumber(result.y)).toBe(true); }); test('null', () => { - const result = position(null); + const result = offsetCoordinates(null); expect(isPlainObject(result)).toBe(true); expect(result.x).toBe(0); expect(result.y).toBe(0); diff --git a/packages/overlayscrollbars/tests/support/options/validation.test.ts b/packages/overlayscrollbars/tests/support/options/validation.test.ts index 74e426d..b2087e6 100644 --- a/packages/overlayscrollbars/tests/support/options/validation.test.ts +++ b/packages/overlayscrollbars/tests/support/options/validation.test.ts @@ -1,5 +1,5 @@ import { validate, optionsTemplateTypes as oTypes, OptionsTemplate } from 'support/options'; -import { extend, isEmptyObject } from 'support/utils'; +import { assignDeep, isEmptyObject } from 'support/utils'; type TestOptionsObj = { propA: 'propA'; null: null }; type TestOptionsEnum = 'A' | 'B' | 'C'; @@ -55,7 +55,7 @@ describe('options validation', () => { foreignProp: 'foreign', foreignDeep: { a: 'A', b: 'B' }, }; - const modifiedOptions = extend({}, options, { nested: foreignObj }, foreignObj); + const modifiedOptions = assignDeep({}, options, { nested: foreignObj }, foreignObj); const result = validate(modifiedOptions, template); const { validated } = result; @@ -63,14 +63,14 @@ describe('options validation', () => { }); test('passed objects arent mutated', () => { - const clonedOptions = extend({}, options); + const clonedOptions = assignDeep({}, options); validate(clonedOptions, template, clonedOptions); expect(clonedOptions).toEqual(options); }); test('passed object isnt returned object', () => { - const clonedOptions = extend({}, options); + const clonedOptions = assignDeep({}, options); const result = validate(clonedOptions, template); expect(result.validated).not.toBe(clonedOptions); @@ -86,7 +86,7 @@ describe('options validation', () => { test('return signle non-object foreign property', () => { const foreignObj = { foreignProp: 'foreign' }; - const modifiedOptions = extend({}, options, foreignObj); + const modifiedOptions = assignDeep({}, options, foreignObj); const result = validate(modifiedOptions, template); const { foreign } = result; @@ -98,7 +98,7 @@ describe('options validation', () => { foreignProp: 'foreign', foreignDeep: { a: 'A', b: 'B' }, }; - const modifiedOptions = extend({}, options, foreignObj); + const modifiedOptions = assignDeep({}, options, foreignObj); const result = validate(modifiedOptions, template); const { foreign } = result; @@ -110,7 +110,7 @@ describe('options validation', () => { foreignProp: 'foreign', foreignDeep: { a: 'A', b: 'B' }, }; - const modifiedOptions = extend({}, options, { nested: foreignObj }, foreignObj); + const modifiedOptions = assignDeep({}, options, { nested: foreignObj }, foreignObj); const result = validate(modifiedOptions, template); const { foreign } = result; @@ -122,7 +122,7 @@ describe('options validation', () => { describe('diff property return', () => { test('one value changed', () => { - const modifiedOptions = extend({}, options, { str: 'newvaluetest' }); + const modifiedOptions = assignDeep({}, options, { str: 'newvaluetest' }); const result = validate(modifiedOptions, template, options); const { validated } = result; @@ -132,7 +132,7 @@ describe('options validation', () => { }); test('multiple values changed', () => { - const modifiedOptions = extend({}, options, { + const modifiedOptions = assignDeep({}, options, { str: 'newvaluetest', nullbool: null, }); @@ -147,7 +147,7 @@ describe('options validation', () => { }); test('one nested value changed', () => { - const modifiedOptions = extend({}, options, { nested: { num: -1293 } }); + const modifiedOptions = assignDeep({}, options, { nested: { num: -1293 } }); const result = validate(modifiedOptions, template, options); const { validated } = result; @@ -159,7 +159,7 @@ describe('options validation', () => { }); test('multiple nested values changed', () => { - const modifiedOptions = extend({}, options, { + const modifiedOptions = assignDeep({}, options, { nested: { num: -1293, abc: 'C' }, }); const result = validate(modifiedOptions, template, options); @@ -176,7 +176,7 @@ describe('options validation', () => { test('various values changed', () => { const newFunc = () => {}; - const modifiedOptions = extend({}, options, { + const modifiedOptions = assignDeep({}, options, { str: 'newstrvalue', func: newFunc, abc: 'C', @@ -206,7 +206,7 @@ describe('options validation', () => { foreignDeep: { a: 'A', b: 'B' }, }; const newFunc = () => {}; - const modifiedOptions = extend( + const modifiedOptions = assignDeep( {}, options, { @@ -239,7 +239,7 @@ describe('options validation', () => { describe('value validity', () => { test('single value doesnt match template', () => { - const modifiedOptions = extend({}, options, { str: 1 }); + const modifiedOptions = assignDeep({}, options, { str: 1 }); const result = validate(modifiedOptions, template); const { validated } = result; @@ -247,7 +247,7 @@ describe('options validation', () => { }); test('single enum value doesnt match template', () => { - const modifiedOptions = extend({}, options, { abc: 'testval' }); + const modifiedOptions = assignDeep({}, options, { abc: 'testval' }); const result = validate(modifiedOptions, template); const { validated } = result; @@ -255,7 +255,7 @@ describe('options validation', () => { }); test('multiple values dont match template', () => { - const modifiedOptions = extend({}, options, { + const modifiedOptions = assignDeep({}, options, { str: 1, abc: 'testval', nullbool: 'string', @@ -269,7 +269,7 @@ describe('options validation', () => { }); test('single nested value dont match template', () => { - const modifiedOptions = extend({}, options, { nested: { num: 'hi' } }); + const modifiedOptions = assignDeep({}, options, { nested: { num: 'hi' } }); const result = validate(modifiedOptions, template); const { validated } = result; @@ -277,7 +277,7 @@ describe('options validation', () => { }); test('single nested enum value dont match template', () => { - const modifiedOptions = extend({}, options, { + const modifiedOptions = assignDeep({}, options, { nested: { abc: 'testabc' }, }); const result = validate(modifiedOptions, template); @@ -287,7 +287,7 @@ describe('options validation', () => { }); test('multiple nested values dont match template', () => { - const modifiedOptions = extend({}, options, { + const modifiedOptions = assignDeep({}, options, { nested: { num: 'hi', abc: 'testabc' }, }); const result = validate(modifiedOptions, template); @@ -298,7 +298,7 @@ describe('options validation', () => { }); test('all nested values dont match template', () => { - const modifiedOptions = extend({}, options, { + const modifiedOptions = assignDeep({}, options, { nested: { num: 'hi', abc: 'testabc', switch: 1 }, }); const result = validate(modifiedOptions, template); @@ -308,7 +308,7 @@ describe('options validation', () => { }); test('all nested values dont match template with foreign property', () => { - const modifiedOptions = extend({}, options, { + const modifiedOptions = assignDeep({}, options, { nested: { foreign: 'foreign', num: 'hi', @@ -323,7 +323,7 @@ describe('options validation', () => { }); test('various values dont match template', () => { - const modifiedOptions = extend({}, options, { + const modifiedOptions = assignDeep({}, options, { nested: { switch: null }, obj: 1, abc: 'testest', @@ -343,7 +343,7 @@ describe('options validation', () => { foreignProp: 'foreign', foreignDeep: { a: 'A', b: 'B' }, }; - const modifiedOptions = extend( + const modifiedOptions = assignDeep( {}, options, { @@ -369,7 +369,7 @@ describe('options validation', () => { }); test('nested object is string', () => { - const modifiedOptions = extend({}, options, { nested: 'string' }); + const modifiedOptions = assignDeep({}, options, { nested: 'string' }); const result = validate(modifiedOptions, template); const { validated } = result; @@ -377,7 +377,7 @@ describe('options validation', () => { }); test('nested object is null', () => { - const modifiedOptions = extend({}, options, { nested: null }); + const modifiedOptions = assignDeep({}, options, { nested: null }); const result = validate(modifiedOptions, template); const { validated } = result; @@ -385,7 +385,7 @@ describe('options validation', () => { }); test('nested object is undefined', () => { - const modifiedOptions = extend({}, options); + const modifiedOptions = assignDeep({}, options); modifiedOptions.nested = undefined; const result = validate(modifiedOptions, template); const { validated } = result; @@ -409,7 +409,7 @@ describe('options validation', () => { const { warn } = console; console.warn = jest.fn(); - const modifiedOptions = extend({}, options, { str: 1 }); + const modifiedOptions = assignDeep({}, options, { str: 1 }); validate(modifiedOptions, template, {}, false); expect(console.warn).not.toBeCalled(); @@ -421,15 +421,15 @@ describe('options validation', () => { console.warn = jest.fn(); // str must be string - validate(extend({}, options, { str: 1 }), template, {}, true); + validate(assignDeep({}, options, { str: 1 }), template, {}, true); expect(console.warn).toBeCalledTimes(1); // abc must be A | B | C - validate(extend({}, options, { abc: 'some string' }), template, {}, true); + validate(assignDeep({}, options, { abc: 'some string' }), template, {}, true); expect(console.warn).toBeCalledTimes(2); // everthing OK - validate(extend({}, options, { abc: 'C' }), template, {}, true); + validate(assignDeep({}, options, { abc: 'C' }), template, {}, true); expect(console.warn).toBeCalledTimes(2); console.warn = warn; diff --git a/packages/overlayscrollbars/tests/support/utils/object.test.ts b/packages/overlayscrollbars/tests/support/utils/object.test.ts index e771c11..ab8ca83 100644 --- a/packages/overlayscrollbars/tests/support/utils/object.test.ts +++ b/packages/overlayscrollbars/tests/support/utils/object.test.ts @@ -1,9 +1,9 @@ -import { extend, keys, hasOwnProperty } from 'support/utils/object'; +import { assignDeep, keys, hasOwnProperty } from 'support/utils/object'; import { isPlainObject } from 'support/utils/types'; describe('object utilities', () => { // https://github.com/jquery/jquery/blob/master/test/unit/core.js#L965 - describe('extend', () => { + describe('assignDeep', () => { // type DeepPartial = T extends object ? { [K in keyof T]?: DeepPartial } : T type Deep = { foo?: { @@ -30,11 +30,11 @@ describe('object utilities', () => { const optionsCopy: Settings = { xnumber2: 1, xstring2: 'x', xxx: 'newstring' }; const merged: Settings = { xnumber1: 5, xnumber2: 1, xstring1: 'peter', xstring2: 'x', xxx: 'newstring' }; - extend(settings, options); + assignDeep(settings, options); expect(settings).toEqual(merged); expect(options).toEqual(optionsCopy); - extend(settings, null, options); + assignDeep(settings, null, options); expect(settings).toEqual(merged); expect(options).toEqual(optionsCopy); @@ -43,7 +43,7 @@ describe('object utilities', () => { const deep2copy: Deep = { foo: { baz: true }, foo2: document }; const deepmerged: Deep = { foo: { bar: true, baz: true }, foo2: document }; - extend(deep1, deep2); + assignDeep(deep1, deep2); expect(deep1.foo).toEqual(deepmerged.foo); expect(deep2.foo).toEqual(deep2copy.foo); expect(deep1.foo2).toBe(document); @@ -51,21 +51,21 @@ describe('object utilities', () => { const arr = [1, 2, 3]; const nestedArray: NestedArray = { arr }; - expect(extend({}, nestedArray).arr).not.toBe(arr); - expect(Array.isArray(extend({ arr: {} }, nestedArray).arr)).toBeTruthy(); - expect(Array.isArray(extend({ arr: {} }, nestedArray).arr)).toBeTruthy(); - expect(isPlainObject(extend({ arr }, { arr: {} }).arr)).toBeTruthy(); + expect(assignDeep({}, nestedArray).arr).not.toBe(arr); + expect(Array.isArray(assignDeep({ arr: {} }, nestedArray).arr)).toBeTruthy(); + expect(Array.isArray(assignDeep({ arr: {} }, nestedArray).arr)).toBeTruthy(); + expect(isPlainObject(assignDeep({ arr }, { arr: {} }).arr)).toBeTruthy(); let empty: { foo?: any } = {}; const optionsWithLength = { foo: { length: -1 } }; - extend(empty, optionsWithLength); + assignDeep(empty, optionsWithLength); expect(empty.foo).toEqual(optionsWithLength.foo); empty = {}; const optionsWithDate = { foo: { date: new Date() } }; - extend(empty, optionsWithDate); + assignDeep(empty, optionsWithDate); expect(empty.foo).toEqual(optionsWithDate.foo); /** @constructor */ @@ -75,53 +75,57 @@ describe('object utilities', () => { const optionsWithCustomObject = { foo: { date: customObject } }; empty = {}; - extend(empty, optionsWithCustomObject); + assignDeep(empty, optionsWithCustomObject); expect(empty.foo && empty.foo.date === customObject).toBeTruthy(); // Makes the class a little more realistic MyKlass.prototype = { someMethod() {} }; empty = {}; - extend(empty, optionsWithCustomObject); + assignDeep(empty, optionsWithCustomObject); expect(empty.foo && empty.foo.date === customObject).toBeTruthy(); const MyNumber = Number; - let ret: any = extend({ foo: 4 }, { foo: new MyNumber(5) }); + let ret: any = assignDeep({ foo: 4 }, { foo: new MyNumber(5) }); expect(parseInt(ret.foo?.toString() as string, 10) === 5).toBeTruthy(); - let nullUndef = extend({}, options, { xnumber2: null }); + let nullUndef = assignDeep({}, options, { xnumber2: null }); expect(nullUndef.xnumber2).toBe(null); // @ts-ignore - nullUndef = extend({}, options, { xnumber2: undefined }); + nullUndef = assignDeep({}, options, {}); expect(nullUndef.xnumber2).toBe(options.xnumber2); // @ts-ignore - nullUndef = extend({}, options, { xnumber0: null }); + nullUndef = assignDeep({}, options, { xnumber2: undefined }); + expect(nullUndef.xnumber2).toBe(undefined); + + // @ts-ignore + nullUndef = assignDeep({}, options, { xnumber0: null }); expect(nullUndef.xnumber0).toBe(null); const target = {}; const recursive = { foo: target, bar: 5 }; - extend(target, recursive); + assignDeep(target, recursive); expect(target).toEqual({ bar: 5 }); - ret = extend({ foo: [] }, { foo: [0] }); + ret = assignDeep({ foo: [] }, { foo: [0] }); expect(ret.foo?.length).toBe(1); - ret = extend({ foo: '1,2,3' }, { foo: [1, 2, 3] }); + ret = assignDeep({ foo: '1,2,3' }, { foo: [1, 2, 3] }); expect(typeof ret.foo !== 'string').toBeTruthy(); - ret = extend({ foo: 'bar' }, { foo: null }); + ret = assignDeep({ foo: 'bar' }, { foo: null }); expect(typeof ret.foo !== 'undefined').toBeTruthy(); const obj = { foo: null }; - extend(obj, { foo: 'notnull' }); + assignDeep(obj, { foo: 'notnull' }); expect(obj.foo).toBe('notnull'); const func: { (): void; key?: string } = () => {}; - extend(func, { key: 'value' }); + assignDeep(func, { key: 'value' }); expect(func.key).toBe('value'); const defaults = { xnumber1: 5, xnumber2: 7, xstring1: 'peter', xstring2: 'pan' }; @@ -132,15 +136,15 @@ describe('object utilities', () => { const options2Copy = { xstring2: 'xx', xxx: 'newstringx' }; const merged2 = { xnumber1: 5, xnumber2: 1, xstring1: 'peter', xstring2: 'xx', xxx: 'newstringx' }; - settings = extend({}, defaults, options1, options2); + settings = assignDeep({}, defaults, options1, options2); expect(settings).toEqual(merged2); expect(defaults).toEqual(defaultsCopy); expect(options1).toEqual(options1Copy); expect(options2).toEqual(options2Copy); - expect(extend('', { foo: 1 })).toEqual({ foo: 1 }); - expect(extend(null, { foo: null, deep: { foo: null } })).toEqual({ foo: null, deep: { foo: null } }); - expect(extend(12, { foo: 1, deep: { foo: null, text: '' } })).toEqual({ foo: 1, deep: { foo: null, text: '' } }); + expect(assignDeep('', { foo: 1 })).toEqual({ foo: 1 }); + expect(assignDeep(null, { foo: null, deep: { foo: null } })).toEqual({ foo: null, deep: { foo: null } }); + expect(assignDeep(12, { foo: 1, deep: { foo: null, text: '' } })).toEqual({ foo: 1, deep: { foo: null, text: '' } }); }); });