@converse/skeletor 0.0.9 → 1.0.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 (39) hide show
  1. package/README.md +5 -89
  2. package/dist/skeletor.d.ts +764 -0
  3. package/dist/skeletor.js +7564 -7743
  4. package/dist/skeletor.min.js +6 -11
  5. package/package.json +46 -30
  6. package/src/{collection.js → collection.ts} +232 -271
  7. package/src/drivers/{sessionStorage.js → sessionStorage.ts} +81 -93
  8. package/src/{eventemitter.js → eventemitter.ts} +44 -59
  9. package/src/{helpers.js → helpers.ts} +56 -69
  10. package/src/index.ts +84 -0
  11. package/src/{listening.js → listening.ts} +32 -27
  12. package/src/{model.js → model.ts} +143 -162
  13. package/src/{storage.js → storage.ts} +92 -49
  14. package/src/types.ts +189 -0
  15. package/src/utils/{events.js → events.ts} +98 -48
  16. package/dist/skeletor.js.map +0 -1
  17. package/dist/skeletor.min.js.map +0 -1
  18. package/src/element.js +0 -238
  19. package/src/index.js +0 -47
  20. package/src/types/collection.d.ts +0 -366
  21. package/src/types/collection.d.ts.map +0 -1
  22. package/src/types/drivers/sessionStorage.d.ts +0 -37
  23. package/src/types/drivers/sessionStorage.d.ts.map +0 -1
  24. package/src/types/element.d.ts +0 -115
  25. package/src/types/element.d.ts.map +0 -1
  26. package/src/types/eventemitter.d.ts +0 -93
  27. package/src/types/eventemitter.d.ts.map +0 -1
  28. package/src/types/helpers.d.ts +0 -62
  29. package/src/types/helpers.d.ts.map +0 -1
  30. package/src/types/index.d.ts +0 -19
  31. package/src/types/index.d.ts.map +0 -1
  32. package/src/types/listening.d.ts +0 -40
  33. package/src/types/listening.d.ts.map +0 -1
  34. package/src/types/model.d.ts +0 -230
  35. package/src/types/model.d.ts.map +0 -1
  36. package/src/types/storage.d.ts +0 -35
  37. package/src/types/storage.d.ts.map +0 -1
  38. package/src/types/utils/events.d.ts +0 -28
  39. package/src/types/utils/events.d.ts.map +0 -1
@@ -1,81 +1,76 @@
1
- import { getResolveablePromise, getSyncMethod, urlError, wrapError } from './helpers.js';
2
- import clone from 'lodash-es/clone.js';
3
- import defaults from 'lodash-es/defaults.js';
4
- import defer from 'lodash-es/defer.js';
5
- import has from 'lodash-es/has.js';
6
- import invert from 'lodash-es/invert.js';
7
- import isEmpty from 'lodash-es/isEmpty.js';
8
- import isEqual from 'lodash-es/isEqual.js';
9
- import iteratee from 'lodash-es/iteratee.js';
10
- import omit from 'lodash-es/omit.js';
11
- import pick from 'lodash-es/pick.js';
12
- import result from 'lodash-es/result.js';
13
- import uniqueId from 'lodash-es/uniqueId.js';
14
- import EventEmitter from './eventemitter.js';
15
-
16
- /**
17
- * @typedef {import('./collection.js').Collection} Collection
18
- * @typedef {Record.<string, any>} Attributes
19
- *
20
- * @typedef {Record.<string, any>} Options
21
- * @property {boolean} [validate]
22
- *
23
- * @typedef {Record.<string, any>} ModelOptions
24
- * @property {Collection} [collection]
25
- * @property {boolean} [parse]
26
- * @property {boolean} [unset]
27
- * @property {boolean} [silent]
28
- */
1
+ import { getResolveablePromise, getSyncMethod, urlError, wrapError } from './helpers';
2
+ import clone from 'lodash-es/clone';
3
+ import defaults from 'lodash-es/defaults';
4
+ import defer from 'lodash-es/defer';
5
+ import has from 'lodash-es/has';
6
+ import invert from 'lodash-es/invert';
7
+ import isEmpty from 'lodash-es/isEmpty';
8
+ import isEqual from 'lodash-es/isEqual';
9
+ import iteratee from 'lodash-es/iteratee';
10
+ import omit from 'lodash-es/omit';
11
+ import pick from 'lodash-es/pick';
12
+ import result from 'lodash-es/result';
13
+ import uniqueId from 'lodash-es/uniqueId';
14
+ import { EventEmitterObject } from './eventemitter';
15
+
16
+ // Import types
17
+ import type { Collection } from './collection';
18
+ import type Storage from './storage';
19
+ import { ModelAttributes, ObjectWithId, SyncOperation, ModelOptions, Options } from './types';
29
20
 
30
21
  /**
22
+ * @public
31
23
  * **Models** are the basic data object in the framework --
32
24
  * frequently representing a row in a table in a database on your server.
33
25
  * A discrete chunk of data and a bunch of useful, related methods for
34
26
  * performing computations and transformations on that data.
35
27
  */
36
- class Model extends EventEmitter(Object) {
28
+ export class Model<T extends ModelAttributes = ModelAttributes> extends EventEmitterObject {
29
+ _browserStorage?: Storage;
30
+ _changing = false;
31
+ _pending: boolean | ModelOptions = false;
32
+ _previousAttributes?: T;
33
+ _url: string = '';
34
+ _urlRoot: string;
35
+ attributes: T;
36
+ changed: Partial<T> = {};
37
+ cid: string;
38
+ collection?: Collection;
39
+ id: string | number;
40
+ validationError: string | number | null = null;
41
+
37
42
  /**
38
43
  * Create a new model with the specified attributes. A client id (`cid`)
39
44
  * is automatically generated and assigned for you.
40
- * @param {Attributes} [attributes]
41
- * @param {ModelOptions} [options]
42
45
  */
43
- constructor(attributes, options) {
46
+ constructor(attributes?: Partial<T>, options?: ModelOptions) {
44
47
  super();
45
- let attrs = attributes || {};
46
- options || (options = {});
47
- this.preinitialize.apply(this, arguments);
48
- this.cid = uniqueId(this.cidPrefix);
49
- this.attributes = {};
48
+ let attrs: Partial<T> = attributes || ({} as Partial<T>);
49
+ options = options || {};
50
50
 
51
- // The value returned during the last failed validation.
52
- this.validationError = null;
51
+ this.preinitialize.apply(this, arguments as any);
52
+ this.cid = uniqueId(this.cidPrefix);
53
+ this.attributes = {} as T;
53
54
 
54
55
  if (options.collection) this.collection = options.collection;
55
- if (options.parse) attrs = this.parse(attrs, options) || {};
56
+ if (options.parse) attrs = this.parse(attrs, options) || ({} as Partial<T>);
56
57
 
57
58
  const default_attrs = result(this, 'defaults');
58
59
  attrs = defaults(Object.assign({}, default_attrs, attrs), default_attrs);
59
60
 
60
61
  this.set(attrs, options);
61
62
 
62
- this.initialize.apply(this, arguments);
63
+ this.initialize.apply(this, arguments as any);
63
64
 
64
- // A hash of attributes whose current and previous value differ.
65
+ // Reset changed after initial set
65
66
  this.changed = {};
66
67
  }
67
68
 
68
- /**
69
- * @param {Storage} storage
70
- */
71
- set browserStorage(storage) {
69
+ set browserStorage(storage: Storage) {
72
70
  this._browserStorage = storage;
73
71
  }
74
72
 
75
- /**
76
- * @returns {Storage} storage
77
- */
78
- get browserStorage() {
73
+ get browserStorage(): Storage | undefined {
79
74
  return this._browserStorage;
80
75
  }
81
76
 
@@ -84,8 +79,7 @@ class Model extends EventEmitter(Object) {
84
79
  * CouchDB users may want to set this to `"_id"` (by overriding this getter
85
80
  * in a subclass).
86
81
  */
87
- // eslint-disable-next-line class-methods-use-this
88
- get idAttribute() {
82
+ get idAttribute(): string {
89
83
  return 'id';
90
84
  }
91
85
 
@@ -93,8 +87,7 @@ class Model extends EventEmitter(Object) {
93
87
  * The prefix is used to create the client id which is used to identify models locally.
94
88
  * You may want to override this if you're experiencing name clashes with model ids.
95
89
  */
96
- // eslint-disable-next-line class-methods-use-this
97
- get cidPrefix() {
90
+ get cidPrefix(): string {
98
91
  return 'c';
99
92
  }
100
93
 
@@ -102,128 +95,118 @@ class Model extends EventEmitter(Object) {
102
95
  * preinitialize is an empty function by default. You can override it with a function
103
96
  * or object. preinitialize will run before any instantiation logic is run in the Model.
104
97
  */
105
- // eslint-disable-next-line class-methods-use-this
106
- preinitialize() {}
98
+ preinitialize(...args: any[]): void {}
107
99
 
108
100
  /**
109
101
  * Initialize is an empty function by default. Override it with your own
110
102
  * initialization logic.
111
- * @param {Attributes} [attrs]
112
- * @param {ModelOptions} [options]
113
103
  */
114
- initialize(attrs, options) {}
104
+ initialize(attrs?: Partial<T>, options?: ModelOptions): void {}
105
+
106
+ validate(attrs: Partial<T> | ObjectWithId, options?: ModelOptions): string | number | null | void {
107
+ return null;
108
+ }
115
109
 
116
110
  /**
117
- * @param {object} attrs
118
- * @param {object} [options]
119
- * @returns {string} The validation error message
111
+ * Return a hash of defaults for the model's attributes.
120
112
  */
121
- validate(attrs, options) {
122
- return '';
113
+ defaults(): Partial<T> {
114
+ return {} as Partial<T>;
123
115
  }
124
116
 
125
117
  /**
126
118
  * Return a copy of the model's `attributes` object.
127
119
  */
128
- toJSON() {
120
+ toJSON(): T {
129
121
  return clone(this.attributes);
130
122
  }
131
123
 
132
124
  /**
133
125
  * Override this if you need custom syncing semantics for *this* particular model.
134
- * @param {'create'|'update'|'patch'|'delete'|'read'} method
135
- * @param {Model} model
136
- * @param {Options} options
137
126
  */
138
- // eslint-disable-next-line class-methods-use-this
139
- sync(method, model, options) {
127
+ sync(method: SyncOperation, model: Model<any>, options: Options): any {
140
128
  return getSyncMethod(model)(method, model, options);
141
129
  }
142
130
 
143
131
  /**
144
132
  * Get the value of an attribute.
145
- * @param {string} attr
146
133
  */
147
- get(attr) {
134
+ get<K extends keyof T>(attr: K): T[K] {
148
135
  return this.attributes[attr];
149
136
  }
150
137
 
151
- keys() {
138
+ keys(): string[] {
152
139
  return Object.keys(this.attributes);
153
140
  }
154
141
 
155
- values() {
142
+ values(): T[keyof T][] {
156
143
  return Object.values(this.attributes);
157
144
  }
158
145
 
159
- pairs() {
146
+ pairs(): [keyof T, T[keyof T]][] {
160
147
  return this.entries();
161
148
  }
162
149
 
163
- entries() {
164
- return Object.entries(this.attributes);
150
+ entries(): [keyof T, T[keyof T]][] {
151
+ return Object.entries(this.attributes) as [keyof T, T[keyof T]][];
165
152
  }
166
153
 
167
- invert() {
154
+ invert(): Record<string, keyof T> {
168
155
  return invert(this.attributes);
169
156
  }
170
157
 
171
- pick(...args) {
158
+ pick<K extends keyof T>(...args: K[]): Pick<T, K> {
172
159
  if (args.length === 1 && Array.isArray(args[0])) {
173
- args = args[0];
160
+ args = args[0] as K[];
174
161
  }
175
- return pick(this.attributes, args);
162
+ return pick(this.attributes, args) as Pick<T, K>;
176
163
  }
177
164
 
178
- omit(...args) {
165
+ omit<K extends keyof T>(...args: K[]): Omit<T, K> {
179
166
  if (args.length === 1 && Array.isArray(args[0])) {
180
- args = args[0];
167
+ args = args[0] as K[];
181
168
  }
182
- return omit(this.attributes, args);
169
+ return omit(this.attributes, args) as Omit<T, K>;
183
170
  }
184
171
 
185
- isEmpty() {
172
+ isEmpty(): boolean {
186
173
  return isEmpty(this.attributes);
187
174
  }
188
175
 
189
176
  /**
190
177
  * Returns `true` if the attribute contains a value that is not null
191
178
  * or undefined.
192
- * @param {string} attr
193
179
  */
194
- has(attr) {
180
+ has(attr: keyof T): boolean {
195
181
  return this.get(attr) != null;
196
182
  }
197
183
 
198
184
  /**
199
185
  * Special-cased proxy to lodash's `matches` method.
200
- * @param {Attributes} attrs
201
186
  */
202
- matches(attrs) {
203
- return !!iteratee(attrs, this)(this.attributes);
187
+ matches(attrs: Partial<T>): boolean {
188
+ return !!iteratee(attrs)(this.attributes);
204
189
  }
205
190
 
206
191
  /**
207
192
  * Set a hash of model attributes on the object, firing `"change"`. This is
208
193
  * the core primitive operation of a model, updating the data and notifying
209
194
  * anyone who needs to know about the change in state. The heart of the beast.
210
- * @param {string|Object} key
211
- * @param {string|Object} [val]
212
- * @param {Options} [options]
213
195
  */
214
- set(key, val, options) {
196
+ set(key: string | Partial<T> | ObjectWithId, val?: any, options?: ModelOptions): boolean | this {
215
197
  if (key == null) return this;
216
198
 
217
199
  // Handle both `"key", value` and `{key: value}` -style arguments.
218
- let attrs;
200
+ let attrs: Partial<T> | ObjectWithId;
219
201
  if (typeof key === 'object') {
220
202
  attrs = key;
221
203
  options = val;
222
204
  } else {
223
- (attrs = {})[key] = val;
205
+ attrs = {} as Partial<T>;
206
+ attrs[key as keyof T] = val;
224
207
  }
225
208
 
226
- options || (options = {});
209
+ options = options || {};
227
210
 
228
211
  // Run validation.
229
212
  if (!this._validate(attrs, options)) return false;
@@ -246,14 +229,14 @@ class Model extends EventEmitter(Object) {
246
229
 
247
230
  // For each `set` attribute, update or delete the current value.
248
231
  for (const attr in attrs) {
249
- val = attrs[attr];
250
- if (!isEqual(current[attr], val)) changes.push(attr);
251
- if (!isEqual(prev[attr], val)) {
252
- changed[attr] = val;
232
+ val = attrs[attr as keyof (T | ObjectWithId)];
233
+ if (!isEqual(current[attr as keyof T], val)) changes.push(attr);
234
+ if (!isEqual(prev[attr as keyof T], val)) {
235
+ changed[attr as keyof T] = val;
253
236
  } else {
254
- delete changed[attr];
237
+ delete changed[attr as keyof T];
255
238
  }
256
- unset ? delete current[attr] : (current[attr] = val);
239
+ unset ? delete current[attr as keyof T] : (current[attr as keyof T] = val);
257
240
  }
258
241
 
259
242
  // Update the `id`.
@@ -267,12 +250,13 @@ class Model extends EventEmitter(Object) {
267
250
  }
268
251
  }
269
252
 
270
- // You might be wondering why there's a `while` loop here. Changes can
271
- // be recursively nested within `"change"` events.
272
- if (changing) return this;
253
+ if (changing) return true;
254
+
273
255
  if (!silent) {
256
+ // You might be wondering why there's a `while` loop here. Changes can
257
+ // be recursively nested within `"change"` events.
274
258
  while (this._pending) {
275
- options = /** @type {Options} */ (this._pending);
259
+ options = this._pending as ModelOptions;
276
260
  this._pending = false;
277
261
  this.trigger('change', this, options);
278
262
  }
@@ -285,31 +269,27 @@ class Model extends EventEmitter(Object) {
285
269
  /**
286
270
  * Remove an attribute from the model, firing `"change"`. `unset` is a noop
287
271
  * if the attribute doesn't exist.
288
- * @param {string} attr
289
- * @param {Options} [options]
290
272
  */
291
- unset(attr, options) {
292
- return this.set(attr, undefined, Object.assign({}, options, { unset: true }));
273
+ unset(attr: keyof T, options?: ModelOptions): boolean | this {
274
+ return this.set(attr as string, undefined, Object.assign({}, options, { unset: true }));
293
275
  }
294
276
 
295
277
  /**
296
278
  * Clear all attributes on the model, firing `"change"`.
297
- * @param {Options} options
298
279
  */
299
- clear(options) {
300
- const attrs = {};
301
- for (const key in this.attributes) attrs[key] = undefined;
280
+ clear(options?: ModelOptions): boolean | this {
281
+ const attrs: Partial<T> = {};
282
+ for (const key in this.attributes) attrs[key as keyof T] = undefined;
302
283
  return this.set(attrs, Object.assign({}, options, { unset: true }));
303
284
  }
304
285
 
305
286
  /**
306
287
  * Determine if the model has changed since the last `"change"` event.
307
288
  * If you specify an attribute name, determine if that attribute has changed.
308
- * @param {string} [attr]
309
289
  */
310
- hasChanged(attr) {
290
+ hasChanged(attr?: keyof T): boolean {
311
291
  if (attr == null) return !isEmpty(this.changed);
312
- return has(this.changed, attr);
292
+ return has(this.changed, attr as string);
313
293
  }
314
294
 
315
295
  /**
@@ -319,20 +299,19 @@ class Model extends EventEmitter(Object) {
319
299
  * persisted to the server. Unset attributes will be set to undefined.
320
300
  * You can also pass an attributes object to diff against the model,
321
301
  * determining if there *would be* a change.
322
- * @param {Object} diff
323
302
  */
324
- changedAttributes(diff) {
303
+ changedAttributes(diff?: Partial<T>): Partial<T> | false {
325
304
  if (!diff) {
326
305
  return this.hasChanged() ? clone(this.changed) : false;
327
306
  }
328
307
 
329
308
  const old = this._changing ? this._previousAttributes : this.attributes;
330
- const changed = {};
331
- let hasChanged;
309
+ const changed: Partial<T> = {};
310
+ let hasChanged = false;
332
311
  for (const attr in diff) {
333
- const val = diff[attr];
334
- if (isEqual(old[attr], val)) continue;
335
- changed[attr] = val;
312
+ const val = diff[attr as keyof T];
313
+ if (isEqual(old[attr as keyof T], val)) continue;
314
+ changed[attr as keyof T] = val;
336
315
  hasChanged = true;
337
316
  }
338
317
  return hasChanged ? changed : false;
@@ -341,9 +320,8 @@ class Model extends EventEmitter(Object) {
341
320
  /**
342
321
  * Get the previous value of an attribute, recorded at the time the last
343
322
  * `"change"` event was fired.
344
- * @param {string} [attr]
345
323
  */
346
- previous(attr) {
324
+ previous<K extends keyof T>(attr: K): T[K] | null {
347
325
  if (attr == null || !this._previousAttributes) return null;
348
326
  return this._previousAttributes[attr];
349
327
  }
@@ -352,21 +330,20 @@ class Model extends EventEmitter(Object) {
352
330
  * Get all of the attributes of the model at the time of the previous
353
331
  * `"change"` event.
354
332
  */
355
- previousAttributes() {
356
- return clone(this._previousAttributes);
333
+ previousAttributes(): T | undefined {
334
+ return this._previousAttributes ? clone(this._previousAttributes) : undefined;
357
335
  }
358
336
 
359
337
  /**
360
338
  * Fetch the model from the server, merging the response with the model's
361
339
  * local attributes. Any changed attributes will trigger a "change" event.
362
- * @param {Options} [options={}]
363
340
  */
364
- fetch(options={}) {
341
+ fetch(options: Options = {}): any {
365
342
  options = Object.assign({ parse: true }, options);
366
343
 
367
344
  const success = options.success;
368
345
 
369
- options.success = (resp) => {
346
+ options.success = (resp: any) => {
370
347
  const serverAttrs = options.parse ? this.parse(resp, options) : resp;
371
348
  if (!this.set(serverAttrs, options)) return false;
372
349
  if (success) success.call(options.context, this, resp, options);
@@ -381,18 +358,16 @@ class Model extends EventEmitter(Object) {
381
358
  * Set a hash of model attributes, and sync the model to the server.
382
359
  * If the server returns an attributes hash that differs, the model's
383
360
  * state will be `set` again.
384
- * @param {string|Attributes} [key]
385
- * @param {boolean|number|string|Options} [val]
386
- * @param {Options} [options]
387
361
  */
388
- save(key, val, options) {
362
+ save(key?: string | null | Partial<T>, val?: any, options?: ModelOptions): any {
389
363
  // Handle both `"key", value` and `{key: value}` -style arguments.
390
- let attrs;
364
+ let attrs: Partial<T> | undefined;
391
365
  if (key == null || typeof key === 'object') {
392
- attrs = key;
393
- options = /** @type {Options} */ (val);
366
+ attrs = key as Partial<T>;
367
+ options = val as ModelOptions;
394
368
  } else {
395
- (attrs = {})[key] = val;
369
+ attrs = {} as Partial<T>;
370
+ attrs[key as keyof T] = val;
396
371
  }
397
372
 
398
373
  options = Object.assign({ validate: true, parse: true }, options);
@@ -405,7 +380,7 @@ class Model extends EventEmitter(Object) {
405
380
  // the model will be valid when the attributes, if any, are set.
406
381
  if (attrs && !wait) {
407
382
  if (!this.set(attrs, options)) return false;
408
- } else if (!this._validate(/** @type {Object} */ (attrs), options)) {
383
+ } else if (!this._validate(attrs || {}, options)) {
409
384
  return false;
410
385
  }
411
386
 
@@ -415,7 +390,7 @@ class Model extends EventEmitter(Object) {
415
390
  const error = options.error;
416
391
  const attributes = this.attributes;
417
392
 
418
- options.success = (resp) => {
393
+ options.success = (resp: any) => {
419
394
  // Ensure attributes are restored during synchronous saves.
420
395
  this.attributes = attributes;
421
396
  let serverAttrs = options.parse ? this.parse(resp, options) : resp;
@@ -426,7 +401,7 @@ class Model extends EventEmitter(Object) {
426
401
  return_promise && promise.resolve();
427
402
  };
428
403
 
429
- options.error = (model, e, options) => {
404
+ options.error = (model: this, e: any, options: Options) => {
430
405
  error && error.call(options.context, model, e, options);
431
406
  return_promise && promise.reject(e);
432
407
  };
@@ -454,9 +429,8 @@ class Model extends EventEmitter(Object) {
454
429
  * Destroy this model on the server if it was already persisted.
455
430
  * Optimistically removes the model from its collection, if it has one.
456
431
  * If `wait: true` is passed, waits for the server to respond before removal.
457
- * @param {Options} [options]
458
432
  */
459
- destroy(options) {
433
+ destroy(options?: ModelOptions): any {
460
434
  options = options ? clone(options) : {};
461
435
  const success = options.success;
462
436
  const wait = options.wait;
@@ -466,13 +440,13 @@ class Model extends EventEmitter(Object) {
466
440
  this.trigger('destroy', this, this.collection, options);
467
441
  };
468
442
 
469
- options.success = (resp) => {
443
+ options.success = (resp: any) => {
470
444
  if (wait) destroy();
471
445
  if (success) success.call(options.context, this, resp, options);
472
446
  if (!this.isNew()) this.trigger('sync', this, resp, options);
473
447
  };
474
448
 
475
- let xhr = false;
449
+ let xhr: any = false;
476
450
  if (this.isNew()) {
477
451
  defer(options.success);
478
452
  } else {
@@ -483,51 +457,60 @@ class Model extends EventEmitter(Object) {
483
457
  return xhr;
484
458
  }
485
459
 
460
+ get urlRoot(): string {
461
+ return this._urlRoot;
462
+ }
463
+
464
+ set urlRoot(root: string) {
465
+ this._urlRoot = root;
466
+ }
467
+
486
468
  /**
487
469
  * Default URL for the model's representation on the server -- if you're
488
470
  * using Backbone's restful methods, override this to change the endpoint
489
471
  * that will be called.
490
472
  */
491
- url() {
473
+ get url(): string {
474
+ if (this._url) return this._url;
475
+
492
476
  const base = result(this, 'urlRoot') || result(this.collection, 'url') || urlError();
493
- if (this.isNew()) return base;
477
+ if (this.isNew()) return base as string;
494
478
  const id = this.get(this.idAttribute);
495
- return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id);
479
+ return (base as string).replace(/[^\/]$/, '$&/') + encodeURIComponent(String(id));
480
+ }
481
+
482
+ set url(url: string) {
483
+ this._url = url;
496
484
  }
497
485
 
498
486
  /**
499
487
  * **parse** converts a response into the hash of attributes to be `set` on
500
488
  * the model. The default implementation is just to pass the response along.
501
- * @param {Options} resp
502
- * @param {Options} [options]
503
489
  */
504
- parse(resp, options) {
490
+ parse(resp: any, options?: ModelOptions): Partial<T> | null | void {
505
491
  return resp;
506
492
  }
507
493
 
508
494
  /**
509
495
  * A model is new if it has never been saved to the server, and lacks an id.
510
496
  */
511
- isNew() {
497
+ isNew(): boolean {
512
498
  return !this.has(this.idAttribute);
513
499
  }
514
500
 
515
501
  /**
516
502
  * Check if the model is currently in a valid state.
517
- * @param {Options} [options]
518
503
  */
519
- isValid(options) {
504
+ isValid(options?: ModelOptions): boolean {
520
505
  return this._validate({}, Object.assign({}, options, { validate: true }));
521
506
  }
522
507
 
523
508
  /**
524
509
  * Run validation against the next complete set of model attributes,
525
510
  * returning `true` if all is well. Otherwise, fire an `"invalid"` event.
526
- * @param {Attributes} attrs
527
- * @param {Options} [options]
528
511
  */
529
- _validate(attrs, options) {
530
- if (!options.validate || !this.validate) return true;
512
+ _validate(attrs: Partial<T> | ObjectWithId, options?: ModelOptions): boolean {
513
+ if (!options?.validate || !this.validate) return true;
531
514
  attrs = Object.assign({}, this.attributes, attrs);
532
515
  const error = (this.validationError = this.validate(attrs, options) || null);
533
516
  if (!error) return true;
@@ -535,5 +518,3 @@ class Model extends EventEmitter(Object) {
535
518
  return false;
536
519
  }
537
520
  }
538
-
539
- export { Model };