hermes-io 2.2.41 → 2.3.42

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
@@ -21,9 +21,6 @@ Install from chrome web store [here](https://chrome.google.com/webstore/detail/h
21
21
 
22
22
  ![chrome extension](https://raw.githubusercontent.com/Maxtermax/hermes-io-devtools/master/demo.gif)
23
23
 
24
- ## Documentation:
25
- https://github.com/Maxtermax/hermes-io#readme
26
-
27
24
  ## Contributing:
28
25
  Feel free to open a PR explaining your changes, this library is open to suggestions and improvements.
29
26
 
@@ -0,0 +1,41 @@
1
+ import { vi } from 'vitest';
2
+ import { Context } from "../src/context/context";
3
+
4
+ describe("Context", () => {
5
+ let context;
6
+
7
+ beforeEach(() => {
8
+ context = new Context("Test Description");
9
+ });
10
+
11
+ afterEach(() => {
12
+ context = null;
13
+ });
14
+
15
+ test("update method updates context properties", () => {
16
+ const value = "test value";
17
+ const listener = vi.fn();
18
+ context.update({ value, listener });
19
+
20
+ expect(context.date).toBeInstanceOf(Date);
21
+ expect(context.value).toBe(value);
22
+ expect(context.listener).toBe(listener);
23
+ expect(context.stackTrace).toEqual(expect.any(String));
24
+ });
25
+
26
+ test("takeSnapshot method returns a snapshot object", () => {
27
+ const snapshot = context.takeSnapshot();
28
+
29
+ expect(snapshot._internalId).toEqual(expect.any(String));
30
+ expect(snapshot.value).toBe(context.value);
31
+ expect(snapshot.date).toBe(context.date);
32
+ expect(snapshot.listener).toBe(context.listener);
33
+ expect(snapshot.stackTrace).toBe(context.stackTrace);
34
+ });
35
+
36
+ test("getStackTrace method returns stack trace", () => {
37
+ const stackTrace = context.getStackTrace();
38
+
39
+ expect(stackTrace).toEqual(expect.any(String));
40
+ });
41
+ });
@@ -0,0 +1,34 @@
1
+ import { Observer } from "../src/observer/observer";
2
+
3
+ describe("Observer", () => {
4
+ let observer;
5
+ let callback1;
6
+ let callback2;
7
+
8
+ beforeEach(() => {
9
+ observer = new Observer();
10
+ callback1 = vi.fn();
11
+ callback2 = vi.fn();
12
+ });
13
+
14
+ afterEach(() => {
15
+ observer = null;
16
+ callback1 = null;
17
+ callback2 = null;
18
+ });
19
+
20
+ it("subscribe and notify", () => {
21
+ observer.subscribe(callback1);
22
+ observer.subscribe(callback2);
23
+ const args = { data: "test" };
24
+ observer.notify(args);
25
+ expect(callback1).toHaveBeenCalledWith(args, expect.any(Function));
26
+ expect(callback2).toHaveBeenCalledWith(args, expect.any(Function));
27
+ });
28
+
29
+ it("unsubscribe", async () => {
30
+ observer.subscribe(callback1);
31
+ observer.unsubscribe(callback1);
32
+ expect(callback1).not.toHaveBeenCalled();
33
+ });
34
+ });
@@ -0,0 +1,63 @@
1
+ import { renderHook, act } from "@testing-library/react-hooks/dom";
2
+ import { Context, listenersMap } from "../src/context/context";
3
+ import { Observer, useObserver } from "../src/observer/observer";
4
+ import { test } from "vitest";
5
+
6
+ // Mock the observer object and its methods
7
+ const mockObserver = {
8
+ subscribe: vi.fn(),
9
+ unsubscribe: vi.fn(),
10
+ };
11
+
12
+ describe("useObserver", () => {
13
+ let context;
14
+ beforeEach(() => {
15
+ context = new Context("Test");
16
+ });
17
+
18
+ afterEach(() => {
19
+ listenersMap.clear();
20
+ vi.clearAllMocks();
21
+ context = null;
22
+ });
23
+
24
+ test("should subscribe and unsubscribe to observer ", async () => {
25
+ const observer = new Observer();
26
+ const listener = vi.fn();
27
+ const contexts = [context];
28
+ const { unmount } = await renderHook(() => {
29
+ const hook = useObserver({ observer, listener, contexts });
30
+ expect(observer.subscriptors.length).toBe(1);
31
+ return hook;
32
+ });
33
+ await act(() => unmount());
34
+ expect(observer.subscriptors.length).toBe(0);
35
+ });
36
+
37
+ it("should add and remove listener from listenersMap", async () => {
38
+ const observer = new Observer();
39
+ const listener = vi.fn();
40
+ const { unmount } = await renderHook(() => {
41
+ const hook = useObserver({ observer, listener, contexts: [context] });
42
+ expect(listenersMap.size).toBe(1);
43
+ return hook;
44
+ });
45
+ await act(() => unmount());
46
+ expect(listenersMap.size).toBe(0);
47
+ });
48
+
49
+ it("should call listener on notification", async () => {
50
+ const observer = mockObserver;
51
+ const listener = vi.fn();
52
+ renderHook(() => {
53
+ useObserver({ observer, listener, contexts: [context] });
54
+ observer.notify({
55
+ context,
56
+ value: {
57
+ test: true,
58
+ },
59
+ });
60
+ expect(listener).toHaveBeenCalledTimes(1);
61
+ });
62
+ });
63
+ });
@@ -0,0 +1,20 @@
1
+ import { test, expect } from "vitest";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { withNotify } from "../src/components/withNotify/withNotify";
4
+ import { Context } from "../src/context/context";
5
+ import { Observer } from "../src/observer/observer";
6
+
7
+ const TestContext = new Context("Test");
8
+ const TestObserver = new Observer();
9
+
10
+ const Wrapper = withNotify((props) => <h1>{Object.keys(props)}</h1>, {
11
+ context: TestContext,
12
+ observer: TestObserver,
13
+ });
14
+
15
+ test("Should add ", () => {
16
+ render(<Wrapper />);
17
+ const node = screen.getByText(/notify/gi);
18
+ expect(node).toBeInTheDocument();
19
+ })
20
+
@@ -0,0 +1,36 @@
1
+ import { test, expect } from "vitest";
2
+ import { render, screen, waitFor } from "@testing-library/react";
3
+ import { withReactive } from "../src/components/withReactive/withReactive";
4
+ import { Context } from "../src/context/context";
5
+ import { Observer } from "../src/observer/observer";
6
+
7
+ const TestContext = new Context("Test");
8
+ const TestObserver = new Observer();
9
+
10
+ const Wrapper = withReactive({
11
+ context: TestContext,
12
+ observer: TestObserver,
13
+ values: {
14
+ title: "test",
15
+ },
16
+ });
17
+
18
+ test("Should Renders the component correctly", () => {
19
+ render(<Wrapper id="test" render={({ title }) => <h1>{title}</h1>} />);
20
+ const node = screen.getByText(/test/gi);
21
+ expect(node).toBeInTheDocument();
22
+ });
23
+
24
+ test("Should re-render on notification", async () => {
25
+ await render(<Wrapper id="test2" render={({ title }) => <h1>{title}</h1>} />);
26
+ TestObserver.notify({
27
+ context: TestContext,
28
+ value: {
29
+ type: "test2",
30
+ value: { title: "new title" },
31
+ },
32
+ });
33
+ await waitFor(() =>
34
+ expect(screen.getByText(/new title/gi)).toBeInTheDocument()
35
+ );
36
+ });
@@ -0,0 +1 @@
1
+ function _extends(){return(_extends=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t}).apply(this,arguments)}import t from"react";export function withNotify(e,n){var r=n.context,o=n.observer,i=function(t){return o.notify({context:r,value:t})};return function(n){return t.createElement(e,_extends({notify:i},n))}}
@@ -0,0 +1 @@
1
+ function _extends(){return(_extends=Object.assign||function(e){for(var r=1;r<arguments.length;r++){var t=arguments[r];for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])}return e}).apply(this,arguments)}import{useObserver as e}from"../../hooks/useObserver";import r,{useState as t}from"react";export function withReactive(n){var o=n.context,a=n.observer,i=n.values,u=void 0===i?{}:i;return function(n){var i=t(!1),s=(i[0],i[1]);return e({listener:function(e){var r=e.value,t=r.type,o=r.value;n.id===t&&(u=_extends({},u,o),s(function(e){return!e}))},contexts:[o],observer:a}),r.createElement(r.Fragment,null,n.render(u))}}
@@ -1 +1 @@
1
- function _extends(){return(_extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e}).apply(this,arguments)}import e from"../constants";var _obj,recording=!1,collection=[];export var listenersMap=new Map;var actions=((_obj={})[e.START_RECORDING]=function(){recording=!0},_obj[e.STOP_RECORDING]=function(){recording=!1},_obj[e.RESET_RECORDING]=function(){collection=[],recording=!1},_obj[e.SET_CONTEXT]=function(t){var n=t.id,r=void 0===n?"":n,a=collection.find(function(e){return e._internalId===r});if(a){if(a.isFromExternalRecording){var i=listenersMap.get(a.listener);return null==i?void 0:i({value:JSON.parse(a.value)})}return a.listener(a.value)}},_obj[e.LOAD_RECORDING]=function(t){collection=t.recording.map(function(e){return void 0===e&&(e={}),_extends({},e,{isFromExternalRecording:!0,_internalId:e.id})})},_obj);window.addEventListener("message",function(t){try{var n=t.data,r=n.source,a=n.payload;if(r===e.CHROME_EXTENSION){if(null==a?void 0:a.type)return actions[a.type](a);actions[a]()}}catch(e){console.error(e)}});export var Context=function(t){var n=this;this.id=null,this._internalId=null,this.date=null,this.value=null,this.listener=null,this.stackTrace=null,this.update=function(e){var t=e.value,r=e.listener;n.date=new Date,n.value=t,n.stackTrace=n.getStackTrace(),n.listener=r,recording&&n.sendSnapshot()},this.sendSnapshot=function(){var t=n.takeSnapshot(),r=t.listener,a=t.stackTrace,i=t.value,o=t.date,s=t._internalId;collection.push(t),window.postMessage({type:e.CONTEXT_SNAPSHOT,payload:{value:JSON.stringify(i.value),listener:r.name,stackTrace:a,date:o,id:s},source:"hermes-io"},"*")},this.takeSnapshot=function(){return{_internalId:crypto.randomUUID(),value:n.value,date:n.date,listener:n.listener,stackTrace:n.stackTrace}},this.getStackTrace=function(){return Error().stack},this.id=Symbol(t)};
1
+ function _extends(){return(_extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e}).apply(this,arguments)}import e from"../constants";var _obj,recording=!1,collection=[];export var listenersMap=new Map;var actions=((_obj={})[e.START_RECORDING]=function(){recording=!0},_obj[e.STOP_RECORDING]=function(){recording=!1},_obj[e.RESET_RECORDING]=function(){collection=[],recording=!1},_obj[e.SET_CONTEXT]=function(e){var t=e.id,n=void 0===t?"":t,r=collection.find(function(e){return e._internalId===n});if(r){if(r.isFromExternalRecording){var a=listenersMap.get(r.listener);return null==a?void 0:a({value:JSON.parse(r.value)})}return r.listener(r.value)}},_obj[e.LOAD_RECORDING]=function(e){collection=e.recording.map(function(e){return void 0===e&&(e={}),_extends({},e,{isFromExternalRecording:!0,_internalId:e.id})})},_obj);window.addEventListener("message",function(t){try{var n=t.data,r=n.source,a=n.payload;if(r===e.CHROME_EXTENSION){if(null==a?void 0:a.type)return actions[a.type](a);actions[a]()}}catch(e){console.error(e)}});export var Context=function(t){var n=this;this.id=null,this._internalId=null,this.date=null,this.value=null,this.listener=null,this.stackTrace=null,this.update=function(e){var t=e.value,r=e.listener;n.date=new Date,n.value=t,n.stackTrace=n.getStackTrace(),n.listener=r,recording&&n.sendSnapshot()},this.sendSnapshot=function(){var t=n.takeSnapshot(),r=t.listener,a=t.stackTrace,i=t.value,o=t.date,s=t._internalId;collection.push(t),window.postMessage({type:e.CONTEXT_SNAPSHOT,payload:{value:JSON.stringify(i.value),listener:r.name,stackTrace:a,date:o,id:s},source:"hermes-io"},"*")},this.takeSnapshot=function(){return{_internalId:crypto.randomUUID(),value:n.value,date:n.date,listener:n.listener,stackTrace:n.stackTrace}},this.getStackTrace=function(){return Error().stack},this.id=Symbol(t)};
package/lib/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./hooks";export*from"./observer/observer";export*from"./context/context";
1
+ export*from"./hooks";export*from"./observer/observer";export*from"./context/context";export*from"./components/withReactive/withReactive";export*from"./components/withNotify/withNotify";
@@ -1 +1 @@
1
- export var Observer=function(){function r(){this.subscriptors=[]}var s=r.prototype;return s.subscribe=function(r){this.subscriptors.push(r)},s.unsubscribe=function(r){this.subscriptors.splice(this.subscriptors.findIndex(function(s){return s===r}),1)},s.notify=function(r){void 0===r&&(r={});var s=this;return new Promise(function(t){s.subscriptors.forEach(function(s){return s(r,t)})})},r}();
1
+ export var Observer=function(){function r(){this.subscriptors=[]}var s=r.prototype;return s.subscribe=function(r){this.subscriptors.push(r)},s.unsubscribe=function(r){this.subscriptors.splice(this.subscriptors.findIndex(function(s){return s===r}),1)},s.notify=function(r){var s=this;return void 0===r&&(r={}),new Promise(function(t){s.subscriptors.forEach(function(s){return s(r,t)})})},r}();
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "hermes-io",
3
- "version": "2.2.41",
3
+ "version": "2.3.42",
4
4
  "description": "A lightweight React library that allows communication between Reactjs components by using the observer pattern and the hook api",
5
5
  "main": "./lib/index.js",
6
6
  "module": "./lib/index.js",
7
7
  "scripts": {
8
- "test": "jest",
9
- "prepare": "swc ./src -d ./lib && cp ./utils/README.md ./README.md"
8
+ "test": "vitest __test__",
9
+ "prepare": "swc ./src -d ./lib"
10
10
  },
11
11
  "exports": {
12
12
  ".": {
@@ -26,16 +26,21 @@
26
26
  "react": "^18.2.0"
27
27
  },
28
28
  "devDependencies": {
29
- "@babel/core": "^7.22.8",
30
- "@babel/preset-env": "^7.22.7",
29
+ "@sveltejs/vite-plugin-svelte": "^3.0.2",
31
30
  "@swc/cli": "^0.1.62",
32
31
  "@swc/core": "^1.3.71",
33
- "@testing-library/jest-dom": "^5.16.5",
32
+ "@testing-library/dom": "^9.3.4",
33
+ "@testing-library/jest-dom": "^6.4.2",
34
+ "@testing-library/react": "^14.2.1",
34
35
  "@testing-library/react-hooks": "^8.0.1",
35
- "babel-jest": "^29.6.1",
36
- "jest": "^29.6.1",
37
- "jest-environment-jsdom": "^29.6.1",
36
+ "@testing-library/svelte": "^4.1.0",
37
+ "@testing-library/user-event": "^14.5.2",
38
+ "@vitejs/plugin-react": "^4.2.1",
39
+ "happy-dom": "^13.3.8",
38
40
  "react": "^18.2.0",
39
- "react-dom": "^18.2.0"
41
+ "react-dom": "^18.2.0",
42
+ "vite": "^5.1.0",
43
+ "vitest": "^1.2.2",
44
+ "@vitejs/plugin-react-swc": "^3.6.0"
40
45
  }
41
46
  }
package/vite.config.js ADDED
@@ -0,0 +1,16 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react-swc";
3
+ import * as path from "path";
4
+
5
+ // https://vitejs.dev/config/
6
+ export default defineConfig({
7
+ plugins: [react()],
8
+ resolve: {
9
+ alias: [{ find: "@", replacement: path.resolve(__dirname, "src") }],
10
+ },
11
+ test: {
12
+ globals: true,
13
+ environment: "happy-dom",
14
+ setupFiles: "./vitest-setup.js",
15
+ },
16
+ });
@@ -0,0 +1,19 @@
1
+ import '@testing-library/jest-dom/vitest';
2
+ import { render } from '@testing-library/react';
3
+
4
+ Object.defineProperty(globalThis, "crypto", {
5
+ value: {
6
+ randomUUID: () => {
7
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
8
+ /[xy]/g,
9
+ function (c) {
10
+ var r = (Math.random() * 16) | 0,
11
+ v = c === "x" ? r : (r & 0x3) | 0x8;
12
+ return v.toString(16);
13
+ }
14
+ );
15
+ },
16
+ },
17
+ });
18
+
19
+ global.render = render;
package/babel.config.js DELETED
@@ -1,15 +0,0 @@
1
- module.exports = {
2
- presets: [
3
- [
4
- "@babel/preset-env",
5
- {
6
- debug: false,
7
- useBuiltIns: "entry",
8
- corejs: 3,
9
- targets: {
10
- browsers: ["last 2 versions", "not ie > 0", "not ie_mob > 0"],
11
- },
12
- },
13
- ],
14
- ],
15
- };
package/jest.config.js DELETED
@@ -1,13 +0,0 @@
1
- module.exports = {
2
- testEnvironment: 'jsdom',
3
- transform: {
4
- '^.+\\.js$': 'babel-jest',
5
- },
6
- moduleFileExtensions: ['js', 'jsx', 'json'],
7
- testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.js?$',
8
- collectCoverageFrom: ['**/*.{js,jsx}', '!**/node_modules/**'],
9
- transformIgnorePatterns: ['<rootDir>/node_modules/'],
10
- coveragePathIgnorePatterns: ['/node_modules/', '/__tests__/'],
11
- coverageReporters: ['html', 'text-summary'],
12
- setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
13
- };
package/lib/context.js DELETED
@@ -1 +0,0 @@
1
- import CONSTANTS from"./constants";let recording=false;let collection=[];const handleMessageFromDevtools=event=>{const{source,payload}=event.data;if(source===CONSTANTS.CHROME_EXTENSION){if(payload===CONSTANTS.START_RECORDING){recording=true;return}if(payload===CONSTANTS.STOP_RECORDING){recording=false}if(payload===CONSTANTS.RESET_RECORDING){collection=[];recording=false}if(payload?.type===CONSTANTS.SET_CONTEXT){const context=collection.find(context=>context._internalId===payload.id);if(context)return context.listener(context.value)}if(payload?.type===CONSTANTS.LOAD_RECORDING){collection=payload.recording}}};window.addEventListener("message",handleMessageFromDevtools);export class Context{constructor(description){this.id=null;this._internalId=null;this.date=null;this.value=null;this.listener=null;this.stackTrace=null;this.update=({value,listener})=>{this.date=new Date;this.value=value;this.stackTrace=this.getStackTrace();this.listener=listener;if(recording){this.sendSnapshot()}};this.sendSnapshot=()=>{const snapshot=this.takeSnapshot();const{listener,stackTrace,value,date,_internalId}=snapshot;collection.push(snapshot);window.postMessage({type:CONSTANTS.CONTEXT_SNAPSHOT,payload:{value:JSON.stringify(value.value),listener:listener.name,stackTrace,date,id:_internalId},source:"hermes-io"},"*")};this.takeSnapshot=()=>{return{_internalId:crypto.randomUUID(),value:this.value,date:this.date,listener:this.listener,stackTrace:this.stackTrace}};this.getStackTrace=()=>{const err=new Error;return err.stack};this.id=Symbol(description)}}
package/lib/main.js DELETED
@@ -1 +0,0 @@
1
- export class Observer{subscribe(callback){this.subscriptors.push(callback)}unsubscribe(callback){this.subscriptors.splice(this.subscriptors.findIndex(cb=>cb===callback),1)}notify(args={}){return new Promise(resolve=>{this.subscriptors.forEach(callback=>callback(args,resolve))})}constructor(){this.subscriptors=[]}}