@d1g1tal/subscribr 1.0.0 → 3.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.
package/README.md CHANGED
@@ -1,2 +1,61 @@
1
1
  # subscribr
2
2
  JavaScript Publish/Subscribe
3
+
4
+ This simple class enables you to subscribe and publish events using the Observer pattern.
5
+
6
+ Basically, you subscribe your event handler using the `Subscribr` instance and are returned a `Subscription` instance.
7
+
8
+ When the event is published, your event handler will be called.
9
+
10
+ ### Installation:
11
+ ```bash
12
+ npm install @d1g1tal/subscribr --save
13
+ ```
14
+ Or Script tags from downloaded script or from a NPM CDN like jsDelivr
15
+
16
+ ```html
17
+ <!-- Load as global script -->
18
+ <script src="/app/js/subscribr.min.js"></script>
19
+
20
+ <!-- Load from CDN -->
21
+ <script src="https://cdn.jsdelivr.net/npm/@d1g1tal/subscribr@2/dist/browser/subscribr.min.js"></script>
22
+ ```
23
+
24
+ ### Usage:
25
+ ```javascript
26
+ // ES Module
27
+ import Subscribr from '@d1g1tal/subscribr';
28
+
29
+ const subscribr = new Subscribr();
30
+ const eventName = 'myEvent';
31
+
32
+ // Subscribr.prototype.subscribe returns a Subscription object.
33
+ const mySubscription = subscribr.subscribe(eventName, (event, data) => console.log(`Event: '${event.type}' published with data: ${data}`));
34
+
35
+ // Publish the event with just the name and a CustomEvent will be created with the eventName. All handlers that have subscribed are called
36
+ subscribr.publish(eventName, { foo: 'bar', zip: 'fizz' }); // Event: 'myEvent' published with data: { foo: 'bar', zip: 'fizz' }
37
+
38
+ // Is the event subscribed?
39
+ const isSubscribed = subscribr.isSubscribed(mySubscription); // true
40
+
41
+ const isUnsubscribed = subscribr.unsubscribe(mySubscription); // true
42
+
43
+ const isSubscribed = subscribr.isSubscribed(mySubscription); // false
44
+
45
+
46
+ // Subscribe to a DOM event
47
+ const eventTargetSubscription = subsribr.subscribe('eventTargetChanged', (event, data) => console.log(`Event target changed with data: ${data}`));
48
+
49
+ // Add some event to an event target (DOMElement)
50
+ new EventTarget().addEventListener('change', function(event) {
51
+ // Publish the event and all handlers that have subscribed are called
52
+ subscribr.publish('eventTargetChanged', event, { value: this.value }); // Event target changed with data: {value: 'new value'}
53
+ });
54
+
55
+ // Is the event subscribed?
56
+ const isSubscribed = subscribr.isSubscribed(eventTargetSubscription); // true
57
+
58
+ const isUnsubscribed = subscribr.unsubscribe(eventTargetSubscription); // true
59
+
60
+ const isSubscribed = subscribr.isSubscribed(eventTargetSubscription); // false
61
+ ```
@@ -0,0 +1,106 @@
1
+ var Subscribr = (() => {
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/subscribr.js
21
+ var subscribr_exports = {};
22
+ __export(subscribr_exports, {
23
+ default: () => Subscribr
24
+ });
25
+
26
+ // node_modules/@d1g1tal/collections/src/set-multi-map.js
27
+ var SetMultiMap = class extends Map {
28
+ set(key, value) {
29
+ super.set(key, (super.get(key) ?? /* @__PURE__ */ new Set()).add(value));
30
+ return this;
31
+ }
32
+ [Symbol.toStringTag]() {
33
+ return "SetMultiMap";
34
+ }
35
+ };
36
+
37
+ // src/context-event-handler.js
38
+ var ContextEventHandler = class {
39
+ #context;
40
+ #eventHandler;
41
+ constructor(context, eventHandler) {
42
+ this.#context = context;
43
+ this.#eventHandler = eventHandler;
44
+ }
45
+ handle(event, data) {
46
+ this.#eventHandler.call(this.#context, event, data);
47
+ }
48
+ get [Symbol.toStringTag]() {
49
+ return "ContextEventHandler";
50
+ }
51
+ };
52
+
53
+ // src/subscription.js
54
+ var Subscription = class {
55
+ #eventName;
56
+ #contextEventHandler;
57
+ constructor(eventName, contextEventHandler) {
58
+ this.#eventName = eventName;
59
+ this.#contextEventHandler = contextEventHandler;
60
+ }
61
+ get eventName() {
62
+ return this.#eventName;
63
+ }
64
+ get contextEventHandler() {
65
+ return this.#contextEventHandler;
66
+ }
67
+ get [Symbol.toStringTag]() {
68
+ return "Subscription";
69
+ }
70
+ };
71
+
72
+ // src/subscribr.js
73
+ var Subscribr = class {
74
+ #subscribers;
75
+ constructor() {
76
+ this.#subscribers = new SetMultiMap();
77
+ }
78
+ subscribe(eventName, eventHandler, context = eventHandler) {
79
+ const contextEventHandler = new ContextEventHandler(context, eventHandler);
80
+ this.#subscribers.set(eventName, contextEventHandler);
81
+ return new Subscription(eventName, contextEventHandler);
82
+ }
83
+ unsubscribe({ eventName, contextEventHandler }) {
84
+ const contextEventHandlers = this.#subscribers.get(eventName);
85
+ const removed = contextEventHandlers?.delete(contextEventHandler);
86
+ if (removed && contextEventHandlers.size == 0) {
87
+ this.#subscribers.delete(eventName);
88
+ }
89
+ return removed;
90
+ }
91
+ publish(eventName, event = new CustomEvent(eventName), data) {
92
+ if (data == null && !(event instanceof Event)) {
93
+ [data, event] = [event, new CustomEvent(eventName)];
94
+ }
95
+ this.#subscribers.get(eventName)?.forEach((contextEventHandler) => contextEventHandler.handle(event, data));
96
+ }
97
+ isSubscribed({ eventName, contextEventHandler }) {
98
+ return this.#subscribers.get(eventName)?.has(contextEventHandler);
99
+ }
100
+ get [Symbol.toStringTag]() {
101
+ return "Subscribr";
102
+ }
103
+ };
104
+ return __toCommonJS(subscribr_exports);
105
+ })();
106
+ window.Subscribr = Subscribr.default;
@@ -0,0 +1,3 @@
1
+ var Subscribr=(()=>{var c=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var g=Object.prototype.hasOwnProperty;var d=(s,t)=>{for(var e in t)c(s,e,{get:t[e],enumerable:!0})},b=(s,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of h(t))!g.call(s,r)&&r!==e&&c(s,r,{get:()=>t[r],enumerable:!(n=a(t,r))||n.enumerable});return s};var p=s=>b(c({},"__esModule",{value:!0}),s);var S={};d(S,{default:()=>l});var o=class extends Map{set(t,e){return super.set(t,(super.get(t)??new Set).add(e)),this}[Symbol.toStringTag](){return"SetMultiMap"}};var i=class{#t;#e;constructor(t,e){this.#t=t,this.#e=e}handle(t,e){this.#e.call(this.#t,t,e)}get[Symbol.toStringTag](){return"ContextEventHandler"}};var u=class{#t;#e;constructor(t,e){this.#t=t,this.#e=e}get eventName(){return this.#t}get contextEventHandler(){return this.#e}get[Symbol.toStringTag](){return"Subscription"}};var l=class{#t;constructor(){this.#t=new o}subscribe(t,e,n=e){let r=new i(n,e);return this.#t.set(t,r),new u(t,r)}unsubscribe({eventName:t,contextEventHandler:e}){let n=this.#t.get(t),r=n?.delete(e);return r&&n.size==0&&this.#t.delete(t),r}publish(t,e=new CustomEvent(t),n){n==null&&!(e instanceof Event)&&([n,e]=[e,new CustomEvent(t)]),this.#t.get(t)?.forEach(r=>r.handle(e,n))}isSubscribed({eventName:t,contextEventHandler:e}){return this.#t.get(t)?.has(e)}get[Symbol.toStringTag](){return"Subscribr"}};return p(S);})();
2
+ window.Subscribr = Subscribr.default;
3
+ //# sourceMappingURL=subscribr.min.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/subscribr.js", "../../node_modules/@d1g1tal/collections/src/set-multi-map.js", "../../src/context-event-handler.js", "../../src/subscription.js"],
4
+ "sourcesContent": ["import SetMultiMap from '@d1g1tal/collections/set-multi-map.js';\nimport ContextEventHandler from './context-event-handler.js';\nimport Subscription from './subscription.js';\n\nexport default class Subscribr {\n\t/** @type {SetMultiMap<string, ContextEventHandler>} */\n\t#subscribers;\n\n\tconstructor() {\n\t\tthis.#subscribers = new SetMultiMap();\n\t}\n\n\t/**\n\t * Subscribe to an event\n\t *\n\t * @param {string} eventName The event name to subscribe to.\n\t * @param {function(Event, *): void} eventHandler The event handler to call when the event is published.\n\t * @param {*} [context] The context to bind to the event handler.\n\t * @returns {Subscription} An object used to check if the subscription still exists and to unsubscribe from the event.\n\t */\n\tsubscribe(eventName, eventHandler, context = eventHandler) {\n\t\tconst contextEventHandler = new ContextEventHandler(context, eventHandler);\n\t\tthis.#subscribers.set(eventName, contextEventHandler);\n\n\t\treturn new Subscription(eventName, contextEventHandler);\n\t}\n\n\t/**\n\t * Unsubscribe from the event\n\t *\n\t * @param {Subscription} subscription The subscription to unsubscribe.\n\t * @param {string} subscription.eventName The event name to subscribe to.\n\t * @param {ContextEventHandler} subscription.contextEventHandler The event handler to call when the event is published.\n\t * @returns {boolean} true if eventListener has been removed successfully. false if the value is not found or if the value is not an object.\n\t */\n\tunsubscribe({ eventName, contextEventHandler }) {\n\t\tconst contextEventHandlers = this.#subscribers.get(eventName);\n\t\tconst removed = contextEventHandlers?.delete(contextEventHandler);\n\n\t\tif (removed && contextEventHandlers.size == 0) {\n\t\t\tthis.#subscribers.delete(eventName);\n\t\t}\n\n\t\treturn removed;\n\t}\n\n\t/**\n\t * Publish an event\n\t *\n\t * @param {string} eventName The name of the event.\n\t * @param {Event} event The event to be handled.\n\t * @param {*} [data] The value to be passed to the event handler as a parameter.\n\t */\n\tpublish(eventName, event = new CustomEvent(eventName), data) {\n\t\tif (data == null && !(event instanceof Event)) {\n\t\t\t[data, event] = [event, new CustomEvent(eventName)];\n\t\t}\n\t\tthis.#subscribers.get(eventName)?.forEach((contextEventHandler) => contextEventHandler.handle(event, data));\n\t}\n\n\t/**\n\t * Check if the event and handler are subscribed.\n\t *\n\t * @param {Subscription} subscription The subscription object.\n\t * @param {string} subscription.eventName The name of the event to check.\n\t * @param {ContextEventHandler} subscription.contextEventHandler The event handler to check.\n\t * @returns {boolean} true if the event name and handler are subscribed, false otherwise.\n\t */\n\tisSubscribed({ eventName, contextEventHandler }) {\n\t\treturn this.#subscribers.get(eventName)?.has(contextEventHandler);\n\t}\n\n\tget [Symbol.toStringTag]() {\n\t\treturn 'Subscribr';\n\t}\n}", "/**\n *\n * @typedef {Map<*, *>} SetMultiMap\n * @extends Map\n */\nexport default class SetMultiMap extends Map {\n\t/**\n\t * Adds a new element with a specified key and value to the SetMultiMap. If an element with the same key already exists, the value will be added to the underlying {@link Set}.\n\t *\n\t * @param {*} key The key to set.\n\t * @param {*} value The value to add to the SetMultiMap\n\t * @returns {SetMultiMap} The SetMultiMap with the updated key and value.\n\t */\n\tset(key, value) {\n\t\tsuper.set(key, (super.get(key) ?? new Set()).add(value));\n\n\t\treturn this;\n\t}\n\n\t[Symbol.toStringTag]() {\n\t\treturn 'SetMultiMap';\n\t}\n}", "export default class ContextEventHandler {\n\t#context;\n\t#eventHandler;\n\n\t/**\n\t * @param {*} context The context to bind to the event handler.\n\t * @param {function(*): void} eventHandler The event handler to call when the event is published.\n\t */\n\tconstructor(context, eventHandler) {\n\t\tthis.#context = context;\n\t\tthis.#eventHandler = eventHandler;\n\t}\n\n\t/**\n\t * Call the event handler for the provided event.\n\t *\n\t * @param {Event} event The event to handle\n\t * @param {*} [data] The value to be passed to the event handler as a parameter.\n\t */\n\thandle(event, data) {\n\t\tthis.#eventHandler.call(this.#context, event, data);\n\t}\n\n\tget [Symbol.toStringTag]() {\n\t\treturn 'ContextEventHandler';\n\t}\n}", "// eslint-disable-next-line jsdoc/valid-types\n/** @typedef {import('./context-event-handler.js').default} ContextEventHandler */\n\nexport default class Subscription {\n\t#eventName;\n\t#contextEventHandler;\n\n\t/**\n\t * @param {string} eventName The event name.\n\t * @param {ContextEventHandler} contextEventHandler Then context event handler.\n\t */\n\tconstructor(eventName, contextEventHandler) {\n\t\tthis.#eventName = eventName;\n\t\tthis.#contextEventHandler = contextEventHandler;\n\t}\n\n\t/**\n\t * Gets the event name for the subscription.\n\t *\n\t * @returns {string} The event name.\n\t */\n\tget eventName() {\n\t\treturn this.#eventName;\n\t}\n\n\t/**\n\t * Gets the context event handler.\n\t *\n\t * @returns {ContextEventHandler} The context event handler\n\t */\n\tget contextEventHandler() {\n\t\treturn this.#contextEventHandler;\n\t}\n\n\tget [Symbol.toStringTag]() {\n\t\treturn 'Subscription';\n\t}\n}"],
5
+ "mappings": "gbAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,ICKA,IAAqBC,EAArB,cAAyC,GAAI,CAQ5C,IAAIC,EAAKC,EAAO,CACf,aAAM,IAAID,GAAM,MAAM,IAAIA,CAAG,GAAK,IAAI,KAAO,IAAIC,CAAK,CAAC,EAEhD,IACR,CAEA,CAAC,OAAO,cAAe,CACtB,MAAO,aACR,CACD,ECtBA,IAAqBC,EAArB,KAAyC,CACxCC,GACAC,GAMA,YAAYC,EAASC,EAAc,CAClC,KAAKH,GAAWE,EAChB,KAAKD,GAAgBE,CACtB,CAQA,OAAOC,EAAOC,EAAM,CACnB,KAAKJ,GAAc,KAAK,KAAKD,GAAUI,EAAOC,CAAI,CACnD,CAEA,IAAK,OAAO,cAAe,CAC1B,MAAO,qBACR,CACD,ECvBA,IAAqBC,EAArB,KAAkC,CACjCC,GACAC,GAMA,YAAYC,EAAWC,EAAqB,CAC3C,KAAKH,GAAaE,EAClB,KAAKD,GAAuBE,CAC7B,CAOA,IAAI,WAAY,CACf,OAAO,KAAKH,EACb,CAOA,IAAI,qBAAsB,CACzB,OAAO,KAAKC,EACb,CAEA,IAAK,OAAO,cAAe,CAC1B,MAAO,cACR,CACD,EHjCA,IAAqBG,EAArB,KAA+B,CAE9BC,GAEA,aAAc,CACb,KAAKA,GAAe,IAAIC,CACzB,CAUA,UAAUC,EAAWC,EAAcC,EAAUD,EAAc,CAC1D,IAAME,EAAsB,IAAIC,EAAoBF,EAASD,CAAY,EACzE,YAAKH,GAAa,IAAIE,EAAWG,CAAmB,EAE7C,IAAIE,EAAaL,EAAWG,CAAmB,CACvD,CAUA,YAAY,CAAE,UAAAH,EAAW,oBAAAG,CAAoB,EAAG,CAC/C,IAAMG,EAAuB,KAAKR,GAAa,IAAIE,CAAS,EACtDO,EAAUD,GAAsB,OAAOH,CAAmB,EAEhE,OAAII,GAAWD,EAAqB,MAAQ,GAC3C,KAAKR,GAAa,OAAOE,CAAS,EAG5BO,CACR,CASA,QAAQP,EAAWQ,EAAQ,IAAI,YAAYR,CAAS,EAAGS,EAAM,CACxDA,GAAQ,MAAQ,EAAED,aAAiB,SACtC,CAACC,EAAMD,CAAK,EAAI,CAACA,EAAO,IAAI,YAAYR,CAAS,CAAC,GAEnD,KAAKF,GAAa,IAAIE,CAAS,GAAG,QAASG,GAAwBA,EAAoB,OAAOK,EAAOC,CAAI,CAAC,CAC3G,CAUA,aAAa,CAAE,UAAAT,EAAW,oBAAAG,CAAoB,EAAG,CAChD,OAAO,KAAKL,GAAa,IAAIE,CAAS,GAAG,IAAIG,CAAmB,CACjE,CAEA,IAAK,OAAO,cAAe,CAC1B,MAAO,WACR,CACD",
6
+ "names": ["subscribr_exports", "__export", "Subscribr", "SetMultiMap", "key", "value", "ContextEventHandler", "#context", "#eventHandler", "context", "eventHandler", "event", "data", "Subscription", "#eventName", "#contextEventHandler", "eventName", "contextEventHandler", "Subscribr", "#subscribers", "SetMultiMap", "eventName", "eventHandler", "context", "contextEventHandler", "ContextEventHandler", "Subscription", "contextEventHandlers", "removed", "event", "data"]
7
+ }
Binary file
@@ -0,0 +1,81 @@
1
+ // node_modules/@d1g1tal/collections/src/set-multi-map.js
2
+ var SetMultiMap = class extends Map {
3
+ set(key, value) {
4
+ super.set(key, (super.get(key) ?? /* @__PURE__ */ new Set()).add(value));
5
+ return this;
6
+ }
7
+ [Symbol.toStringTag]() {
8
+ return "SetMultiMap";
9
+ }
10
+ };
11
+
12
+ // src/context-event-handler.js
13
+ var ContextEventHandler = class {
14
+ #context;
15
+ #eventHandler;
16
+ constructor(context, eventHandler) {
17
+ this.#context = context;
18
+ this.#eventHandler = eventHandler;
19
+ }
20
+ handle(event, data) {
21
+ this.#eventHandler.call(this.#context, event, data);
22
+ }
23
+ get [Symbol.toStringTag]() {
24
+ return "ContextEventHandler";
25
+ }
26
+ };
27
+
28
+ // src/subscription.js
29
+ var Subscription = class {
30
+ #eventName;
31
+ #contextEventHandler;
32
+ constructor(eventName, contextEventHandler) {
33
+ this.#eventName = eventName;
34
+ this.#contextEventHandler = contextEventHandler;
35
+ }
36
+ get eventName() {
37
+ return this.#eventName;
38
+ }
39
+ get contextEventHandler() {
40
+ return this.#contextEventHandler;
41
+ }
42
+ get [Symbol.toStringTag]() {
43
+ return "Subscription";
44
+ }
45
+ };
46
+
47
+ // src/subscribr.js
48
+ var Subscribr = class {
49
+ #subscribers;
50
+ constructor() {
51
+ this.#subscribers = new SetMultiMap();
52
+ }
53
+ subscribe(eventName, eventHandler, context = eventHandler) {
54
+ const contextEventHandler = new ContextEventHandler(context, eventHandler);
55
+ this.#subscribers.set(eventName, contextEventHandler);
56
+ return new Subscription(eventName, contextEventHandler);
57
+ }
58
+ unsubscribe({ eventName, contextEventHandler }) {
59
+ const contextEventHandlers = this.#subscribers.get(eventName);
60
+ const removed = contextEventHandlers?.delete(contextEventHandler);
61
+ if (removed && contextEventHandlers.size == 0) {
62
+ this.#subscribers.delete(eventName);
63
+ }
64
+ return removed;
65
+ }
66
+ publish(eventName, event = new CustomEvent(eventName), data) {
67
+ if (data == null && !(event instanceof Event)) {
68
+ [data, event] = [event, new CustomEvent(eventName)];
69
+ }
70
+ this.#subscribers.get(eventName)?.forEach((contextEventHandler) => contextEventHandler.handle(event, data));
71
+ }
72
+ isSubscribed({ eventName, contextEventHandler }) {
73
+ return this.#subscribers.get(eventName)?.has(contextEventHandler);
74
+ }
75
+ get [Symbol.toStringTag]() {
76
+ return "Subscribr";
77
+ }
78
+ };
79
+ export {
80
+ Subscribr as default
81
+ };
@@ -0,0 +1,2 @@
1
+ var n=class extends Map{set(t,e){return super.set(t,(super.get(t)??new Set).add(e)),this}[Symbol.toStringTag](){return"SetMultiMap"}};var o=class{#t;#e;constructor(t,e){this.#t=t,this.#e=e}handle(t,e){this.#e.call(this.#t,t,e)}get[Symbol.toStringTag](){return"ContextEventHandler"}};var i=class{#t;#e;constructor(t,e){this.#t=t,this.#e=e}get eventName(){return this.#t}get contextEventHandler(){return this.#e}get[Symbol.toStringTag](){return"Subscription"}};var l=class{#t;constructor(){this.#t=new n}subscribe(t,e,r=e){let s=new o(r,e);return this.#t.set(t,s),new i(t,s)}unsubscribe({eventName:t,contextEventHandler:e}){let r=this.#t.get(t),s=r?.delete(e);return s&&r.size==0&&this.#t.delete(t),s}publish(t,e=new CustomEvent(t),r){r==null&&!(e instanceof Event)&&([r,e]=[e,new CustomEvent(t)]),this.#t.get(t)?.forEach(s=>s.handle(e,r))}isSubscribed({eventName:t,contextEventHandler:e}){return this.#t.get(t)?.has(e)}get[Symbol.toStringTag](){return"Subscribr"}};export{l as default};
2
+ //# sourceMappingURL=subscribr.min.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../node_modules/@d1g1tal/collections/src/set-multi-map.js", "../../src/context-event-handler.js", "../../src/subscription.js", "../../src/subscribr.js"],
4
+ "sourcesContent": ["/**\n *\n * @typedef {Map<*, *>} SetMultiMap\n * @extends Map\n */\nexport default class SetMultiMap extends Map {\n\t/**\n\t * Adds a new element with a specified key and value to the SetMultiMap. If an element with the same key already exists, the value will be added to the underlying {@link Set}.\n\t *\n\t * @param {*} key The key to set.\n\t * @param {*} value The value to add to the SetMultiMap\n\t * @returns {SetMultiMap} The SetMultiMap with the updated key and value.\n\t */\n\tset(key, value) {\n\t\tsuper.set(key, (super.get(key) ?? new Set()).add(value));\n\n\t\treturn this;\n\t}\n\n\t[Symbol.toStringTag]() {\n\t\treturn 'SetMultiMap';\n\t}\n}", "export default class ContextEventHandler {\n\t#context;\n\t#eventHandler;\n\n\t/**\n\t * @param {*} context The context to bind to the event handler.\n\t * @param {function(*): void} eventHandler The event handler to call when the event is published.\n\t */\n\tconstructor(context, eventHandler) {\n\t\tthis.#context = context;\n\t\tthis.#eventHandler = eventHandler;\n\t}\n\n\t/**\n\t * Call the event handler for the provided event.\n\t *\n\t * @param {Event} event The event to handle\n\t * @param {*} [data] The value to be passed to the event handler as a parameter.\n\t */\n\thandle(event, data) {\n\t\tthis.#eventHandler.call(this.#context, event, data);\n\t}\n\n\tget [Symbol.toStringTag]() {\n\t\treturn 'ContextEventHandler';\n\t}\n}", "// eslint-disable-next-line jsdoc/valid-types\n/** @typedef {import('./context-event-handler.js').default} ContextEventHandler */\n\nexport default class Subscription {\n\t#eventName;\n\t#contextEventHandler;\n\n\t/**\n\t * @param {string} eventName The event name.\n\t * @param {ContextEventHandler} contextEventHandler Then context event handler.\n\t */\n\tconstructor(eventName, contextEventHandler) {\n\t\tthis.#eventName = eventName;\n\t\tthis.#contextEventHandler = contextEventHandler;\n\t}\n\n\t/**\n\t * Gets the event name for the subscription.\n\t *\n\t * @returns {string} The event name.\n\t */\n\tget eventName() {\n\t\treturn this.#eventName;\n\t}\n\n\t/**\n\t * Gets the context event handler.\n\t *\n\t * @returns {ContextEventHandler} The context event handler\n\t */\n\tget contextEventHandler() {\n\t\treturn this.#contextEventHandler;\n\t}\n\n\tget [Symbol.toStringTag]() {\n\t\treturn 'Subscription';\n\t}\n}", "import SetMultiMap from '@d1g1tal/collections/set-multi-map.js';\nimport ContextEventHandler from './context-event-handler.js';\nimport Subscription from './subscription.js';\n\nexport default class Subscribr {\n\t/** @type {SetMultiMap<string, ContextEventHandler>} */\n\t#subscribers;\n\n\tconstructor() {\n\t\tthis.#subscribers = new SetMultiMap();\n\t}\n\n\t/**\n\t * Subscribe to an event\n\t *\n\t * @param {string} eventName The event name to subscribe to.\n\t * @param {function(Event, *): void} eventHandler The event handler to call when the event is published.\n\t * @param {*} [context] The context to bind to the event handler.\n\t * @returns {Subscription} An object used to check if the subscription still exists and to unsubscribe from the event.\n\t */\n\tsubscribe(eventName, eventHandler, context = eventHandler) {\n\t\tconst contextEventHandler = new ContextEventHandler(context, eventHandler);\n\t\tthis.#subscribers.set(eventName, contextEventHandler);\n\n\t\treturn new Subscription(eventName, contextEventHandler);\n\t}\n\n\t/**\n\t * Unsubscribe from the event\n\t *\n\t * @param {Subscription} subscription The subscription to unsubscribe.\n\t * @param {string} subscription.eventName The event name to subscribe to.\n\t * @param {ContextEventHandler} subscription.contextEventHandler The event handler to call when the event is published.\n\t * @returns {boolean} true if eventListener has been removed successfully. false if the value is not found or if the value is not an object.\n\t */\n\tunsubscribe({ eventName, contextEventHandler }) {\n\t\tconst contextEventHandlers = this.#subscribers.get(eventName);\n\t\tconst removed = contextEventHandlers?.delete(contextEventHandler);\n\n\t\tif (removed && contextEventHandlers.size == 0) {\n\t\t\tthis.#subscribers.delete(eventName);\n\t\t}\n\n\t\treturn removed;\n\t}\n\n\t/**\n\t * Publish an event\n\t *\n\t * @param {string} eventName The name of the event.\n\t * @param {Event} event The event to be handled.\n\t * @param {*} [data] The value to be passed to the event handler as a parameter.\n\t */\n\tpublish(eventName, event = new CustomEvent(eventName), data) {\n\t\tif (data == null && !(event instanceof Event)) {\n\t\t\t[data, event] = [event, new CustomEvent(eventName)];\n\t\t}\n\t\tthis.#subscribers.get(eventName)?.forEach((contextEventHandler) => contextEventHandler.handle(event, data));\n\t}\n\n\t/**\n\t * Check if the event and handler are subscribed.\n\t *\n\t * @param {Subscription} subscription The subscription object.\n\t * @param {string} subscription.eventName The name of the event to check.\n\t * @param {ContextEventHandler} subscription.contextEventHandler The event handler to check.\n\t * @returns {boolean} true if the event name and handler are subscribed, false otherwise.\n\t */\n\tisSubscribed({ eventName, contextEventHandler }) {\n\t\treturn this.#subscribers.get(eventName)?.has(contextEventHandler);\n\t}\n\n\tget [Symbol.toStringTag]() {\n\t\treturn 'Subscribr';\n\t}\n}"],
5
+ "mappings": "AAKA,IAAqBA,EAArB,cAAyC,GAAI,CAQ5C,IAAIC,EAAKC,EAAO,CACf,aAAM,IAAID,GAAM,MAAM,IAAIA,CAAG,GAAK,IAAI,KAAO,IAAIC,CAAK,CAAC,EAEhD,IACR,CAEA,CAAC,OAAO,cAAe,CACtB,MAAO,aACR,CACD,ECtBA,IAAqBC,EAArB,KAAyC,CACxCC,GACAC,GAMA,YAAYC,EAASC,EAAc,CAClC,KAAKH,GAAWE,EAChB,KAAKD,GAAgBE,CACtB,CAQA,OAAOC,EAAOC,EAAM,CACnB,KAAKJ,GAAc,KAAK,KAAKD,GAAUI,EAAOC,CAAI,CACnD,CAEA,IAAK,OAAO,cAAe,CAC1B,MAAO,qBACR,CACD,ECvBA,IAAqBC,EAArB,KAAkC,CACjCC,GACAC,GAMA,YAAYC,EAAWC,EAAqB,CAC3C,KAAKH,GAAaE,EAClB,KAAKD,GAAuBE,CAC7B,CAOA,IAAI,WAAY,CACf,OAAO,KAAKH,EACb,CAOA,IAAI,qBAAsB,CACzB,OAAO,KAAKC,EACb,CAEA,IAAK,OAAO,cAAe,CAC1B,MAAO,cACR,CACD,ECjCA,IAAqBG,EAArB,KAA+B,CAE9BC,GAEA,aAAc,CACb,KAAKA,GAAe,IAAIC,CACzB,CAUA,UAAUC,EAAWC,EAAcC,EAAUD,EAAc,CAC1D,IAAME,EAAsB,IAAIC,EAAoBF,EAASD,CAAY,EACzE,YAAKH,GAAa,IAAIE,EAAWG,CAAmB,EAE7C,IAAIE,EAAaL,EAAWG,CAAmB,CACvD,CAUA,YAAY,CAAE,UAAAH,EAAW,oBAAAG,CAAoB,EAAG,CAC/C,IAAMG,EAAuB,KAAKR,GAAa,IAAIE,CAAS,EACtDO,EAAUD,GAAsB,OAAOH,CAAmB,EAEhE,OAAII,GAAWD,EAAqB,MAAQ,GAC3C,KAAKR,GAAa,OAAOE,CAAS,EAG5BO,CACR,CASA,QAAQP,EAAWQ,EAAQ,IAAI,YAAYR,CAAS,EAAGS,EAAM,CACxDA,GAAQ,MAAQ,EAAED,aAAiB,SACtC,CAACC,EAAMD,CAAK,EAAI,CAACA,EAAO,IAAI,YAAYR,CAAS,CAAC,GAEnD,KAAKF,GAAa,IAAIE,CAAS,GAAG,QAASG,GAAwBA,EAAoB,OAAOK,EAAOC,CAAI,CAAC,CAC3G,CAUA,aAAa,CAAE,UAAAT,EAAW,oBAAAG,CAAoB,EAAG,CAChD,OAAO,KAAKL,GAAa,IAAIE,CAAS,GAAG,IAAIG,CAAmB,CACjE,CAEA,IAAK,OAAO,cAAe,CAC1B,MAAO,WACR,CACD",
6
+ "names": ["SetMultiMap", "key", "value", "ContextEventHandler", "#context", "#eventHandler", "context", "eventHandler", "event", "data", "Subscription", "#eventName", "#contextEventHandler", "eventName", "contextEventHandler", "Subscribr", "#subscribers", "SetMultiMap", "eventName", "eventHandler", "context", "contextEventHandler", "ContextEventHandler", "Subscription", "contextEventHandlers", "removed", "event", "data"]
7
+ }
package/dist/esm.zip ADDED
Binary file
package/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { default as ContextEventHandler } from "./src/context-event-handler.js";
2
+ export { default as Subscribr } from "./src/subscribr.js";
3
+ export { default as Subscription } from "./src/subscription.js";
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export {default as ContextEventHandler} from './src/context-event-handler.js';
2
+ export {default as Subscribr} from './src/subscribr.js';
3
+ export {default as Subscription} from './src/subscription.js';
package/package.json CHANGED
@@ -1,16 +1,31 @@
1
1
  {
2
2
  "name": "@d1g1tal/subscribr",
3
- "version": "1.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "JavaScript Publish/Subscribe Library",
5
5
  "type": "module",
6
- "main": "./src/subscribr.js",
7
- "module": "./src/subscribr.js",
8
- "publishConfig": {
6
+ "types": "index.d.js",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./src/subscribr.js",
10
+ "default": "./dist/browser/subscribr.min.js"
11
+ }
12
+ },
13
+ "publishConfig": {
9
14
  "access": "public"
10
15
  },
16
+ "files": [
17
+ "/src",
18
+ "/dist",
19
+ "index.js",
20
+ "index.d.ts"
21
+ ],
11
22
  "scripts": {
12
- "build": "rimraf dist && esbuild src/subscribr.js --bundle --sourcemap --minify --target=es2022 --format=esm --outfile=dist/esm/subscribr.min.js && esbuild src/subscribr.js --bundle --sourcemap --minify --target=es2022 --platform=browser --global-name=Subscribr --outfile=dist/browser/subscribr.min.js",
13
- "test": "echo \"Error: no test specified\" && exit 1"
23
+ "build": "npm run build:esm && npm run build:browser",
24
+ "build:esm": "rimraf dist/esm && esbuild src/subscribr.js --bundle --target=es2022 --format=esm --outfile=dist/esm/subscribr.js && esbuild src/subscribr.js --bundle --sourcemap --minify --target=es2022 --format=esm --outfile=dist/esm/subscribr.min.js",
25
+ "build:browser": "rimraf dist/browser && esbuild src/subscribr.js --bundle --target=es2022 --platform=browser --global-name=Subscribr --footer:js='window.Subscribr = Subscribr.default;' --outfile=dist/browser/subscribr.js && esbuild src/subscribr.js --bundle --sourcemap --minify --target=es2022 --platform=browser --global-name=Subscribr --footer:js='window.Subscribr = Subscribr.default;' --outfile=dist/browser/subscribr.min.js",
26
+ "lint": "eslint --ext .js --fix --ignore-path .gitignore .",
27
+ "d.ts": "tsc --allowJs -declaration --emitDeclarationOnly --skipLibCheck --lib esnext index.js",
28
+ "test": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js"
14
29
  },
15
30
  "repository": {
16
31
  "type": "git",
@@ -28,8 +43,31 @@
28
43
  },
29
44
  "homepage": "https://github.com/D1g1talEntr0py/subscribr#readme",
30
45
  "devDependencies": {
31
- "esbuild": "^0.15.7",
32
- "eslint": "^8.23.1",
46
+ "@d1g1tal/chrysalis": "^1.1.7",
47
+ "@skypack/package-check": "^0.2.2",
48
+ "esbuild": "^0.15.12",
49
+ "eslint": "^8.26.0",
50
+ "eslint-plugin-compat": "^4.0.2",
51
+ "eslint-plugin-jsdoc": "^39.3.21",
52
+ "jest": "^29.2.1",
33
53
  "rimraf": "^3.0.2"
54
+ },
55
+ "jest": {
56
+ "verbose": true,
57
+ "transform": {},
58
+ "coverageDirectory": "./tests/coverage/",
59
+ "coveragePathIgnorePatterns": [
60
+ "/node_modules/"
61
+ ],
62
+ "collectCoverage": true,
63
+ "collectCoverageFrom": [
64
+ "src/**/*.js"
65
+ ]
66
+ },
67
+ "browserslist": [
68
+ "defaults"
69
+ ],
70
+ "dependencies": {
71
+ "@d1g1tal/collections": "^0.0.4"
34
72
  }
35
73
  }
@@ -0,0 +1,22 @@
1
+ export default class ContextEventHandler {
2
+ /**
3
+ * @param {*} context The context to bind to the event handler.
4
+ * @param {function(*): void} eventHandler The event handler to call when the event is published.
5
+ */
6
+ constructor(context: any, eventHandler: (arg0: any) => void);
7
+ /**
8
+ * Call the event handler for the provided event.
9
+ *
10
+ * @param {Event} event The event to handle
11
+ * @param {*} [data] The value to be passed to the event handler as a parameter.
12
+ */
13
+ handle(event: Event, data?: any): void;
14
+ /**
15
+ * Get the event handler
16
+ *
17
+ * @returns {function(*)} The event handler
18
+ */
19
+ get eventHandler(): (arg0: any) => any;
20
+ get [Symbol.toStringTag](): string;
21
+ #private;
22
+ }
@@ -0,0 +1,27 @@
1
+ export default class ContextEventHandler {
2
+ #context;
3
+ #eventHandler;
4
+
5
+ /**
6
+ * @param {*} context The context to bind to the event handler.
7
+ * @param {function(*): void} eventHandler The event handler to call when the event is published.
8
+ */
9
+ constructor(context, eventHandler) {
10
+ this.#context = context;
11
+ this.#eventHandler = eventHandler;
12
+ }
13
+
14
+ /**
15
+ * Call the event handler for the provided event.
16
+ *
17
+ * @param {Event} event The event to handle
18
+ * @param {*} [data] The value to be passed to the event handler as a parameter.
19
+ */
20
+ handle(event, data) {
21
+ this.#eventHandler.call(this.#context, event, data);
22
+ }
23
+
24
+ get [Symbol.toStringTag]() {
25
+ return 'ContextEventHandler';
26
+ }
27
+ }
@@ -0,0 +1,40 @@
1
+ export default class Subscribr {
2
+ /**
3
+ * Subscribe to an event
4
+ *
5
+ * @param {string} eventName The event name to subscribe to.
6
+ * @param {function(Event, *): void} eventHandler The event handler to call when the event is published.
7
+ * @param {*} [context] The context to bind to the event handler.
8
+ * @returns {Subscription} An object used to check if the subscription still exists and to unsubscribe from the event.
9
+ */
10
+ subscribe(eventName: string, eventHandler: (arg0: Event, arg1: any) => void, context?: any): Subscription;
11
+ /**
12
+ * Unsubscribe from the event
13
+ *
14
+ * @param {Subscription} subscription The subscription to unsubscribe.
15
+ * @param {string} subscription.eventName The event name to subscribe to.
16
+ * @param {ContextEventHandler} subscription.contextEventHandler The event handler to call when the event is published.
17
+ * @returns {boolean} true if eventListener has been removed successfully. false if the value is not found or if the value is not an object.
18
+ */
19
+ unsubscribe({ eventName, contextEventHandler }: Subscription): boolean;
20
+ /**
21
+ * Publish an event
22
+ *
23
+ * @param {string} eventName The name of the event.
24
+ * @param {Event} event The event to be handled.
25
+ * @param {*} [data] The value to be passed to the event handler as a parameter.
26
+ */
27
+ publish(eventName: string, event?: Event, data?: any): void;
28
+ /**
29
+ * Check if the event and handler are subscribed.
30
+ *
31
+ * @param {Subscription} subscription The subscription object.
32
+ * @param {string} subscription.eventName The name of the event to check.
33
+ * @param {ContextEventHandler} subscription.contextEventHandler The event handler to check.
34
+ * @returns {boolean} true if the event name and handler are subscribed, false otherwise.
35
+ */
36
+ isSubscribed({ eventName, contextEventHandler }: Subscription): boolean;
37
+ get [Symbol.toStringTag](): string;
38
+ #private;
39
+ }
40
+ import Subscription from "./subscription.js";
package/src/subscribr.js CHANGED
@@ -1,48 +1,77 @@
1
+ import SetMultiMap from '@d1g1tal/collections/set-multi-map.js';
2
+ import ContextEventHandler from './context-event-handler.js';
3
+ import Subscription from './subscription.js';
4
+
1
5
  export default class Subscribr {
2
- /** @type {Map.<string, Array.<function(Event, Object):undefined>>} */
3
- #subscribers;
6
+ /** @type {SetMultiMap<string, ContextEventHandler>} */
7
+ #subscribers;
4
8
 
5
- constructor() {
6
- this.#subscribers = new Map();
7
- }
9
+ constructor() {
10
+ this.#subscribers = new SetMultiMap();
11
+ }
8
12
 
9
13
  /**
10
14
  * Subscribe to an event
11
15
  *
12
- * @param {string} eventType
13
- * @param {function(Event, Object):undefined} eventListener
14
- * @return {{unsubscribe: function()}}
16
+ * @param {string} eventName The event name to subscribe to.
17
+ * @param {function(Event, *): void} eventHandler The event handler to call when the event is published.
18
+ * @param {*} [context] The context to bind to the event handler.
19
+ * @returns {Subscription} An object used to check if the subscription still exists and to unsubscribe from the event.
15
20
  */
16
- subscribe(eventType, eventListener) {
17
- if (!this.#subscribers.has(eventType)) {
18
- this.#subscribers.set(eventType, []);
19
- }
21
+ subscribe(eventName, eventHandler, context = eventHandler) {
22
+ const contextEventHandler = new ContextEventHandler(context, eventHandler);
23
+ this.#subscribers.set(eventName, contextEventHandler);
24
+
25
+ return new Subscription(eventName, contextEventHandler);
26
+ }
27
+
28
+ /**
29
+ * Unsubscribe from the event
30
+ *
31
+ * @param {Subscription} subscription The subscription to unsubscribe.
32
+ * @param {string} subscription.eventName The event name to subscribe to.
33
+ * @param {ContextEventHandler} subscription.contextEventHandler The event handler to call when the event is published.
34
+ * @returns {boolean} true if eventListener has been removed successfully. false if the value is not found or if the value is not an object.
35
+ */
36
+ unsubscribe({ eventName, contextEventHandler }) {
37
+ const contextEventHandlers = this.#subscribers.get(eventName);
38
+ const removed = contextEventHandlers?.delete(contextEventHandler);
20
39
 
21
- const subscribr = this;
22
- const index = this.#subscribers.get(eventType).push(eventListener) - 1;
40
+ if (removed && contextEventHandlers.size == 0) {
41
+ this.#subscribers.delete(eventName);
42
+ }
23
43
 
24
- return {
25
- /**
26
- * Unsubscribe from the event
27
- */
28
- unsubscribe: () => subscribr.#subscribers.get(eventType).splice(index, 1)
29
- };
44
+ return removed;
30
45
  }
31
46
 
32
47
  /**
33
48
  * Publish an event
34
49
  *
35
- * @param {string} eventType
36
- * @param {Event} [event=new CustomEvent(eventType)]
37
- * @param {Object} [data]
50
+ * @param {string} eventName The name of the event.
51
+ * @param {Event} event The event to be handled.
52
+ * @param {*} [data] The value to be passed to the event handler as a parameter.
38
53
  */
39
- publish(eventType, event = new CustomEvent(eventType), data) {
40
- if (!this.#subscribers.has(eventType)) {
41
- return;
54
+ publish(eventName, event = new CustomEvent(eventName), data) {
55
+ if (data == null && !(event instanceof Event)) {
56
+ // Swap the event and data parameters becuase only data was passesed without an event object
57
+ [data, event] = [event, new CustomEvent(eventName)];
42
58
  }
59
+ this.#subscribers.get(eventName)?.forEach((contextEventHandler) => contextEventHandler.handle(event, data));
60
+ }
61
+
62
+ /**
63
+ * Check if the event and handler are subscribed.
64
+ *
65
+ * @param {Subscription} subscription The subscription object.
66
+ * @param {string} subscription.eventName The name of the event to check.
67
+ * @param {ContextEventHandler} subscription.contextEventHandler The event handler to check.
68
+ * @returns {boolean} true if the event name and handler are subscribed, false otherwise.
69
+ */
70
+ isSubscribed({ eventName, contextEventHandler }) {
71
+ return this.#subscribers.get(eventName)?.has(contextEventHandler);
72
+ }
43
73
 
44
- this.#subscribers.get(eventType).forEach(function(eventListener) {
45
- eventListener.call(this, event, data);
46
- });
74
+ get [Symbol.toStringTag]() {
75
+ return 'Subscribr';
47
76
  }
48
77
  }
@@ -0,0 +1,23 @@
1
+ /** @typedef {import('./context-event-handler.js').default} ContextEventHandler */
2
+ export default class Subscription {
3
+ /**
4
+ * @param {string} eventName The event name.
5
+ * @param {ContextEventHandler} contextEventHandler Then context event handler.
6
+ */
7
+ constructor(eventName: string, contextEventHandler: ContextEventHandler);
8
+ /**
9
+ * Gets the event name for the subscription.
10
+ *
11
+ * @returns {string} The event name.
12
+ */
13
+ get eventName(): string;
14
+ /**
15
+ * Gets the context event handler.
16
+ *
17
+ * @returns {ContextEventHandler} The context event handler
18
+ */
19
+ get contextEventHandler(): import("./context-event-handler.js").default;
20
+ get [Symbol.toStringTag](): string;
21
+ #private;
22
+ }
23
+ export type ContextEventHandler = import('./context-event-handler.js').default;
@@ -0,0 +1,38 @@
1
+ // eslint-disable-next-line jsdoc/valid-types
2
+ /** @typedef {import('./context-event-handler.js').default} ContextEventHandler */
3
+
4
+ export default class Subscription {
5
+ #eventName;
6
+ #contextEventHandler;
7
+
8
+ /**
9
+ * @param {string} eventName The event name.
10
+ * @param {ContextEventHandler} contextEventHandler Then context event handler.
11
+ */
12
+ constructor(eventName, contextEventHandler) {
13
+ this.#eventName = eventName;
14
+ this.#contextEventHandler = contextEventHandler;
15
+ }
16
+
17
+ /**
18
+ * Gets the event name for the subscription.
19
+ *
20
+ * @returns {string} The event name.
21
+ */
22
+ get eventName() {
23
+ return this.#eventName;
24
+ }
25
+
26
+ /**
27
+ * Gets the context event handler.
28
+ *
29
+ * @returns {ContextEventHandler} The context event handler
30
+ */
31
+ get contextEventHandler() {
32
+ return this.#contextEventHandler;
33
+ }
34
+
35
+ get [Symbol.toStringTag]() {
36
+ return 'Subscription';
37
+ }
38
+ }
package/.eslintrc.js DELETED
@@ -1,16 +0,0 @@
1
- export default {
2
- "env": {
3
- "browser": true,
4
- "es2021": true,
5
- "node": true
6
- },
7
- "extends": "eslint:recommended",
8
- "overrides": [
9
- ],
10
- "parserOptions": {
11
- "ecmaVersion": "latest",
12
- "sourceType": "module"
13
- },
14
- "rules": {
15
- }
16
- }
@@ -1,6 +0,0 @@
1
- {
2
- "cSpell.words": [
3
- "esbuild",
4
- "Subscribr"
5
- ]
6
- }
package/esbuild.js DELETED
File without changes
package/jsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "baseUrl": ".",
4
- "module": "es2020",
5
- "target": "es2020",
6
- "checkJs": true
7
- },
8
- "include": [ "./*", "src/**/*", "tests/*.js" ],
9
- "exclude": [ "node_modules", "dist" ]
10
- }