• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-webcomponents / 13265423658

11 Feb 2025 02:39PM UTC coverage: 98.224% (-0.04%) from 98.265%
13265423658

Pull #1352

github

web-flow
Merge 107e76eb5 into 44d06629e
Pull Request #1352: Refactor Tab component

3847 of 4049 branches covered (95.01%)

Branch coverage included in aggregate %.

420 of 433 new or added lines in 4 files covered. (97.0%)

2 existing lines in 1 file now uncovered.

24857 of 25174 relevant lines covered (98.74%)

468.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.6
/src/components/common/util.ts
1
export interface PartNameInfo {
59✔
2
  readonly [name: string]: string | boolean | number;
59✔
3
}
59✔
4

59✔
5
export const partNameMap = (partNameInfo: PartNameInfo) => {
59✔
6
  return Object.keys(partNameInfo)
47,966✔
7
    .filter((key) => partNameInfo[key])
47,966✔
8
    .join(' ');
47,966✔
9
};
47,966✔
10

59✔
11
export function noop() {}
59✔
12

59✔
13
export const asPercent = (part: number, whole: number) => (part / whole) * 100;
59✔
14

59✔
15
export const clamp = (number: number, min: number, max: number) =>
59✔
16
  Math.max(min, Math.min(number, max));
2,944✔
17

59✔
18
export function numberOfDecimals(number: number): number {
59✔
19
  const [_, decimals] = number.toString().split('.');
122✔
20
  return decimals ? decimals.length : 0;
122✔
21
}
122✔
22

59✔
23
export function roundPrecise(number: number, magnitude = 1): number {
59✔
24
  const factor = 10 ** magnitude;
122✔
25
  return Math.round(number * factor) / factor;
122✔
26
}
122✔
27

59✔
28
export function numberInRangeInclusive(
59✔
29
  value: number,
4✔
30
  min: number,
4✔
31
  max: number
4✔
32
) {
4✔
33
  return value >= min && value <= max;
4!
34
}
4✔
35

59✔
36
export function sameObject(a: object, b: object) {
59✔
37
  return JSON.stringify(a) === JSON.stringify(b);
621✔
38
}
621✔
39

59✔
40
export function createCounter() {
59✔
41
  let i = 0;
134✔
42
  return () => {
134✔
43
    i++;
2,214✔
44
    return i;
2,214✔
45
  };
2,214✔
46
}
134✔
47

59✔
48
/**
59✔
49
 * Returns whether an element has a Left-to-Right directionality.
59✔
50
 */
59✔
51
export function isLTR(element: HTMLElement) {
59✔
52
  return element.matches(':dir(ltr)');
2,954✔
53
}
2,954✔
54

59✔
55
/**
59✔
56
 * Builds a string from format specifiers and replacement parameters.
59✔
57
 * Will coerce non-string parameters to their string representations.
59✔
58
 *
59✔
59
 * @example
59✔
60
 * ```typescript
59✔
61
 * formatString('{0} says "{1}".', 'John', 'Hello'); // 'John says "Hello".'
59✔
62
 * formatString('{1} is greater than {0}', 0, 1); // '1 is greater than 0'
59✔
63
 * ```
59✔
64
 */
59✔
65
export function formatString(template: string, ...params: unknown[]): string {
59✔
66
  const length = params.length;
618✔
67

618✔
68
  return template.replace(/{(\d+)}/g, (match: string, index: number) =>
618✔
69
    index >= length ? match : `${params[index]}`
882✔
70
  );
618✔
71
}
618✔
72

59✔
73
/**
59✔
74
 * Parse the passed `value` as a number or return the `fallback` if it can't be done.
59✔
75
 *
59✔
76
 * @example
59✔
77
 * ```typescript
59✔
78
 * asNumber('5'); // 5
59✔
79
 * asNumber('3.14'); // 3.14
59✔
80
 * asNumber('five'); // 0
59✔
81
 * asNUmber('five', 5); // 5
59✔
82
 * ```
59✔
83
 */
59✔
84
export function asNumber(value: unknown, fallback = 0) {
59✔
85
  const parsed = Number.parseFloat(value as string);
615✔
86
  return Number.isNaN(parsed) ? fallback : parsed;
615✔
87
}
615✔
88

59✔
89
/**
59✔
90
 * Returns the value wrapped between the min and max bounds.
59✔
91
 *
59✔
92
 * If the value is greater than max, returns the min and vice-versa.
59✔
93
 * If the value is between the bounds, it is returned unchanged.
59✔
94
 *
59✔
95
 * @example
59✔
96
 * ```typescript
59✔
97
 * wrap(1, 4, 2); // 2
59✔
98
 * wrap(1, 4, 5); // 1
59✔
99
 * wrap(1, 4, -1); // 4
59✔
100
 * ```
59✔
101
 */
59✔
102
export function wrap(min: number, max: number, value: number) {
59✔
103
  if (value < min) {
37✔
104
    return max;
11✔
105
  }
11✔
106
  if (value > max) {
37✔
107
    return min;
3✔
108
  }
3✔
109

23✔
110
  return value;
23✔
111
}
23✔
112

59✔
113
export function isDefined<T = unknown>(value: T) {
59✔
114
  return value !== undefined;
2,183✔
115
}
2,183✔
116

59✔
117
export function* iterNodes<T = Node>(
59✔
118
  root: Node,
850✔
119
  whatToShow?: keyof typeof NodeFilter,
850✔
120
  filter?: (node: T) => boolean
850✔
121
): Generator<T> {
850✔
122
  if (!isDefined(globalThis.document)) {
850!
123
    return;
×
124
  }
×
125

850✔
126
  const iter = globalThis.document.createTreeWalker(
850✔
127
    root,
850✔
128
    NodeFilter[whatToShow ?? 'SHOW_ALL']
850!
129
  );
850✔
130

850✔
131
  let node = iter.nextNode() as T;
850✔
132

850✔
133
  while (node) {
850✔
134
    if (filter) {
8,059✔
135
      if (filter(node)) {
8,059✔
136
        yield node;
3,582✔
137
      }
3,582✔
138
    } else {
8,059!
139
      yield node;
×
140
    }
×
141

8,059✔
142
    node = iter.nextNode() as T;
8,059✔
143
  }
8,059✔
144
}
850✔
145

59✔
146
export function getElementByIdFromRoot(root: HTMLElement, id: string) {
59✔
147
  return (root.getRootNode() as Document | ShadowRoot).getElementById(id);
132✔
148
}
132✔
149

59✔
150
export function isElement(node: unknown): node is Element {
59✔
151
  return node instanceof Node && node.nodeType === Node.ELEMENT_NODE;
12,146✔
152
}
12,146✔
153

59✔
154
export function getElementsFromEventPath<T extends Element>(event: Event) {
59✔
155
  return event.composedPath().filter((item) => isElement(item)) as T[];
1,188✔
156
}
1,188✔
157

59✔
158
export function findElementFromEventPath<T extends Element>(
59✔
159
  predicate: string | ((element: Element) => boolean),
1,188✔
160
  event: Event
1,188✔
161
) {
1,188✔
162
  const func = isString(predicate)
1,188✔
163
    ? (e: Element) => e.matches(predicate)
350✔
164
    : (e: Element) => predicate(e);
838✔
165

1,188✔
166
  return getElementsFromEventPath(event).find(func) as T | undefined;
1,188✔
167
}
1,188✔
168

59✔
169
export function groupBy<T>(array: T[], key: keyof T | ((item: T) => any)) {
59✔
170
  const result: Record<string, T[]> = {};
132✔
171
  const _get = isFunction(key) ? key : (item: T) => item[key];
132!
172

132✔
173
  for (const item of array) {
132✔
174
    const category = _get(item);
739✔
175
    const group = result[category];
739✔
176

739✔
177
    if (Array.isArray(group)) {
739✔
178
      group.push(item);
482✔
179
    } else {
739✔
180
      result[category] = [item];
257✔
181
    }
257✔
182
  }
739✔
183

132✔
184
  return result;
132✔
185
}
132✔
186

59✔
187
export function first<T>(arr: T[]) {
59✔
188
  return arr.at(0) as T;
11,964✔
189
}
11,964✔
190

59✔
191
export function last<T>(arr: T[]) {
59✔
192
  return arr.at(-1) as T;
9,766✔
193
}
9,766✔
194

59✔
195
export function modulo(n: number, d: number) {
59✔
196
  return ((n % d) + d) % d;
1,098✔
197
}
1,098✔
198

59✔
199
/**
59✔
200
 * Creates an array of `n` elements from a given iterator.
59✔
201
 *
59✔
202
 */
59✔
203
export function take<T>(iterable: IterableIterator<T>, n: number) {
59✔
204
  const result: T[] = [];
449✔
205
  let i = 0;
449✔
206
  let current = iterable.next();
449✔
207

449✔
208
  while (i < n && !current.done) {
449✔
209
    result.push(current.value);
3,143✔
210
    current = iterable.next();
3,143✔
211
    i++;
3,143✔
212
  }
3,143✔
213

449✔
214
  return result;
449✔
215
}
449✔
216

59✔
217
/**
59✔
218
 * Splits an array into chunks of length `size` and returns a generator
59✔
219
 * yielding each chunk.
59✔
220
 * The last chunk may contain less than `size` elements.
59✔
221
 *
59✔
222
 * @example
59✔
223
 * ```typescript
59✔
224
 * const arr = [0,1,2,3,4,5,6,7,8,9];
59✔
225
 *
59✔
226
 * Array.from(chunk(arr, 2)) // [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]
59✔
227
 * Array.from(chunk(arr, 3)) // [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
59✔
228
 * Array.from(chunk([], 3)) // []
59✔
229
 * Array.from(chunk(arr, -3)) // Error
59✔
230
 * ```
59✔
231
 */
59✔
232
export function* chunk<T>(arr: T[], size: number) {
59✔
233
  if (size < 1) {
525!
234
    throw new Error('size must be an integer >= 1');
×
235
  }
×
236
  for (let i = 0; i < arr.length; i += size) {
525✔
237
    yield arr.slice(i, i + size);
3,035✔
238
  }
3,035✔
239
}
525✔
240

59✔
241
export function splitToWords(text: string) {
59✔
242
  const input = text.replaceAll(/[^a-zA-Z0-9\s-_]/g, '');
5,135✔
243
  if (/[\s-_]+/.test(input)) return input.split(/[\s-_]+/);
5,135!
244
  return input.split(/(?=[A-Z])+/);
5,135✔
245
}
5,135✔
246

59✔
247
export function toKebabCase(text: string): string {
59✔
248
  const input = text.trim();
5,135✔
249
  return splitToWords(input).join('-').toLocaleLowerCase();
5,135✔
250
}
5,135✔
251

59✔
252
export function isFunction(value: unknown): value is CallableFunction {
59✔
253
  return typeof value === 'function';
555✔
254
}
555✔
255

59✔
256
export function isString(value: unknown): value is string {
59✔
257
  return typeof value === 'string';
3,285✔
258
}
3,285✔
259

59✔
260
/**
59✔
261
 * Returns whether a given collection has at least one member.
59✔
262
 */
59✔
263
export function isEmpty<T, U extends string>(
59✔
264
  x: ArrayLike<T> | Set<T> | Map<U, T>
11,634✔
265
): boolean {
11,634✔
266
  return 'length' in x ? x.length < 1 : x.size < 1;
11,634✔
267
}
11,634✔
268

59✔
269
export function asArray<T>(value?: T | T[]): T[] {
59✔
270
  if (!isDefined(value)) return [];
781✔
271
  return Array.isArray(value) ? value : [value];
781✔
272
}
781✔
273

59✔
274
export function scrollIntoView(
59✔
275
  element?: HTMLElement,
82✔
276
  config?: ScrollIntoViewOptions
82✔
277
): void {
82✔
278
  if (!element) {
82!
NEW
UNCOV
279
    return;
×
NEW
UNCOV
280
  }
×
281

82✔
282
  element.scrollIntoView(
82✔
283
    Object.assign(
82✔
284
      {
82✔
285
        behavior: 'auto',
82✔
286
        block: 'nearest',
82✔
287
        inline: 'nearest',
82✔
288
      },
82✔
289
      config
82✔
290
    )
82✔
291
  );
82✔
292
}
82✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc