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

WolferyScripting / resclient-ts / #25

24 Aug 2025 12:37PM UTC coverage: 51.153% (+0.9%) from 50.293%
#25

push

DonovanDMC
1.1.0

227 of 281 branches covered (80.78%)

Branch coverage included in aggregate %.

1570 of 3232 relevant lines covered (48.58%)

10.67 hits per line

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

72.68
/lib/models/ResModel.ts
1
import type ResClient from "./ResClient.js";
1✔
2
import type CacheItem from "./CacheItem.js";
1✔
3
import { copy, equal, update, type PropertyDefinition } from "../includes/utils/obj.js";
1✔
4
import Properties from "../util/Properties.js";
1✔
5
import type { AnyFunction, AnyObject } from "../util/types.js";
1✔
6

1✔
7
export interface ResModelOptions {
1✔
8
    definition?: Record<string, PropertyDefinition>;
1✔
9
}
1✔
10
export default class ResModel {
1✔
11
    protected _definition?: Record<string, PropertyDefinition>;
38✔
12
    protected _props!: AnyObject;
38✔
13
    protected api!: ResClient;
38✔
14
    rid!: string;
38✔
15
    constructor(api: ResClient, rid: string, options?: ResModelOptions) {
38✔
16
        update(this, options ?? {}, {
38✔
17
            definition: { type: "?object", property: "_definition" }
38✔
18
        });
38✔
19
        this.p
38✔
20
            .writable("_definition")
38✔
21
            .readOnly("_props", {})
38✔
22
            .readOnly("api", api)
38✔
23
            .define("rid", false, true, true, rid);
38✔
24
    }
38✔
25

38✔
26
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
38✔
27
    protected async _listen(on: boolean): Promise<void> {
38✔
28
        // empty
11✔
29
    }
11✔
30

38✔
31
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
38✔
32
    protected _shouldPromoteKey(key: string, value: unknown): boolean {
38✔
33
        return true;
17✔
34
    }
17✔
35

38✔
36
    protected get cacheItem(): CacheItem<ResModel> {
38✔
37
        return this.getClient().cache[this.rid] as CacheItem<ResModel>;
×
38
    }
×
39

38✔
40
    protected get p(): Properties {
38✔
41
        return Properties.of(this);
38✔
42
    }
38✔
43

38✔
44
    get props(): AnyObject {
38✔
45
        return this._props;
×
46
    }
×
47

38✔
48
    auth<T = unknown>(method: string, params: unknown): Promise<T> {
38✔
49
        return this.api.authenticate<T>(this.rid, method, params);
×
50
    }
×
51

38✔
52
    call<T = unknown>(method: string, params?: unknown): Promise<T> {
38✔
53
        return this.api.call<T>(this.rid, method, params);
×
54
    }
×
55

38✔
56
    /** Called when the model is unsubscribed. */
38✔
57
    async dispose(): Promise<void> {
38✔
58
        await this._listen(false);
×
59
    }
×
60

38✔
61
    getClient(): ResClient {
38✔
62
        return this.api;
×
63
    }
×
64

38✔
65
    async init(data?: AnyObject): Promise<this> {
38✔
66
        if (data) {
11✔
67
            this.update(data);
11✔
68
        }
11✔
69

11✔
70
        await this._listen(true);
11✔
71
        return this;
11✔
72
    }
11✔
73

38✔
74
    /** Prevent this model from being unsubscribed. */
38✔
75
    keep(): void {
38✔
76
        this.cacheItem.keep();
×
77
    }
×
78

38✔
79
    off(events: string | Array<string> | null, handler: AnyFunction): this {
38✔
80
        this.api.eventBus.off(this, events, handler);
×
81
        return this;
×
82
    }
×
83

38✔
84
    on(events: string | Array<string> | null, handler: AnyFunction): this {
38✔
85
        this.api.eventBus.on(this, events, handler);
×
86
        return this;
×
87
    }
×
88

38✔
89
    resourceOff(events: string | Array<string> | null, handler: AnyFunction): this {
38✔
90
        this.api.resourceOff(this.rid, events, handler);
×
91
        return this;
×
92
    }
×
93

38✔
94
    resourceOn(events: string | Array<string> | null, handler: AnyFunction): this {
38✔
95
        this.api.resourceOn(this.rid, events, handler);
×
96
        return this;
×
97
    }
×
98

38✔
99
    // TODO: needs better typing
38✔
100
    setModel(props: AnyObject): Promise<unknown> {
38✔
101
        return this.api.setModel(this.rid, props);
×
102
    }
×
103

38✔
104
    toJSON(): AnyObject {
38✔
105
        const o = this._definition
4✔
106
            ? copy(this._props, this._definition)
4!
107
            : ({ ...this._props });
4✔
108
        // eslint-disable-next-line guard-for-in
4✔
109
        for (const k in o) {
4✔
110
            const v = o[k];
6✔
111
            if (typeof v === "object" && v !== null && "toJSON" in v) {
6✔
112
                o[k] = (v as { toJSON(): object; }).toJSON();
1✔
113
            }
1✔
114
        }
6✔
115
        return o;
4✔
116
    }
4✔
117

38✔
118
    /** Undo preventing this model from being unsubscribed. */
38✔
119
    unkeep(): void {
38✔
120
        this.cacheItem.unkeep();
×
121
    }
×
122

38✔
123
    update(props: AnyObject, reset = false): AnyObject | null {
38✔
124
        if (!props) {
15✔
125
            return null;
1✔
126
        }
1✔
127

14✔
128
        let changed: AnyObject | null = null, v: unknown, promote: boolean;
14✔
129
        const p = this._props;
14✔
130

14✔
131

14✔
132
        if (reset) {
15!
133
            props = { ...props };
×
134
            for (const k in p) {
×
135
                if (!Object.hasOwn(props, k)) {
×
136
                    props[k] = undefined;
×
137
                }
×
138
            }
×
139
        }
×
140

14✔
141
        if (this._definition) {
15!
142
            changed = update(p, props, this._definition);
×
143
            for (const key in changed) {
×
144
                if ((Object.hasOwn(this, key) || !(this as AnyObject)[key]) && key[0] !== "_" && Object.getOwnPropertyDescriptor(this, key)?.writable !== false) {
×
145
                    v = p[key];
×
146
                    if (v === undefined) {
×
147
                        delete (this as AnyObject)[key];
×
148
                    } else {
×
149
                        (this as AnyObject)[key] = v;
×
150
                    }
×
151
                }
×
152
            }
×
153
        } else {
15✔
154
            // eslint-disable-next-line guard-for-in
14✔
155
            for (const key in props) {
14✔
156
                v = props[key];
24✔
157
                promote = (Object.hasOwn(this, key) || !(this as AnyObject)[key]) && key[0] !== "_" && Object.getOwnPropertyDescriptor(this, key)?.writable !== false && this._shouldPromoteKey(key, v);
24✔
158
                if (!equal(p[key], v)) {
24✔
159
                    changed ||= {};
24✔
160
                    changed[key] = p[key];
24✔
161
                    if (v === undefined) {
24!
162
                        delete p[key];
×
163
                        if (promote) {
×
164
                            delete (this as AnyObject)[key];
×
165
                        }
×
166
                    } else {
24✔
167
                        p[key] = v;
24✔
168
                        if (promote) {
24✔
169
                            (this as AnyObject)[key] = v;
17✔
170
                        }
17✔
171
                    }
24✔
172
                }
24✔
173
            }
24✔
174
        }
14✔
175

14✔
176
        return changed;
14✔
177
    }
14✔
178
}
38✔
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