@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,9 +1,12 @@
1
- // (c) 2010-2019 Jeremy Ashkenas and DocumentCloud
2
-
3
- import create from 'lodash-es/create.js';
4
- import extend from 'lodash-es/extend.js';
5
- import has from 'lodash-es/has.js';
6
- import result from 'lodash-es/result.js';
1
+ // (c) 2010-2019 Jeremy Ashkenas and DocumentCloud
2
+ // (c) 2018-2025 JC Brand
3
+ import create from 'lodash-es/create';
4
+ import extend from 'lodash-es/extend';
5
+ import has from 'lodash-es/has';
6
+ import result from 'lodash-es/result';
7
+ import { Model } from './model';
8
+ import { Collection } from './collection';
9
+ import { type SyncOptions, SyncOperation } from './types';
7
10
 
8
11
  /**
9
12
  * Custom error for indicating timeouts
@@ -11,12 +14,12 @@ import result from 'lodash-es/result.js';
11
14
  */
12
15
  export class NotImplementedError extends Error {}
13
16
 
14
- function S4() {
17
+ function S4(): string {
15
18
  // Generate four random hex digits.
16
19
  return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
17
20
  }
18
21
 
19
- export function guid() {
22
+ export function guid(): string {
20
23
  // Generate a pseudo-GUID by concatenating random hexadecimal.
21
24
  return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4();
22
25
  }
@@ -28,10 +31,13 @@ export function guid() {
28
31
  // Similar to `goog.inherits`, but uses a hash of prototype properties and
29
32
  // class properties to be extended.
30
33
  //
31
- export function inherits(protoProps, staticProps) {
34
+ export function inherits<T extends new (...args: any[]) => any>(
35
+ protoProps: Record<string, any> | null,
36
+ staticProps?: Record<string, any>
37
+ ): T {
32
38
  // eslint-disable-next-line @typescript-eslint/no-this-alias
33
39
  const parent = this;
34
- let child;
40
+ let child: T;
35
41
 
36
42
  // The constructor function for the new subclass is either defined by you
37
43
  // (the "constructor" property in your `extend` definition), or defaulted
@@ -39,9 +45,9 @@ export function inherits(protoProps, staticProps) {
39
45
  if (protoProps && has(protoProps, 'constructor')) {
40
46
  child = protoProps.constructor;
41
47
  } else {
42
- child = function () {
43
- return parent.apply(this, arguments);
44
- };
48
+ child = function (this: any, ...args: any[]) {
49
+ return parent.apply(this, args);
50
+ } as unknown as T;
45
51
  }
46
52
 
47
53
  // Add static properties to the constructor function, if supplied.
@@ -54,23 +60,23 @@ export function inherits(protoProps, staticProps) {
54
60
 
55
61
  // Set a convenience property in case the parent's prototype is needed
56
62
  // later.
57
- child.__super__ = parent.prototype;
63
+ (child as any).__super__ = parent.prototype;
58
64
 
59
65
  return child;
60
66
  }
61
67
 
62
- export function getResolveablePromise() {
63
- /**
64
- * @typedef {Object} PromiseWrapper
65
- * @property {boolean} isResolved
66
- * @property {boolean} isPending
67
- * @property {boolean} isRejected
68
- * @property {Function} resolve
69
- * @property {Function} reject
70
- */
71
-
72
- /** @type {PromiseWrapper} */
73
- const wrapper = {
68
+ interface PromiseWrapper {
69
+ isResolved: boolean;
70
+ isPending: boolean;
71
+ isRejected: boolean;
72
+ resolve: ((value?: any) => void) | null;
73
+ reject: ((reason?: any) => void) | null;
74
+ }
75
+
76
+ type ResolveablePromise = Promise<any> & PromiseWrapper;
77
+
78
+ export function getResolveablePromise(): ResolveablePromise {
79
+ const wrapper: PromiseWrapper = {
74
80
  isResolved: false,
75
81
  isPending: true,
76
82
  isRejected: false,
@@ -78,16 +84,11 @@ export function getResolveablePromise() {
78
84
  reject: null,
79
85
  };
80
86
 
81
- /**
82
- * @typedef {Promise & PromiseWrapper} ResolveablePromise
83
- */
87
+ const promise = new Promise((resolve, reject) => {
88
+ wrapper.resolve = resolve;
89
+ wrapper.reject = reject;
90
+ }) as ResolveablePromise;
84
91
 
85
- const promise = /** @type {ResolveablePromise} */ (
86
- new Promise((resolve, reject) => {
87
- wrapper.resolve = resolve;
88
- wrapper.reject = reject;
89
- })
90
- );
91
92
  Object.assign(promise, wrapper);
92
93
  promise.then(
93
94
  function (v) {
@@ -101,27 +102,27 @@ export function getResolveablePromise() {
101
102
  promise.isPending = false;
102
103
  promise.isRejected = true;
103
104
  throw e;
104
- },
105
+ }
105
106
  );
106
107
  return promise;
107
108
  }
108
109
 
109
110
  // Throw an error when a URL is needed, and none is supplied.
110
- export function urlError() {
111
+ export function urlError(): never {
111
112
  throw new Error('A "url" property or function must be specified');
112
113
  }
113
114
 
114
115
  // Wrap an optional error callback with a fallback error event.
115
- export function wrapError(model, options) {
116
+ export function wrapError(model: Model<any> | Collection<any>, options: any): void {
116
117
  const error = options.error;
117
- options.error = function (resp) {
118
+ options.error = function (resp: any) {
118
119
  if (error) error.call(options.context, model, resp, options);
119
120
  model.trigger('error', model, resp, options);
120
121
  };
121
122
  }
122
123
 
123
124
  // Map from CRUD to HTTP for our default `sync` implementation.
124
- const methodMap = {
125
+ const methodMap: Record<string, string> = {
125
126
  create: 'POST',
126
127
  update: 'PUT',
127
128
  patch: 'PATCH',
@@ -129,30 +130,11 @@ const methodMap = {
129
130
  read: 'GET',
130
131
  };
131
132
 
132
- /**
133
- * @typedef {import('./model.js').Model} Model
134
- * @typedef {import('./collection.js').Collection} Collection
135
- */
136
-
137
-
138
- /**
139
- * @param {Model | Collection} model
140
- */
141
- export function getSyncMethod(model) {
142
- const store = result(model, 'browserStorage') || result(/** @type {Model} */(model).collection, 'browserStorage');
143
- return store ? store.sync() : sync;
133
+ export function getSyncMethod(model: Model | Collection<any>): typeof sync & { __name__?: string } {
134
+ const store = result(model, 'browserStorage') || result((model as Model).collection, 'browserStorage');
135
+ return store ? (store as any).sync() : sync;
144
136
  }
145
137
 
146
- /**
147
- * @typedef {Object} SyncOptions
148
- * @property {string} [url]
149
- * @property {any} [data]
150
- * @property {any} [attrs]
151
- * @property {Function} [success]
152
- * @property {Function} [error]
153
- * @property {any} [xhr]
154
- */
155
-
156
138
  /**
157
139
  * Override this function to change the manner in which Backbone persists
158
140
  * models to the server. You will be passed the type of request, and the
@@ -164,12 +146,11 @@ export function getSyncMethod(model) {
164
146
  * - Use `setTimeout` to batch rapid-fire updates into a single request.
165
147
  * - Persist models via WebSockets instead of Ajax.
166
148
  * - Persist models to browser storage
167
- *
168
- * @param {'create'|'update'|'patch'} method
169
- * @param {import('./model.js').Model} model
170
- * @param {SyncOptions} [options]
171
149
  */
172
- export function sync(method, model, options = {}) {
150
+ /**
151
+ * @public
152
+ */
153
+ export function sync(method: SyncOperation, model: Model | Collection<any>, options: SyncOptions = {}): Promise<any> {
173
154
  let data = options.data;
174
155
 
175
156
  // Ensure that we have the appropriate request data.
@@ -178,15 +159,21 @@ export function sync(method, model, options = {}) {
178
159
  }
179
160
 
180
161
  const type = methodMap[method];
181
- const params = {
162
+ const params: RequestInit & { success?: any; error?: any } = {
182
163
  method: type,
183
164
  body: data ? JSON.stringify(data) : '',
165
+ headers: {
166
+ 'Content-Type': 'application/json',
167
+ },
184
168
  success: options.success,
185
169
  error: options.error,
186
170
  };
187
171
 
188
172
  const url = options.url || result(model, 'url') || urlError();
189
- const xhr = (options.xhr = fetch(url, params));
173
+ const xhr = fetch(url, params);
174
+ if (options) {
175
+ options.xhr = xhr;
176
+ }
190
177
  model.trigger('request', model, xhr, { ...params, xhr });
191
178
  return xhr;
192
179
  }
package/src/index.ts ADDED
@@ -0,0 +1,84 @@
1
+ /* global global */
2
+ import { EventEmitter } from './eventemitter';
3
+ import Storage from './storage';
4
+ import { Collection } from './collection';
5
+ import { Model } from './model';
6
+ import { sync } from './helpers';
7
+
8
+ /**
9
+ * @public
10
+ */
11
+ interface SkeletorType {
12
+ Collection: typeof Collection;
13
+ EventEmitter: typeof EventEmitter;
14
+ Model: typeof Model;
15
+ sync: typeof sync;
16
+ VERSION?: string;
17
+ noConflict?: () => SkeletorType;
18
+ }
19
+
20
+ /**
21
+ * @public
22
+ */
23
+ const skeletor: SkeletorType = {
24
+ Collection,
25
+ EventEmitter,
26
+ Model,
27
+ sync,
28
+ };
29
+
30
+ // Establish the root object, `window` (`self`) in the browser, or `global` on the server.
31
+ // We use `self` instead of `window` for `WebWorker` support.
32
+ const root =
33
+ (typeof self == 'object' && self.self === self && self) ||
34
+ (typeof global == 'object' && global.global === global && global);
35
+
36
+ // Current version of the library. Keep in sync with `package.json`.
37
+ skeletor.VERSION = '0.0.1';
38
+
39
+ // Save the previous value of the `Skeletor` variable, so that it can be
40
+ // restored later on, if `noConflict` is used.
41
+ const previousSkeletor = root.Skeletor;
42
+
43
+ // Runs Skeletor.js in *noConflict* mode, returning the `Skeletor` variable
44
+ // to its previous owner. Returns a reference to this Skeletor object.
45
+ /**
46
+ * @public
47
+ */
48
+ function noConflict() {
49
+ root.Skeletor = previousSkeletor;
50
+ return this;
51
+ }
52
+ skeletor.noConflict = noConflict;
53
+
54
+ root.Skeletor = skeletor;
55
+ export default skeletor;
56
+
57
+ export { noConflict, Collection, EventEmitter, Model, Storage, sync };
58
+
59
+ export type { LocalForageWithExtensions } from './storage';
60
+ export type {
61
+ ClassConstructor,
62
+ CollectionOptions,
63
+ Comparator,
64
+ EventCallback,
65
+ EventCallbackMap,
66
+ EventContext,
67
+ EventHandlersMap,
68
+ EventListenerMap,
69
+ ModelAttributes,
70
+ ModelOptions,
71
+ ObjectListenedTo,
72
+ ObjectWithId,
73
+ Options,
74
+ SyncOperation,
75
+ SyncOptions,
76
+ EventHandler,
77
+ ListeningType,
78
+ IEventEmitter,
79
+ ListeningMap,
80
+ } from './types';
81
+
82
+ export type { CollectionIterator } from './collection';
83
+ export type { SkeletorType };
84
+ export type { EventEmitterObject } from './eventemitter';
@@ -1,19 +1,26 @@
1
- import { eventsApi, onApi, offApi } from './utils/events.js';
1
+ import { eventsApi, onApi, offApi } from './utils/events';
2
+ import type {
3
+ EventCallback,
4
+ IEventEmitter,
5
+ EventCallbackMap,
6
+ EventsApiOptions,
7
+ ListeningType,
8
+ } from './types';
2
9
 
3
10
  /**
4
11
  * A listening class that tracks and cleans up memory bindings
5
12
  * when all callbacks have been offed.
6
13
  */
7
- class Listening {
14
+ class Listening implements ListeningType {
15
+ id: string;
16
+ listener: IEventEmitter;
17
+ obj: any;
18
+ interop: boolean;
19
+ count: number;
20
+ _events?: EventCallbackMap;
8
21
 
9
- /** @typedef {import('./eventemitter.js').default} EventEmitter */
10
-
11
- /**
12
- * @param {any} listener
13
- * @param {any} obj
14
- */
15
- constructor(listener, obj) {
16
- this.id = listener._listenId;
22
+ constructor(listener: IEventEmitter, obj: any) {
23
+ this.id = listener._listenId!;
17
24
  this.listener = listener;
18
25
  this.obj = obj;
19
26
  this.interop = true;
@@ -21,18 +28,14 @@ class Listening {
21
28
  this._events = undefined;
22
29
  }
23
30
 
24
- /**
25
- * @param {string} name
26
- * @param {Function} callback
27
- * @param {any} context
28
- * @param {Listening} _listening
29
- */
30
- start(name, callback, context, _listening) {
31
- this._events = eventsApi(onApi, this._events || {}, name, callback, {
31
+ start(name: string | EventCallbackMap, callback: EventCallback, context: any, _listening: ListeningType): this {
32
+ const options: EventsApiOptions = {
32
33
  context: this.obj,
33
34
  ctx: context,
34
35
  listening: _listening,
35
- });
36
+ };
37
+
38
+ this._events = eventsApi(onApi, this._events || {}, name, callback, options) as EventCallbackMap;
36
39
 
37
40
  if (_listening) {
38
41
  const listeners = this.obj._listeners || (this.obj._listeners = {});
@@ -51,16 +54,14 @@ class Listening {
51
54
  * Uses an optimized counter if the listenee uses Backbone.Events.
52
55
  * Otherwise, falls back to manual tracking to support events
53
56
  * library interop.
54
- * @param {string} name
55
- * @param {Function} callback
56
57
  */
57
- stop(name, callback) {
58
- let cleanup;
58
+ stop(name: string | EventCallbackMap, callback: EventCallback): void {
59
+ let cleanup: boolean;
59
60
  if (this.interop) {
60
61
  this._events = eventsApi(offApi, this._events, name, callback, {
61
62
  context: undefined,
62
63
  listeners: undefined,
63
- });
64
+ }) as EventCallbackMap;
64
65
  cleanup = !this._events;
65
66
  } else {
66
67
  this.count--;
@@ -72,9 +73,13 @@ class Listening {
72
73
  /**
73
74
  * Cleans up memory bindings between the listener and the listenee.
74
75
  */
75
- cleanup() {
76
- delete this.listener._listeningTo[this.obj._listenId];
77
- if (!this.interop) delete this.obj._listeners[this.id];
76
+ cleanup(): void {
77
+ if (this.listener._listeningTo) {
78
+ delete this.listener._listeningTo[this.obj._listenId!];
79
+ }
80
+ if (!this.interop && this.obj._listeners) {
81
+ delete this.obj._listeners[this.id];
82
+ }
78
83
  }
79
84
  }
80
85