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

excaliburjs / Excalibur / 15987755689

01 Jul 2025 01:45AM UTC coverage: 87.937% (+0.005%) from 87.932%
15987755689

Pull #3454

github

web-flow
Merge c23f6dfac into 38eabdd7d
Pull Request #3454: refactor: Optimize BoundingBox/Raycast

5145 of 7132 branches covered (72.14%)

34 of 37 new or added lines in 2 files covered. (91.89%)

1 existing line in 1 file now uncovered.

13931 of 15842 relevant lines covered (87.94%)

24812.97 hits per line

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

83.67
/src/engine/Util/Util.ts
1
import { Vector, vec } from '../Math/vector';
2
import type { Clock } from './Clock';
3
import { Future } from './Future';
4

5
/**
6
 *
7
 */
8
export function getMinIndex(array: number[]): number {
9
  if (array.length === 0) {
56!
NEW
10
    throw new Error('Cannot find minIndex of array.length == 0');
×
11
  }
12

13
  let min = array[0];
56✔
14
  let minIndex = 0;
56✔
15

16
  for (let i = 1; i < array.length; i++) {
56✔
17
    if (array[i] < min) {
168✔
18
      min = array[i];
50✔
19
      minIndex = i;
50✔
20
    }
21
  }
22
  return minIndex;
56✔
23
}
24

25
/**
26
 * Find the screen position of an HTML element
27
 */
28
export function getPosition(el: HTMLElement): Vector {
29
  // do we need the scroll too? technically the offset method before did that
30
  if (el && el.getBoundingClientRect) {
6,442✔
31
    const rect = el.getBoundingClientRect();
6,028✔
32
    return vec(rect.x + window.scrollX, rect.y + window.scrollY);
6,028✔
33
  }
34
  return Vector.Zero;
414✔
35
}
36

37
/**
38
 * Add an item to an array list if it doesn't already exist. Returns true if added, false if not and already exists in the array.
39
 * @deprecated Will be removed in v0.26.0
40
 */
41
export function addItemToArray<T>(item: T, array: T[]): boolean {
42
  if (array.indexOf(item) === -1) {
×
43
    array.push(item);
×
44
    return true;
×
45
  }
46
  return false;
×
47
}
48

49
/**
50
 * Remove an item from an list
51
 * @deprecated Will be removed in v0.26.0
52
 */
53
export function removeItemFromArray<T>(item: T, array: T[]): boolean {
54
  let index = -1;
173✔
55
  if ((index = array.indexOf(item)) > -1) {
173✔
56
    array.splice(index, 1);
172✔
57
    return true;
172✔
58
  }
59

60
  return false;
1✔
61
}
62

63
/**
64
 * See if an array contains something
65
 */
66
export function contains(array: Array<any>, obj: any): boolean {
67
  for (let i = 0; i < array.length; i++) {
28✔
68
    if (array[i] === obj) {
1!
69
      return true;
×
70
    }
71
  }
72
  return false;
28✔
73
}
74

75
/**
76
 * Used for exhaustive checks at compile time
77
 */
78
export function fail(message: never): never {
79
  throw new Error(message);
×
80
}
81

82
/**
83
 * Create a promise that resolves after a certain number of milliseconds
84
 *
85
 * It is strongly recommended you pass the excalibur clock so delays are bound to the
86
 * excalibur clock which would be unaffected by stop/pause.
87
 * @param milliseconds
88
 * @param clock
89
 */
90
export function delay(milliseconds: number, clock?: Clock): Promise<void> {
91
  const future = new Future<void>();
34✔
92
  const schedule = clock?.schedule.bind(clock) ?? setTimeout;
34✔
93
  schedule(() => {
34✔
94
    future.resolve();
34✔
95
  }, milliseconds);
96
  return future.promise;
34✔
97
}
98

99
/**
100
 * Remove keys from object literals
101
 * @param object
102
 * @param keys
103
 */
104
export function omit<TObject extends Object, Keys extends keyof TObject>(object: TObject, keys: Keys[]) {
105
  const newObj: Omit<TObject, Keys> = {} as any;
1,642✔
106
  for (const key in object) {
1,642✔
107
    if (!keys.includes(key as any)) {
6,344✔
108
      (newObj as any)[key] = object[key];
5,826✔
109
    }
110
  }
111
  return newObj;
1,642✔
112
}
113

114
/**
115
 * Simple object check.
116
 * @param item
117
 */
118
export function isObject(item: any): item is object {
119
  return item && typeof item === 'object' && !Array.isArray(item);
1,956✔
120
}
121

122
/**
123
 * Deep merge two objects.
124
 * @param target
125
 * @param sources
126
 */
127
export function mergeDeep<T extends object>(target: T, ...sources: T[]) {
128
  if (!sources.length) {
1,618✔
129
    return target;
809✔
130
  }
131
  const source = sources.shift();
809✔
132

133
  if (isObject(target) && isObject(source)) {
809✔
134
    for (const key in source) {
181✔
135
      if (isObject(source[key])) {
338✔
136
        if (!target[key]) {
79!
137
          Object.assign(target, { [key]: {} });
×
138
        }
139
        mergeDeep(target[key] as any, source[key]);
79✔
140
      } else {
141
        Object.assign(target, { [key]: source[key] });
259✔
142
      }
143
    }
144
  }
145

146
  return mergeDeep(target, ...sources);
809✔
147
}
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

© 2026 Coveralls, Inc