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

excaliburjs / Excalibur / 14804036802

02 May 2025 09:58PM UTC coverage: 5.927% (-83.4%) from 89.28%
14804036802

Pull #3404

github

web-flow
Merge 5c103d7f8 into 0f2ccaeb2
Pull Request #3404: feat: added Graph module to Math

234 of 8383 branches covered (2.79%)

229 of 246 new or added lines in 1 file covered. (93.09%)

13145 existing lines in 208 files now uncovered.

934 of 15759 relevant lines covered (5.93%)

4.72 hits per line

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

16.67
/src/engine/Resources/Resource.ts
1
import { Loadable } from '../Interfaces/Loadable';
2
import { Logger } from '../Util/Log';
3
import { EventEmitter } from '../EventEmitter';
4

5
export type ResourceEvents = {
6
  complete: any;
7
  load: ProgressEvent<XMLHttpRequestEventTarget>;
8
  loadstart: ProgressEvent<XMLHttpRequestEventTarget>;
9
  progress: ProgressEvent<XMLHttpRequestEventTarget>;
10
  error: ProgressEvent<XMLHttpRequestEventTarget>;
11
};
12

13
export const ResourceEvents = {
1✔
14
  Complete: 'complete',
15
  Load: 'load',
16
  LoadStart: 'loadstart',
17
  Progress: 'progress',
18
  Error: 'error'
19
};
20

21
/**
22
 * The {@apilink Resource} type allows games built in Excalibur to load generic resources.
23
 * For any type of remote resource it is recommended to use {@apilink Resource} for preloading.
24
 */
25
export class Resource<T> implements Loadable<T> {
26
  public data: T = null;
1✔
27
  public logger: Logger = Logger.getInstance();
1✔
28
  public events = new EventEmitter();
1✔
29

30
  /**
31
   * @param path          Path to the remote resource
32
   * @param responseType  The type to expect as a response: "" | "arraybuffer" | "blob" | "document" | "json" | "text";
33
   * @param bustCache     Whether or not to cache-bust requests
34
   */
35
  constructor(
36
    public path: string,
1✔
37
    public responseType: '' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text',
1✔
38
    public bustCache: boolean = false
1✔
39
  ) {}
40

41
  /**
42
   * Returns true if the Resource is completely loaded and is ready
43
   * to be drawn.
44
   */
45
  public isLoaded(): boolean {
UNCOV
46
    return this.data !== null;
×
47
  }
48

49
  private _cacheBust(uri: string): string {
UNCOV
50
    const query: RegExp = /\?\w*=\w*/;
×
UNCOV
51
    if (query.test(uri)) {
×
52
      uri += '&__=' + Date.now();
×
53
    } else {
UNCOV
54
      uri += '?__=' + Date.now();
×
55
    }
UNCOV
56
    return uri;
×
57
  }
58
  /**
59
   * Begin loading the resource and returns a promise to be resolved on completion
60
   */
61
  public load(): Promise<T> {
UNCOV
62
    return new Promise((resolve, reject) => {
×
63
      // Exit early if we already have data
UNCOV
64
      if (this.data !== null) {
×
UNCOV
65
        this.logger.debug('Already have data for resource', this.path);
×
UNCOV
66
        this.events.emit('complete', this.data as any);
×
UNCOV
67
        resolve(this.data);
×
UNCOV
68
        return;
×
69
      }
70

UNCOV
71
      const request = new XMLHttpRequest();
×
UNCOV
72
      request.open('GET', this.bustCache ? this._cacheBust(this.path) : this.path, true);
×
UNCOV
73
      request.responseType = this.responseType;
×
UNCOV
74
      request.addEventListener('loadstart', (e) => this.events.emit('loadstart', e as any));
×
UNCOV
75
      request.addEventListener('progress', (e) => this.events.emit('progress', e as any));
×
UNCOV
76
      request.addEventListener('error', (e) => this.events.emit('error', e as any));
×
UNCOV
77
      request.addEventListener('load', (e) => this.events.emit('load', e as any));
×
UNCOV
78
      request.addEventListener('load', () => {
×
79
        // XHR on file:// success status is 0, such as with PhantomJS
UNCOV
80
        if (request.status !== 0 && request.status !== 200) {
×
UNCOV
81
          this.logger.error('Failed to load resource ', this.path, ' server responded with error code', request.status);
×
UNCOV
82
          this.events.emit('error', request.response);
×
UNCOV
83
          reject(new Error(request.statusText));
×
UNCOV
84
          return;
×
85
        }
86

UNCOV
87
        if (request.response instanceof Blob && request.response.type === 'text/html') {
×
88
          const errorText = `Expected blob (usually image) data from the server when loading ${this.path}, but got HTML content instead!
×
89

90
Check your server configuration, for example Vite serves static files from the /public folder`;
91
          this.events.emit('error', request.response);
×
92
          reject(new Error(errorText));
×
93
          return;
×
94
        }
95

UNCOV
96
        this.data = request.response;
×
UNCOV
97
        this.events.emit('complete', this.data as any);
×
UNCOV
98
        this.logger.debug('Completed loading resource', this.path);
×
UNCOV
99
        resolve(this.data);
×
100
      });
UNCOV
101
      request.send();
×
102
    });
103
  }
104
}
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