From 07fc35cd669fdb403d73e1c1cded63da6bc30fc5 Mon Sep 17 00:00:00 2001 From: Janne Savolainen Date: Mon, 13 Mar 2023 08:27:57 +0200 Subject: [PATCH] Extract startable-stoppable to NPM package Signed-off-by: Janne Savolainen --- package-lock.json | 30 +++++---- .../startable-stoppable/index.ts | 7 ++ .../startable-stoppable/jest.config.js | 2 + .../startable-stoppable/package.json | 29 ++++++++ .../src/get-startable-stoppable.test.ts | 66 +++++++++++++++++++ .../src/get-startable-stoppable.ts | 43 ++++++++++++ .../startable-stoppable/tsconfig.json | 3 + .../startable-stoppable/webpack.config.js | 1 + 8 files changed, 170 insertions(+), 11 deletions(-) create mode 100644 packages/utility-features/startable-stoppable/index.ts create mode 100644 packages/utility-features/startable-stoppable/jest.config.js create mode 100644 packages/utility-features/startable-stoppable/package.json create mode 100644 packages/utility-features/startable-stoppable/src/get-startable-stoppable.test.ts create mode 100644 packages/utility-features/startable-stoppable/src/get-startable-stoppable.ts create mode 100644 packages/utility-features/startable-stoppable/tsconfig.json create mode 100644 packages/utility-features/startable-stoppable/webpack.config.js diff --git a/package-lock.json b/package-lock.json index 2b313d03d2..cb6d040ff3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4738,6 +4738,10 @@ "resolved": "packages/semver", "link": true }, + "node_modules/@k8slens/startable-stoppable": { + "resolved": "packages/utility-features/startable-stoppable", + "link": true + }, "node_modules/@k8slens/test-utils": { "resolved": "packages/utility-features/test-utils", "link": true @@ -6882,7 +6886,6 @@ "version": "12.1.5", "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", - "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", "@testing-library/dom": "^8.0.0", @@ -6900,7 +6903,6 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -6918,14 +6920,12 @@ "node_modules/@testing-library/react/node_modules/@types/aria-query": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", - "dev": true + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" }, "node_modules/@testing-library/react/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "engines": { "node": ">=10" }, @@ -6937,7 +6937,6 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, "dependencies": { "deep-equal": "^2.0.5" } @@ -6946,7 +6945,6 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -7663,7 +7661,6 @@ "version": "17.0.19", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.19.tgz", "integrity": "sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ==", - "dev": true, "dependencies": { "@types/react": "^17" } @@ -37235,14 +37232,25 @@ "peerDependencies": { "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", - "@ogre-tools/fp": "^15.1.1", - "@ogre-tools/injectable": "^15.1.1" + "@ogre-tools/fp": "^15.1.2", + "@ogre-tools/injectable": "^15.1.2" } }, + "packages/utility-features/startable-stoppable": { + "version": "1.0.0-alpha.1", + "license": "MIT" + }, "packages/utility-features/test-utils": { "name": "@k8slens/test-utils", "version": "1.0.0-alpha.1", - "license": "MIT" + "license": "MIT", + "peerDependencies": { + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-react": "^15.1.2", + "@testing-library/react": "^12.1.5", + "lodash": "^4.17.21", + "react": "^17.0.2" + } }, "packages/utility-features/utilities": { "name": "@k8slens/utilities", diff --git a/packages/utility-features/startable-stoppable/index.ts b/packages/utility-features/startable-stoppable/index.ts new file mode 100644 index 0000000000..e5dddee5be --- /dev/null +++ b/packages/utility-features/startable-stoppable/index.ts @@ -0,0 +1,7 @@ +export type { + StartableStoppable, + Starter, + Stopper, +} from "./src/get-startable-stoppable"; + +export { getStartableStoppable } from "./src/get-startable-stoppable"; diff --git a/packages/utility-features/startable-stoppable/jest.config.js b/packages/utility-features/startable-stoppable/jest.config.js new file mode 100644 index 0000000000..23be80353b --- /dev/null +++ b/packages/utility-features/startable-stoppable/jest.config.js @@ -0,0 +1,2 @@ +module.exports = + require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; diff --git a/packages/utility-features/startable-stoppable/package.json b/packages/utility-features/startable-stoppable/package.json new file mode 100644 index 0000000000..d4466cae2f --- /dev/null +++ b/packages/utility-features/startable-stoppable/package.json @@ -0,0 +1,29 @@ +{ + "name": "@k8slens/startable-stoppable", + "private": false, + "version": "1.0.0-alpha.1", + "description": "TBD", + "type": "commonjs", + "files": [ + "build" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/lensapp/lens.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "build": "webpack", + "dev": "webpack --mode=development --watch", + "test:unit": "jest --coverage --runInBand", + "lint": "lens-lint", + "lint:fix": "lens-lint --fix" + } +} diff --git a/packages/utility-features/startable-stoppable/src/get-startable-stoppable.test.ts b/packages/utility-features/startable-stoppable/src/get-startable-stoppable.test.ts new file mode 100644 index 0000000000..ad9b8c6921 --- /dev/null +++ b/packages/utility-features/startable-stoppable/src/get-startable-stoppable.test.ts @@ -0,0 +1,66 @@ +import type { StartableStoppable } from "./get-startable-stoppable"; +import { getStartableStoppable } from "./get-startable-stoppable"; + +describe("getStartableStoppable", () => { + let stopMock: jest.MockedFunction<() => void>; + let startMock: jest.MockedFunction<() => () => void>; + let actual: StartableStoppable; + + beforeEach(() => { + stopMock = jest.fn(); + startMock = jest.fn().mockImplementation(() => stopMock); + actual = getStartableStoppable("some-id", startMock); + }); + + it("does not start yet", () => { + expect(startMock).not.toHaveBeenCalled(); + }); + + it("does not stop yet", () => { + expect(stopMock).not.toHaveBeenCalled(); + }); + + it("when stopping before ever starting, throws", () => { + expect(() => actual.stop()).toThrow( + 'Tried to stop "some-id", but it is already stopped.' + ); + }); + + it("is not started", () => { + expect(actual.started).toBe(false); + }); + + describe("when started", () => { + beforeEach(() => { + actual.start(); + }); + + it("calls start function", () => { + expect(startMock).toHaveBeenCalled(); + }); + + it("is started", () => { + expect(actual.started).toBe(true); + }); + + it("when started again, throws", () => { + expect(() => actual.start()).toThrow( + 'Tried to start "some-id", but it is already started.' + ); + }); + + describe("when stopped", () => { + beforeEach(() => { + actual.stop(); + }); + + it("calls stop function", () => { + expect(stopMock).toBeCalled(); + }); + + it("is stopped", () => { + expect(actual.started).toBe(false); + }); + }); + }); +}); diff --git a/packages/utility-features/startable-stoppable/src/get-startable-stoppable.ts b/packages/utility-features/startable-stoppable/src/get-startable-stoppable.ts new file mode 100644 index 0000000000..1aac8274a6 --- /dev/null +++ b/packages/utility-features/startable-stoppable/src/get-startable-stoppable.ts @@ -0,0 +1,43 @@ +export type Stopper = () => void; +export type Starter = () => Stopper; + +export interface StartableStoppable { + readonly started: boolean; + start: () => void; + stop: () => void; +} + +type StartableStoppableState = "stopped" | "started" | "starting"; + +export function getStartableStoppable( + id: string, + startAndGetStopper: Starter +): StartableStoppable { + let stop: Stopper; + let state: StartableStoppableState = "stopped"; + + return { + get started() { + return state === "started"; + }, + + start: () => { + if (state !== "stopped") { + throw new Error(`Tried to start "${id}", but it is already ${state}.`); + } + + state = "starting"; + stop = startAndGetStopper(); + state = "started"; + }, + + stop: () => { + if (state !== "started") { + throw new Error(`Tried to stop "${id}", but it is already ${state}.`); + } + + stop(); + state = "stopped"; + }, + }; +} diff --git a/packages/utility-features/startable-stoppable/tsconfig.json b/packages/utility-features/startable-stoppable/tsconfig.json new file mode 100644 index 0000000000..a4f6fa613e --- /dev/null +++ b/packages/utility-features/startable-stoppable/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@k8slens/typescript/config/base.json" +} diff --git a/packages/utility-features/startable-stoppable/webpack.config.js b/packages/utility-features/startable-stoppable/webpack.config.js new file mode 100644 index 0000000000..3183f30179 --- /dev/null +++ b/packages/utility-features/startable-stoppable/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForNode;