@slickgrid-universal/utils 4.1.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/cjs/domUtils.js +35 -8
  2. package/dist/cjs/domUtils.js.map +1 -1
  3. package/dist/cjs/index.js +1 -1
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/{types → models}/index.js +2 -2
  6. package/dist/cjs/models/index.js.map +1 -0
  7. package/dist/cjs/{types/htmlElementPosition.interface.js → models/interfaces.js} +1 -1
  8. package/dist/cjs/models/interfaces.js.map +1 -0
  9. package/dist/cjs/models/types.js +3 -0
  10. package/dist/cjs/models/types.js.map +1 -0
  11. package/dist/cjs/nodeExtend.js.map +1 -1
  12. package/dist/cjs/stripTagsUtil.js +6 -5
  13. package/dist/cjs/stripTagsUtil.js.map +1 -1
  14. package/dist/cjs/utils.js +52 -40
  15. package/dist/cjs/utils.js.map +1 -1
  16. package/dist/esm/domUtils.js +31 -6
  17. package/dist/esm/domUtils.js.map +1 -1
  18. package/dist/esm/index.js +1 -1
  19. package/dist/esm/index.js.map +1 -1
  20. package/dist/esm/models/index.js +3 -0
  21. package/dist/esm/models/index.js.map +1 -0
  22. package/dist/esm/models/interfaces.js +2 -0
  23. package/dist/esm/models/interfaces.js.map +1 -0
  24. package/dist/esm/models/types.js +2 -0
  25. package/dist/esm/models/types.js.map +1 -0
  26. package/dist/esm/nodeExtend.js.map +1 -1
  27. package/dist/esm/stripTagsUtil.js +6 -5
  28. package/dist/esm/stripTagsUtil.js.map +1 -1
  29. package/dist/esm/utils.js +49 -38
  30. package/dist/esm/utils.js.map +1 -1
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/dist/types/domUtils.d.ts +20 -3
  33. package/dist/types/domUtils.d.ts.map +1 -1
  34. package/dist/types/index.d.ts +1 -1
  35. package/dist/types/index.d.ts.map +1 -1
  36. package/dist/types/models/index.d.ts +3 -0
  37. package/dist/types/models/index.d.ts.map +1 -0
  38. package/dist/types/{types/htmlElementPosition.interface.d.ts → models/interfaces.d.ts} +1 -1
  39. package/dist/types/models/interfaces.d.ts.map +1 -0
  40. package/dist/types/{types/infer.type.d.ts → models/types.d.ts} +2 -1
  41. package/dist/types/models/types.d.ts.map +1 -0
  42. package/dist/types/stripTagsUtil.d.ts +6 -5
  43. package/dist/types/stripTagsUtil.d.ts.map +1 -1
  44. package/dist/types/utils.d.ts +14 -12
  45. package/dist/types/utils.d.ts.map +1 -1
  46. package/package.json +2 -2
  47. package/src/domUtils.ts +33 -7
  48. package/src/index.ts +1 -1
  49. package/src/models/index.ts +2 -0
  50. package/src/{types/infer.type.ts → models/types.ts} +2 -0
  51. package/src/nodeExtend.ts +1 -1
  52. package/src/stripTagsUtil.ts +6 -5
  53. package/src/utils.ts +60 -41
  54. package/dist/cjs/types/htmlElementPosition.interface.js.map +0 -1
  55. package/dist/cjs/types/index.js.map +0 -1
  56. package/dist/cjs/types/infer.type.js +0 -4
  57. package/dist/cjs/types/infer.type.js.map +0 -1
  58. package/dist/esm/types/htmlElementPosition.interface.js +0 -2
  59. package/dist/esm/types/htmlElementPosition.interface.js.map +0 -1
  60. package/dist/esm/types/index.js +0 -3
  61. package/dist/esm/types/index.js.map +0 -1
  62. package/dist/esm/types/infer.type.js +0 -3
  63. package/dist/esm/types/infer.type.js.map +0 -1
  64. package/dist/types/types/htmlElementPosition.interface.d.ts.map +0 -1
  65. package/dist/types/types/index.d.ts +0 -3
  66. package/dist/types/types/index.d.ts.map +0 -1
  67. package/dist/types/types/infer.type.d.ts.map +0 -1
  68. package/src/types/index.ts +0 -2
  69. /package/src/{types/htmlElementPosition.interface.ts → models/interfaces.ts} +0 -0
package/src/domUtils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { HtmlElementPosition, InferDOMType } from './types/index';
1
+ import type { HtmlElementPosition, InferDOMType } from './models/index';
2
2
 
3
3
  /** calculate available space for each side of the DOM element */
4
4
  export function calculateAvailableSpace(element: HTMLElement): { top: number; bottom: number; left: number; right: number; } {
@@ -63,21 +63,32 @@ export function createDomElement<T extends keyof HTMLElementTagNameMap, K extend
63
63
  return elm;
64
64
  }
65
65
 
66
+ /**
67
+ * Accepts string containing the class or space-separated list of classes, and
68
+ * returns list of individual classes.
69
+ * Method properly takes into account extra whitespaces in the `className`
70
+ * e.g.: " class1 class2 " => will result in `['class1', 'class2']`.
71
+ * @param {String} className - space separated list of class names
72
+ */
73
+ export function classNameToList(className = ''): string[] {
74
+ return className.split(' ').filter(cls => cls); // filter will remove whitespace entries
75
+ }
76
+
66
77
  /**
67
78
  * Loop through all properties of an object and nullify any properties that are instanceof HTMLElement,
68
79
  * if we detect an array then use recursion to go inside it and apply same logic
69
80
  * @param obj - object containing 1 or more properties with DOM Elements
70
81
  */
71
82
  export function destroyAllElementProps(obj: any) {
72
- if (obj) {
73
- for (const key of Object.keys(obj)) {
83
+ if (typeof obj === 'object') {
84
+ Object.keys(obj).forEach(key => {
74
85
  if (Array.isArray(obj[key])) {
75
86
  destroyAllElementProps(obj[key]);
76
87
  }
77
88
  if (obj[key] instanceof HTMLElement) {
78
89
  obj[key] = null;
79
90
  }
80
- }
91
+ });
81
92
  }
82
93
  }
83
94
 
@@ -93,14 +104,29 @@ export function emptyElement<T extends Element = Element>(element?: T | null): T
93
104
  }
94
105
 
95
106
  /**
96
- * From a DocumentFragment, get the innerHTML or outerHTML of all child elements.
107
+ * @deprecated @see `getHtmlStringOutput()`
108
+ * This function is now deprecated and is an alias to the new `getHtmlStringOutput()`, so please use this new function instead which works with various type of inputs.
109
+ */
110
+ export function getHTMLFromFragment(input: DocumentFragment | HTMLElement | string | number, type: 'innerHTML' | 'outerHTML' = 'innerHTML'): string {
111
+ return getHtmlStringOutput(input, type);
112
+ }
113
+
114
+ /**
115
+ * From any input provided, return the HTML string (when a string is provided, it will be returned "as is" but when it's a number it will be converted to string)
116
+ * When detecting HTMLElement/DocumentFragment, we can also specify which HTML type to retrieve innerHTML or outerHTML.
97
117
  * We can get the HTML by looping through all fragment `childNodes`
118
+ * @param {DocumentFragment | HTMLElement | string | number} input
119
+ * @param {'innerHTML' | 'outerHTML'} [type] - when the input is a DocumentFragment or HTMLElement, which type of HTML do you want to return? 'innerHTML' or 'outerHTML'
120
+ * @returns {String}
98
121
  */
99
- export function getHTMLFromFragment(input: DocumentFragment, type: 'innerHTML' | 'outerHTML' = 'innerHTML'): string {
122
+ export function getHtmlStringOutput(input: DocumentFragment | HTMLElement | string | number, type: 'innerHTML' | 'outerHTML' = 'innerHTML'): string {
100
123
  if (input instanceof DocumentFragment) {
124
+ // a DocumentFragment doesn't have innerHTML/outerHTML, but we can loop through all children and concatenate them all to an HTML string
101
125
  return [].map.call(input.childNodes, (x: HTMLElement) => x[type]).join('') || input.textContent || '';
126
+ } else if (input instanceof HTMLElement) {
127
+ return input[type];
102
128
  }
103
- return input;
129
+ return String(input ?? ''); // reaching this line means it's already a string (or number) so just return it as string
104
130
  }
105
131
 
106
132
  /** Get offset of HTML element relative to a parent element */
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from './domUtils';
2
2
  export * from './nodeExtend';
3
3
  export * from './stripTagsUtil';
4
- export * from './types';
4
+ export * from './models';
5
5
  export * from './utils';
@@ -0,0 +1,2 @@
1
+ export * from './interfaces';
2
+ export * from './types';
@@ -4,3 +4,5 @@ export type InferDOMType<T> =
4
4
  T extends CSSStyleDeclaration ? Partial<CSSStyleDeclaration> :
5
5
  T extends infer R ? R : any;
6
6
  /* eslint-enable @typescript-eslint/indent */
7
+
8
+ export type AnyFunction = (...args: any[]) => any;
package/src/nodeExtend.ts CHANGED
@@ -58,7 +58,7 @@ const setProperty = function setProperty(target: any, options: any) {
58
58
  };
59
59
 
60
60
  // Return undefined instead of __proto__ if '__proto__' is not an own property
61
- const getProperty = function getProperty(obj: any, name: any) {
61
+ const getProperty = function getProperty(obj: any, name: string) {
62
62
  if (name === '__proto__') {
63
63
  if (!hasOwn.call(obj, name)) {
64
64
  return void 0;
@@ -1,12 +1,13 @@
1
1
  /**
2
- * This stripTags function is a lib that already existed
3
- * but was not TypeScript and ESM friendly.
4
- * So I ported the code into the project and removed any old code like IE11 that we don't need for our project.
5
- * I also accept more input types without throwing, the code below accepts `string | number | boolean | HTMLElement` while original code only accepted string.
2
+ * This stripTags function is a lib that already existed on NPM
3
+ * but was not written as TypeScript and was not ESM friendly.
4
+ * So I ported the code into the project and removed any legacy browser code that we don't need for our project since we dropped IE browsers support.
5
+ * The function also accept more input types without throwing like the original one does,
6
+ * the code below accepts `string | number | boolean | HTMLElement` while original code only accepted string.
6
7
  *
7
8
  * The previous lib can be found here at this Github link:
8
9
  * https://github.com/ericnorris/striptags/
9
- * With an MIT licence that and can be found at
10
+ * With an MIT licence that and can be found at this link:
10
11
  * https://github.com/ericnorris/striptags/blob/main/LICENSE
11
12
  */
12
13
 
package/src/utils.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { AnyFunction } from './models/types';
2
+
1
3
  /**
2
4
  * Add an item to an array only when the item does not exists, when the item is an object we will be using their "id" to compare
3
5
  * @param inputArray
@@ -57,11 +59,11 @@ export function deepCopy(objectOrArray: any | any[]): any | any[] {
57
59
 
58
60
  // Loop through each item in the original
59
61
  // Recursively copy it's value and add to the clone
60
- for (const key in objectOrArray) {
62
+ Object.keys(objectOrArray).forEach(key => {
61
63
  if (Object.prototype.hasOwnProperty.call(objectOrArray, key)) {
62
64
  (clone as any)[key] = deepCopy(objectOrArray[key]);
63
65
  }
64
- }
66
+ });
65
67
  return clone;
66
68
  };
67
69
 
@@ -104,7 +106,7 @@ export function deepMerge(target: any, ...sources: any[]): any {
104
106
  target = (!isObject(target) && isObject(source)) ? {} : target;
105
107
 
106
108
  if (isObject(target) && isObject(source)) {
107
- for (const prop in source) {
109
+ Object.keys(source).forEach(prop => {
108
110
  if (source.hasOwnProperty(prop)) {
109
111
  if (prop in target) {
110
112
  // handling merging of two properties with equal names
@@ -128,53 +130,22 @@ export function deepMerge(target: any, ...sources: any[]): any {
128
130
  target[prop] = source[prop];
129
131
  }
130
132
  }
131
- }
133
+ });
132
134
  }
133
135
  return deepMerge(target, ...sources);
134
136
  }
135
137
 
136
- /**
137
- * This method is similar to `Object.assign` with the exception that it will also extend the object properties when filled.
138
- * There's also a distinction with extend vs merge, we are only extending when the property is not filled (if it is filled then it remains untouched and will not be merged)
139
- * It also applies the change directly on the target object which mutates the original object.
140
- * For example using these 2 objects: obj1 = { a: 1, b: { c: 2, d: 3 }} and obj2 = { b: { d: 2, e: 3}}:
141
- * - Object.assign(obj1, obj2) => { a: 1, b: { e: 4 }}
142
- * - objectAssignAndExtend(obj1, obj2) => { a: 1, b: { c: 2, d: 3, e: 4 }
143
- * @param {Object} target - the target object — what to apply the sources properties and mutate into
144
- * @param {Object} sources - the source object(s) — objects containing the properties you want to apply.
145
- * @returns {Object} The target object.
146
- */
147
- export function objectAssignAndExtend(target: any, ...sources: any): any {
148
- if (!sources.length || sources[0] === undefined) {
149
- return target;
150
- }
151
- const source = sources.shift();
152
-
153
- // when target is not an object but source is an object, then we'll assign as object
154
- target = (!isObject(target) && isObject(source)) ? {} : target;
155
-
156
- if (isObject(target) && isObject(source)) {
157
- for (const key of Object.keys(source)) {
158
- if (typeof source[key] === 'object' && source[key] !== null) {
159
- objectAssignAndExtend(target[key], source[key]);
160
- }
161
- if ((target[key] === null || target[key] === undefined) && source[key] !== null && source[key] !== undefined) {
162
- target[key] = source[key];
163
- }
164
- }
165
- }
166
- return objectAssignAndExtend(target, ...sources);
167
- }
168
-
169
138
  /**
170
139
  * Empty an object properties by looping through them all and deleting them
171
140
  * @param obj - input object
172
141
  */
173
142
  export function emptyObject(obj: any) {
174
- for (const key in obj) {
175
- if (obj.hasOwnProperty(key)) {
176
- delete obj[key];
177
- }
143
+ if (isObject(obj)) {
144
+ Object.keys(obj).forEach(key => {
145
+ if (obj.hasOwnProperty(key)) {
146
+ delete obj[key];
147
+ }
148
+ });
178
149
  }
179
150
  obj = null;
180
151
  obj = {};
@@ -182,6 +153,50 @@ export function emptyObject(obj: any) {
182
153
  return obj;
183
154
  }
184
155
 
156
+ /**
157
+ * Get the function details (param & body) of a function.
158
+ * It supports regular function and also ES6 arrow functions
159
+ * @param {Function} fn - function to analyze
160
+ * @param {Boolean} [addReturn] - when using ES6 function as single liner, we could add the missing `return ...`
161
+ * @returns
162
+ */
163
+ export function getFunctionDetails(fn: AnyFunction, addReturn = true) {
164
+ let isAsyncFn = false;
165
+
166
+ const getFunctionBody = (func: AnyFunction) => {
167
+ const fnStr = func.toString();
168
+ isAsyncFn = fnStr.includes('async ');
169
+
170
+ // when fn is one liner arrow fn returning an object in brackets e.g. `() => ({ hello: 'world' })`
171
+ if ((fnStr.replaceAll(' ', '').includes('=>({'))) {
172
+ const matches = fnStr.match(/(({.*}))/g) || [];
173
+ return matches.length >= 1 ? `return ${matches[0]!.trimStart()}` : fnStr;
174
+ }
175
+ const isOneLinerArrowFn = (!fnStr.includes('{') && fnStr.includes('=>'));
176
+ const body = fnStr.substring(
177
+ (fnStr.indexOf('{') + 1) || (fnStr.indexOf('=>') + 2),
178
+ fnStr.includes('}') ? fnStr.lastIndexOf('}') : fnStr.length
179
+ );
180
+ if (addReturn && isOneLinerArrowFn && !body.startsWith('return')) {
181
+ return 'return ' + body.trimStart(); // add the `return ...` to the body for ES6 arrow fn
182
+ }
183
+ return body;
184
+ };
185
+
186
+ const getFunctionParams = (func: AnyFunction): string[] => {
187
+ const STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg;
188
+ const ARG_NAMES = /([^\s,]+)/g;
189
+ const fnStr = func.toString().replace(STRIP_COMMENTS, '');
190
+ return fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARG_NAMES) ?? [];
191
+ };
192
+
193
+ return {
194
+ params: getFunctionParams(fn),
195
+ body: getFunctionBody(fn),
196
+ isAsync: isAsyncFn,
197
+ };
198
+ }
199
+
185
200
  /**
186
201
  * Check if an object is empty
187
202
  * @param obj - input object
@@ -198,6 +213,10 @@ export function isDefined<T>(value: T | undefined | null): value is T {
198
213
  return <T>value !== undefined && <T>value !== null && <T>value !== '';
199
214
  }
200
215
 
216
+ export function isDefinedNumber<T>(value: T | undefined | null): value is T {
217
+ return <T>value !== null && !isNaN(value as any) && <T>value !== '';
218
+ }
219
+
201
220
  /**
202
221
  * Simple object check.
203
222
  * @param item
@@ -1 +0,0 @@
1
- {"version":3,"file":"htmlElementPosition.interface.js","sourceRoot":"","sources":["../../../src/types/htmlElementPosition.interface.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kEAAgD;AAChD,+CAA6B"}
@@ -1,4 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- /* eslint-enable @typescript-eslint/indent */
4
- //# sourceMappingURL=infer.type.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"infer.type.js","sourceRoot":"","sources":["../../../src/types/infer.type.ts"],"names":[],"mappings":";;AAKA,6CAA6C"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=htmlElementPosition.interface.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"htmlElementPosition.interface.js","sourceRoot":"","sources":["../../../src/types/htmlElementPosition.interface.ts"],"names":[],"mappings":""}
@@ -1,3 +0,0 @@
1
- export * from './htmlElementPosition.interface';
2
- export * from './infer.type';
3
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,cAAc,CAAC"}
@@ -1,3 +0,0 @@
1
- export {};
2
- /* eslint-enable @typescript-eslint/indent */
3
- //# sourceMappingURL=infer.type.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"infer.type.js","sourceRoot":"","sources":["../../../src/types/infer.type.ts"],"names":[],"mappings":";AAKA,6CAA6C"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"htmlElementPosition.interface.d.ts","sourceRoot":"","sources":["../../../src/types/htmlElementPosition.interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf"}
@@ -1,3 +0,0 @@
1
- export * from './htmlElementPosition.interface';
2
- export * from './infer.type';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,cAAc,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"infer.type.d.ts","sourceRoot":"","sources":["../../../src/types/infer.type.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,CAAC,CAAC,IACxB,CAAC,SAAS,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,GAC5D,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './htmlElementPosition.interface';
2
- export * from './infer.type';