silentium 0.0.2

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 (199) hide show
  1. package/.husky/pre-commit +1 -0
  2. package/.husky/pre-push +2 -0
  3. package/.vscode/settings.json +8 -0
  4. package/CHANGELOG.md +12 -0
  5. package/LICENSE.md +7 -0
  6. package/README.md +3 -0
  7. package/commitizen.cjs +50 -0
  8. package/dist/silentium.cjs +771 -0
  9. package/dist/silentium.cjs.map +1 -0
  10. package/dist/silentium.d.ts +365 -0
  11. package/dist/silentium.js +735 -0
  12. package/dist/silentium.js.map +1 -0
  13. package/dist/silentium.min.js +1 -0
  14. package/dist/silentium.min.mjs +2 -0
  15. package/dist/silentium.min.mjs.map +1 -0
  16. package/dist/silentium.mjs +735 -0
  17. package/dist/silentium.mjs.map +1 -0
  18. package/docs/README.md +3 -0
  19. package/docs/assets/css/base.css +42 -0
  20. package/docs/assets/favicon/android-icon-144x144.png +0 -0
  21. package/docs/assets/favicon/android-icon-192x192.png +0 -0
  22. package/docs/assets/favicon/android-icon-36x36.png +0 -0
  23. package/docs/assets/favicon/android-icon-48x48.png +0 -0
  24. package/docs/assets/favicon/android-icon-72x72.png +0 -0
  25. package/docs/assets/favicon/android-icon-96x96.png +0 -0
  26. package/docs/assets/favicon/apple-icon-114x114.png +0 -0
  27. package/docs/assets/favicon/apple-icon-120x120.png +0 -0
  28. package/docs/assets/favicon/apple-icon-144x144.png +0 -0
  29. package/docs/assets/favicon/apple-icon-152x152.png +0 -0
  30. package/docs/assets/favicon/apple-icon-180x180.png +0 -0
  31. package/docs/assets/favicon/apple-icon-57x57.png +0 -0
  32. package/docs/assets/favicon/apple-icon-60x60.png +0 -0
  33. package/docs/assets/favicon/apple-icon-72x72.png +0 -0
  34. package/docs/assets/favicon/apple-icon-76x76.png +0 -0
  35. package/docs/assets/favicon/apple-icon-precomposed.png +0 -0
  36. package/docs/assets/favicon/apple-icon.png +0 -0
  37. package/docs/assets/favicon/browserconfig.xml +2 -0
  38. package/docs/assets/favicon/favicon-16x16.png +0 -0
  39. package/docs/assets/favicon/favicon-32x32.png +0 -0
  40. package/docs/assets/favicon/favicon-96x96.png +0 -0
  41. package/docs/assets/favicon/favicon.ico +0 -0
  42. package/docs/assets/favicon/manifest.json +41 -0
  43. package/docs/assets/favicon/ms-icon-144x144.png +0 -0
  44. package/docs/assets/favicon/ms-icon-150x150.png +0 -0
  45. package/docs/assets/favicon/ms-icon-310x310.png +0 -0
  46. package/docs/assets/favicon/ms-icon-70x70.png +0 -0
  47. package/docs/assets/img/404.jpg +0 -0
  48. package/docs/assets/img/angular_16.jpg +0 -0
  49. package/docs/assets/img/angular_32.jpg +0 -0
  50. package/docs/assets/img/eo_16.jpg +0 -0
  51. package/docs/assets/img/eo_big.png +0 -0
  52. package/docs/assets/img/github_16.jpg +0 -0
  53. package/docs/assets/img/logo.jpg +0 -0
  54. package/docs/assets/img/philosofy/observable.jpg +0 -0
  55. package/docs/assets/img/philosofy/responsible.jpg +0 -0
  56. package/docs/assets/img/philosofy/result.jpg +0 -0
  57. package/docs/assets/img/philosofy/tell.jpg +0 -0
  58. package/docs/assets/img/react_16.jpg +0 -0
  59. package/docs/assets/img/react_32.jpg +0 -0
  60. package/docs/assets/img/vue_16.jpg +0 -0
  61. package/docs/assets/img/vue_32.jpg +0 -0
  62. package/docs/assets/schemes/dip.html +28 -0
  63. package/docs/build.sh +20 -0
  64. package/docs/favicon.ico +0 -0
  65. package/docs/index-dev.html +346 -0
  66. package/docs/index.html +346 -0
  67. package/docs/manifest.json +41 -0
  68. package/docs/pages/404.html +9 -0
  69. package/docs/pages/common/layout.html +17 -0
  70. package/docs/pages/compatibility/dip.html +82 -0
  71. package/docs/pages/compatibility/elegant-objects.html +373 -0
  72. package/docs/pages/compatibility/layout.html +17 -0
  73. package/docs/pages/examples/errors.html +167 -0
  74. package/docs/pages/examples/index.html +10 -0
  75. package/docs/pages/examples.html +41 -0
  76. package/docs/pages/factory/index.html +18 -0
  77. package/docs/pages/factory.html +36 -0
  78. package/docs/pages/guest/guest-applied.html +51 -0
  79. package/docs/pages/guest/guest-cast.html +219 -0
  80. package/docs/pages/guest/guest-disposable.html +147 -0
  81. package/docs/pages/guest/guest-executor-applied.html +65 -0
  82. package/docs/pages/guest/guest-object.html +101 -0
  83. package/docs/pages/guest/guest-pool.html +107 -0
  84. package/docs/pages/guest/guest-sync.html +66 -0
  85. package/docs/pages/guest/index.html +115 -0
  86. package/docs/pages/guest.html +59 -0
  87. package/docs/pages/index.html +72 -0
  88. package/docs/pages/integrations/angular.html +5 -0
  89. package/docs/pages/integrations/layout.html +17 -0
  90. package/docs/pages/integrations/react.html +7 -0
  91. package/docs/pages/integrations/vue.html +102 -0
  92. package/docs/pages/patron/index.html +140 -0
  93. package/docs/pages/patron/patron-applied.html +66 -0
  94. package/docs/pages/patron/patron-executor-applied.html +94 -0
  95. package/docs/pages/patron/patron-once.html +110 -0
  96. package/docs/pages/patron/patron-pool.html +99 -0
  97. package/docs/pages/patron.html +50 -0
  98. package/docs/pages/philosofy.html +210 -0
  99. package/docs/pages/source/index.html +167 -0
  100. package/docs/pages/source/source-active.html +120 -0
  101. package/docs/pages/source/source-all.html +129 -0
  102. package/docs/pages/source/source-applied.html +73 -0
  103. package/docs/pages/source/source-dynamic.html +93 -0
  104. package/docs/pages/source/source-executor-applied.html +64 -0
  105. package/docs/pages/source/source-map.html +192 -0
  106. package/docs/pages/source/source-once.html +73 -0
  107. package/docs/pages/source/source-race.html +171 -0
  108. package/docs/pages/source/source-sequence.html +160 -0
  109. package/docs/pages/source/source-with-pool.html +102 -0
  110. package/docs/pages/source/source.html +167 -0
  111. package/docs/pages/source.html +68 -0
  112. package/docs/pages/terminology/guest.html +14 -0
  113. package/docs/pages/terminology/index.html +6 -0
  114. package/docs/pages/terminology/introduction.html +25 -0
  115. package/docs/pages/terminology/patron.html +10 -0
  116. package/docs/pages/terminology/source.html +55 -0
  117. package/docs/pages/terminology/visitor.html +19 -0
  118. package/docs/pages/terminology.html +53 -0
  119. package/docs/pages/utils/give.html +47 -0
  120. package/docs/pages/utils/index.html +24 -0
  121. package/docs/pages/utils/is-guest-aware.html +22 -0
  122. package/docs/pages/utils/is-guest.html +21 -0
  123. package/docs/pages/utils/is-patron-in-pools.html +53 -0
  124. package/docs/pages/utils/is-source.html +21 -0
  125. package/docs/pages/utils/private.html +44 -0
  126. package/docs/pages/utils/remove-patron-from-pools.html +57 -0
  127. package/docs/pages/utils/source-of.html +20 -0
  128. package/docs/pages/utils/value.html +47 -0
  129. package/docs/pages/utils.html +64 -0
  130. package/docs/template.html +346 -0
  131. package/eslint.config.mjs +47 -0
  132. package/package.json +57 -0
  133. package/rollup.config.js +52 -0
  134. package/src/Guest/Guest.test.ts +15 -0
  135. package/src/Guest/Guest.ts +53 -0
  136. package/src/Guest/GuestApplied.test.ts +13 -0
  137. package/src/Guest/GuestApplied.ts +16 -0
  138. package/src/Guest/GuestCast.test.ts +30 -0
  139. package/src/Guest/GuestCast.ts +39 -0
  140. package/src/Guest/GuestDisposable.test.ts +26 -0
  141. package/src/Guest/GuestDisposable.ts +33 -0
  142. package/src/Guest/GuestExecutorApplied.test.ts +27 -0
  143. package/src/Guest/GuestExecutorApplied.ts +23 -0
  144. package/src/Guest/GuestObject.test.ts +11 -0
  145. package/src/Guest/GuestObject.ts +34 -0
  146. package/src/Guest/GuestPool.test.ts +30 -0
  147. package/src/Guest/GuestPool.ts +56 -0
  148. package/src/Guest/GuestSync.test.ts +12 -0
  149. package/src/Guest/GuestSync.ts +25 -0
  150. package/src/Patron/Patron.test.ts +16 -0
  151. package/src/Patron/Patron.ts +35 -0
  152. package/src/Patron/PatronApplied.ts +22 -0
  153. package/src/Patron/PatronExecutorApplied.ts +25 -0
  154. package/src/Patron/PatronOnce.sourceEmpty.test.ts +38 -0
  155. package/src/Patron/PatronOnce.test.ts +32 -0
  156. package/src/Patron/PatronOnce.ts +38 -0
  157. package/src/Patron/PatronPool.test.ts +22 -0
  158. package/src/Patron/PatronPool.ts +121 -0
  159. package/src/Private/Private.test.ts +12 -0
  160. package/src/Private/Private.ts +20 -0
  161. package/src/Private/PrivateClass.modules.test.ts +36 -0
  162. package/src/Private/PrivateClass.test.ts +13 -0
  163. package/src/Private/PrivateClass.ts +29 -0
  164. package/src/Source/Source.test.ts +14 -0
  165. package/src/Source/Source.ts +59 -0
  166. package/src/Source/SourceActive.test.ts +13 -0
  167. package/src/Source/SourceActive.ts +41 -0
  168. package/src/Source/SourceAll._asArray.test.ts +22 -0
  169. package/src/Source/SourceAll._twoValuesAfter.test.ts +19 -0
  170. package/src/Source/SourceAll._twoValuesBefore.test.ts +19 -0
  171. package/src/Source/SourceAll._withPatron.test.ts +25 -0
  172. package/src/Source/SourceAll.ts +86 -0
  173. package/src/Source/SourceApplied.test.ts +14 -0
  174. package/src/Source/SourceApplied.ts +23 -0
  175. package/src/Source/SourceDynamic.ofSource.test.ts +21 -0
  176. package/src/Source/SourceDynamic.test.ts +26 -0
  177. package/src/Source/SourceDynamic.ts +35 -0
  178. package/src/Source/SourceExecutorApplied.test.ts +30 -0
  179. package/src/Source/SourceExecutorApplied.ts +22 -0
  180. package/src/Source/SourceMap.defered.test.ts +46 -0
  181. package/src/Source/SourceMap.fn.test.ts +27 -0
  182. package/src/Source/SourceMap.test.ts +32 -0
  183. package/src/Source/SourceMap.ts +48 -0
  184. package/src/Source/SourceOnce.notcalled.test.ts +13 -0
  185. package/src/Source/SourceOnce.test.ts +10 -0
  186. package/src/Source/SourceOnce.ts +31 -0
  187. package/src/Source/SourceRace.test.ts +46 -0
  188. package/src/Source/SourceRace.ts +30 -0
  189. package/src/Source/SourceSequence.defered.test.ts +53 -0
  190. package/src/Source/SourceSequence.test.ts +30 -0
  191. package/src/Source/SourceSequence.ts +72 -0
  192. package/src/Source/SourceWithPool.empty.test.ts +14 -0
  193. package/src/Source/SourceWithPool.test.ts +10 -0
  194. package/src/Source/SourceWithPool.ts +58 -0
  195. package/src/index.ts +26 -0
  196. package/test-utils/debounce.ts +11 -0
  197. package/test-utils/id.ts +1 -0
  198. package/test-utils/wait.ts +6 -0
  199. package/tsconfig.json +26 -0
@@ -0,0 +1,26 @@
1
+ import { GuestDisposable } from "./GuestDisposable";
2
+ import { Patron } from "../Patron/Patron";
3
+ import { SourceWithPool } from "../Source/SourceWithPool";
4
+ import { expect, test, vitest } from "vitest";
5
+
6
+ test("GuestDisposable.test", () => {
7
+ const source = new SourceWithPool(1);
8
+
9
+ const guest = vitest.fn();
10
+
11
+ // Работает проверка один раз, потом патром себя удаляет
12
+ source.value(
13
+ new Patron(
14
+ new GuestDisposable(guest, (value) => {
15
+ return value !== null && value > 1;
16
+ }),
17
+ ),
18
+ );
19
+
20
+ // Эти выражения не вызывает expect
21
+ source.give(2);
22
+ source.give(3);
23
+
24
+ expect(guest).toBeCalledTimes(1);
25
+ expect(guest).toBeCalledWith(1);
26
+ });
@@ -0,0 +1,33 @@
1
+ import { give, GuestObjectType, GuestType } from "./Guest";
2
+
3
+ export interface GuestDisposableType<T = any> extends GuestObjectType<T> {
4
+ disposed(value: T | null): boolean;
5
+ }
6
+
7
+ export type MaybeDisposableType<T = any> = Partial<GuestDisposableType<T>>;
8
+
9
+ /**
10
+ * @url https://kosukhin.github.io/patron.site/#/guest/guest-disposable
11
+ */
12
+ export class GuestDisposable<T> implements GuestDisposableType<T> {
13
+ public constructor(
14
+ private guest: GuestType,
15
+ private disposeCheck: (value: T | null) => boolean,
16
+ ) {
17
+ if (guest === undefined) {
18
+ throw new Error("GuestDisposable didnt receive guest argument");
19
+ }
20
+ if (disposeCheck === undefined) {
21
+ throw new Error("GuestDisposable didnt receive disposeCheck argument");
22
+ }
23
+ }
24
+
25
+ public disposed(value: T | null): boolean {
26
+ return this.disposeCheck(value);
27
+ }
28
+
29
+ public give(value: T): this {
30
+ give(value, this.guest);
31
+ return this;
32
+ }
33
+ }
@@ -0,0 +1,27 @@
1
+ import { Patron } from "../Patron/Patron";
2
+ import { expect, test, vi } from "vitest";
3
+ import { SourceWithPool } from "../Source/SourceWithPool";
4
+ import { GuestExecutorApplied } from "../Guest/GuestExecutorApplied";
5
+ import { debounce } from "../../test-utils/debounce";
6
+
7
+ test("GuestExecutorApplied.test", () => {
8
+ vi.useFakeTimers({ shouldAdvanceTime: true });
9
+ let counter = 0;
10
+ const guest = (v: number) => {
11
+ counter += v;
12
+ };
13
+
14
+ const source = new SourceWithPool();
15
+ source.value(
16
+ new Patron(new GuestExecutorApplied(guest, debounce.bind(null, 100))),
17
+ );
18
+
19
+ source.give(1);
20
+ source.give(1);
21
+ source.give(1);
22
+
23
+ vi.runOnlyPendingTimers();
24
+
25
+ expect(counter).toBe(1);
26
+ vi.useRealTimers();
27
+ });
@@ -0,0 +1,23 @@
1
+ import {
2
+ give,
3
+ GuestExecutorType,
4
+ GuestObjectType,
5
+ GuestType,
6
+ } from "../Guest/Guest";
7
+
8
+ /**
9
+ * @url https://kosukhin.github.io/patron.site/#/guest/guest-executor-applied
10
+ */
11
+ export class GuestExecutorApplied<T> implements GuestObjectType<T> {
12
+ public give: GuestExecutorType<T, this>;
13
+
14
+ public constructor(
15
+ baseGuest: GuestType<T>,
16
+ applier: (executor: GuestExecutorType) => GuestExecutorType,
17
+ ) {
18
+ this.give = applier((v) => give(v, baseGuest)) as GuestExecutorType<
19
+ T,
20
+ this
21
+ >;
22
+ }
23
+ }
@@ -0,0 +1,11 @@
1
+ import { expect, test, vitest } from "vitest";
2
+ import { SourceWithPool } from "../Source/SourceWithPool";
3
+ import { GuestObject } from "./GuestObject";
4
+
5
+ test("GuestObject.test", () => {
6
+ const source = new SourceWithPool(1);
7
+ const fnGuest = vitest.fn();
8
+ source.value(new GuestObject(fnGuest));
9
+ expect(fnGuest).toBeCalled();
10
+ expect(fnGuest).toBeCalledWith(1);
11
+ });
@@ -0,0 +1,34 @@
1
+ import { Guest, GuestType } from "./Guest";
2
+ import { GuestDisposableType, MaybeDisposableType } from "./GuestDisposable";
3
+
4
+ /**
5
+ * @url https://kosukhin.github.io/patron.site/#/guest/guest-object
6
+ */
7
+ export class GuestObject<T> implements GuestDisposableType<T> {
8
+ public constructor(private baseGuest: GuestType<T>) {
9
+ if (baseGuest === undefined) {
10
+ throw new Error("GuestObject didnt receive baseGuest argument");
11
+ }
12
+ }
13
+
14
+ public give(value: T): this {
15
+ let guest = this.baseGuest;
16
+ if (typeof guest === "function") {
17
+ guest = new Guest(guest);
18
+ }
19
+ guest.give(value);
20
+ return this;
21
+ }
22
+
23
+ public introduction() {
24
+ if (typeof this.baseGuest === "function" || !this.baseGuest.introduction) {
25
+ return "guest";
26
+ }
27
+ return this.baseGuest.introduction();
28
+ }
29
+
30
+ public disposed(value: T | null): boolean {
31
+ const maybeDisposable = this.baseGuest as MaybeDisposableType;
32
+ return maybeDisposable.disposed ? maybeDisposable.disposed(value) : false;
33
+ }
34
+ }
@@ -0,0 +1,30 @@
1
+ import { expect, test } from "vitest";
2
+ import { Patron } from "../Patron/Patron";
3
+ import { GuestPool } from "./GuestPool";
4
+
5
+ test("GuestPool.test", async () => {
6
+ const pool = new GuestPool<number>(null);
7
+ let receivedCount = 0;
8
+
9
+ // 2 + 2
10
+ pool.add(
11
+ new Patron((value) => {
12
+ receivedCount += value;
13
+ }),
14
+ );
15
+ // 2 + 2
16
+ pool.add(
17
+ new Patron((value) => {
18
+ receivedCount += value;
19
+ }),
20
+ );
21
+ // 2
22
+ pool.add((value) => {
23
+ receivedCount += value;
24
+ });
25
+
26
+ pool.give(2);
27
+ pool.give(2);
28
+
29
+ expect(receivedCount).toBe(10);
30
+ });
@@ -0,0 +1,56 @@
1
+ import { PatronPool, PoolType } from "../Patron/PatronPool";
2
+ import { give, GuestObjectType, GuestType } from "./Guest";
3
+
4
+ /**
5
+ * @url https://kosukhin.github.io/patron.site/#/guest/guest-pool
6
+ */
7
+ export class GuestPool<T> implements GuestObjectType<T>, PoolType<T> {
8
+ private guests = new Set<GuestType<T>>();
9
+
10
+ private patronPool: PatronPool<T>;
11
+
12
+ public constructor(initiator: unknown) {
13
+ this.patronPool = new PatronPool(initiator);
14
+ }
15
+
16
+ public give(value: T): this {
17
+ this.deliverToGuests(value);
18
+ this.patronPool.give(value);
19
+ return this;
20
+ }
21
+
22
+ public add(guest: GuestType<T>): this {
23
+ if (
24
+ typeof guest === "function" ||
25
+ !guest.introduction ||
26
+ guest.introduction() === "guest"
27
+ ) {
28
+ this.guests.add(guest);
29
+ }
30
+ this.patronPool.add(guest);
31
+ return this;
32
+ }
33
+
34
+ public remove(patron: GuestObjectType<T>): this {
35
+ this.guests.delete(patron);
36
+ this.patronPool.remove(patron);
37
+ return this;
38
+ }
39
+
40
+ public distribute(receiving: T, possiblePatron: GuestObjectType<T>): this {
41
+ this.add(possiblePatron);
42
+ this.give(receiving);
43
+ return this;
44
+ }
45
+
46
+ public size() {
47
+ return this.patronPool.size() + this.guests.size;
48
+ }
49
+
50
+ private deliverToGuests(value: T) {
51
+ this.guests.forEach((target) => {
52
+ give(value, target);
53
+ });
54
+ this.guests.clear();
55
+ }
56
+ }
@@ -0,0 +1,12 @@
1
+ import { expect, test } from "vitest";
2
+ import { GuestSync } from "./GuestSync";
3
+ import { SourceWithPool } from "../Source/SourceWithPool";
4
+
5
+ test("GuestSync.test", () => {
6
+ const source = new SourceWithPool(123);
7
+ const syncGuest = new GuestSync(111);
8
+ syncGuest.give(222);
9
+ expect(syncGuest.value()).toBe(222);
10
+ source.value(syncGuest);
11
+ expect(syncGuest.value()).toBe(123);
12
+ });
@@ -0,0 +1,25 @@
1
+ import { GuestObjectType } from "./Guest";
2
+
3
+ export interface GuestValueType<T = any> extends GuestObjectType<T> {
4
+ value(): T;
5
+ }
6
+
7
+ /**
8
+ * @url https://kosukhin.github.io/patron.site/#/guest/guest-sync
9
+ */
10
+ export class GuestSync<T> implements GuestValueType<T> {
11
+ public constructor(private theValue: T) {
12
+ if (theValue === undefined) {
13
+ throw new Error("GuestSync didnt receive theValue argument");
14
+ }
15
+ }
16
+
17
+ public give(value: T): this {
18
+ this.theValue = value;
19
+ return this;
20
+ }
21
+
22
+ public value() {
23
+ return this.theValue;
24
+ }
25
+ }
@@ -0,0 +1,16 @@
1
+ import { expect, test } from "vitest";
2
+ import { Patron } from "./Patron";
3
+ import { SourceWithPool } from "../Source/SourceWithPool";
4
+
5
+ test("Patron.test", () => {
6
+ const one = new SourceWithPool(1);
7
+ let patronCalledTimes = 0;
8
+ const patron = new Patron(() => {
9
+ patronCalledTimes += 1;
10
+ });
11
+
12
+ one.value(patron);
13
+ one.give(2);
14
+
15
+ expect(patronCalledTimes).toBe(2);
16
+ });
@@ -0,0 +1,35 @@
1
+ import { give, GuestType } from "../Guest/Guest";
2
+ import { GuestDisposableType } from "../Guest/GuestDisposable";
3
+
4
+ /**
5
+ * @url https://kosukhin.github.io/patron.site/#/patron
6
+ */
7
+ export class Patron<T> implements GuestDisposableType<T> {
8
+ public constructor(private willBePatron: GuestType<T>) {
9
+ if (willBePatron === undefined) {
10
+ throw new Error("Patron didnt receive willBePatron argument");
11
+ }
12
+ }
13
+
14
+ public introduction() {
15
+ return "patron" as const;
16
+ }
17
+
18
+ public give(value: T): this {
19
+ give(value, this.willBePatron);
20
+ return this;
21
+ }
22
+
23
+ public disposed(value: T | null): boolean {
24
+ const maybeDisposable = this.willBePatron as GuestDisposableType;
25
+ return maybeDisposable?.disposed?.(value) || false;
26
+ }
27
+ }
28
+
29
+ /**
30
+ * @url https://kosukhin.github.io/patron.site/#/utils/is-patron
31
+ */
32
+ export const isPatron = (guest: GuestType): guest is Patron<unknown> =>
33
+ typeof guest === "object" &&
34
+ guest !== null &&
35
+ guest?.introduction?.() === "patron";
@@ -0,0 +1,22 @@
1
+ import { GuestObjectType, GuestType } from "../Guest/Guest";
2
+ import { GuestApplied } from "../Guest/GuestApplied";
3
+
4
+ /**
5
+ * @url https://kosukhin.github.io/patron.site/#/patron/patron-applied
6
+ */
7
+ export class PatronApplied<T, R> implements GuestObjectType<T> {
8
+ private guestApplied: GuestApplied<T, R>;
9
+
10
+ public constructor(baseGuest: GuestType<R>, applier: (value: T) => R) {
11
+ this.guestApplied = new GuestApplied(baseGuest, applier);
12
+ }
13
+
14
+ public give(value: T): this {
15
+ this.guestApplied.give(value);
16
+ return this;
17
+ }
18
+
19
+ public introduction(): "guest" | "patron" {
20
+ return "patron";
21
+ }
22
+ }
@@ -0,0 +1,25 @@
1
+ import { GuestExecutorType, GuestObjectType, GuestType } from "../Guest/Guest";
2
+ import { GuestExecutorApplied } from "../Guest/GuestExecutorApplied";
3
+
4
+ /**
5
+ * @url https://kosukhin.github.io/patron.site/#/patron/patron-executor-applied
6
+ */
7
+ export class PatronExecutorApplied<T> implements GuestObjectType<T> {
8
+ private guestApplied: GuestExecutorApplied<T>;
9
+
10
+ public constructor(
11
+ baseGuest: GuestType<T>,
12
+ applier: (executor: GuestExecutorType) => GuestExecutorType,
13
+ ) {
14
+ this.guestApplied = new GuestExecutorApplied(baseGuest, applier);
15
+ }
16
+
17
+ public give(value: T): this {
18
+ this.guestApplied.give(value);
19
+ return this;
20
+ }
21
+
22
+ public introduction(): "guest" | "patron" {
23
+ return "patron";
24
+ }
25
+ }
@@ -0,0 +1,38 @@
1
+ import { afterEach, beforeEach, expect, test, vi } from "vitest";
2
+ import { PatronOnce } from "./PatronOnce";
3
+ import { SourceWithPool } from "../Source/SourceWithPool";
4
+
5
+ beforeEach(() => {
6
+ vi.useFakeTimers({ shouldAdvanceTime: true });
7
+ });
8
+
9
+ afterEach(() => {
10
+ vi.runOnlyPendingTimers();
11
+ vi.useRealTimers();
12
+ });
13
+
14
+ const wait = (ms: number) =>
15
+ new Promise((resolve) => {
16
+ setTimeout(() => {
17
+ resolve(1);
18
+ }, ms);
19
+ });
20
+
21
+ test("PatronOnce.sourceEmpty.test", async () => {
22
+ const source = new SourceWithPool();
23
+ let calls = 0;
24
+ const patron = new PatronOnce(() => {
25
+ calls += 1;
26
+ });
27
+ source.value(patron);
28
+
29
+ await wait(10);
30
+ source.give(22);
31
+ await wait(10);
32
+ source.give(32);
33
+ await wait(10);
34
+ source.give(42);
35
+ await wait(10);
36
+
37
+ expect(calls).toBe(1);
38
+ });
@@ -0,0 +1,32 @@
1
+ import { wait } from "./../../test-utils/wait";
2
+ import { afterEach, beforeEach, expect, test, vi } from "vitest";
3
+ import { SourceWithPool } from "../Source/SourceWithPool";
4
+ import { PatronOnce } from "./PatronOnce";
5
+
6
+ beforeEach(() => {
7
+ vi.useFakeTimers({ shouldAdvanceTime: true });
8
+ });
9
+
10
+ afterEach(() => {
11
+ vi.runOnlyPendingTimers();
12
+ vi.useRealTimers();
13
+ });
14
+
15
+ test("PatronOnce.test", async () => {
16
+ const source = new SourceWithPool(12);
17
+ let calls = 0;
18
+ const patron = new PatronOnce(() => {
19
+ calls += 1;
20
+ });
21
+ source.value(patron);
22
+
23
+ await wait(10);
24
+ source.give(22);
25
+ await wait(10);
26
+ source.give(32);
27
+ await wait(10);
28
+ source.give(42);
29
+ await wait(10);
30
+
31
+ expect(calls).toBe(1);
32
+ });
@@ -0,0 +1,38 @@
1
+ import { give, GuestType } from "../Guest/Guest";
2
+ import {
3
+ GuestDisposableType,
4
+ MaybeDisposableType,
5
+ } from "../Guest/GuestDisposable";
6
+
7
+ /**
8
+ * @url https://kosukhin.github.io/patron.site/#/patron/patron-once
9
+ */
10
+ export class PatronOnce<T> implements GuestDisposableType<T> {
11
+ private received = false;
12
+
13
+ public constructor(private baseGuest: GuestType<T>) {
14
+ if (baseGuest === undefined) {
15
+ throw new Error("PatronOnce didnt receive baseGuest argument");
16
+ }
17
+ }
18
+
19
+ public introduction() {
20
+ return "patron" as const;
21
+ }
22
+
23
+ public give(value: T): this {
24
+ if (!this.received) {
25
+ this.received = true;
26
+ give(value, this.baseGuest);
27
+ }
28
+ return this;
29
+ }
30
+
31
+ public disposed(value: T | null): boolean {
32
+ if (this.received) {
33
+ return true;
34
+ }
35
+ const maybeDisposable = this.baseGuest as MaybeDisposableType;
36
+ return maybeDisposable.disposed ? maybeDisposable.disposed(value) : false;
37
+ }
38
+ }
@@ -0,0 +1,22 @@
1
+ import { expect, test } from "vitest";
2
+ import { PatronPool } from "./PatronPool";
3
+ import { Patron } from "./Patron";
4
+
5
+ test("PatronPool.test", () => {
6
+ const pool = new PatronPool<number>(null);
7
+ let receivedCount = 0;
8
+
9
+ pool.add(
10
+ new Patron((value) => {
11
+ receivedCount += value;
12
+ }),
13
+ );
14
+ pool.add(
15
+ new Patron((value) => {
16
+ receivedCount += value;
17
+ }),
18
+ );
19
+ pool.give(2);
20
+
21
+ expect(receivedCount).toBe(4);
22
+ });
@@ -0,0 +1,121 @@
1
+ import { give, GuestObjectType, GuestType } from "../Guest/Guest";
2
+ import { GuestDisposableType } from "../Guest/GuestDisposable";
3
+
4
+ const poolSets = new Map<PoolType, Set<GuestObjectType>>();
5
+
6
+ /**
7
+ * @url https://kosukhin.github.io/patron.site/#/utils/patron-pools
8
+ */
9
+ export const patronPools = (patron: GuestObjectType) => {
10
+ const pools: PoolType[] = [];
11
+ poolSets.forEach((pool, poolInstance) => {
12
+ if (pool.has(patron)) {
13
+ pools.push(poolInstance);
14
+ }
15
+ });
16
+ return pools;
17
+ };
18
+
19
+ /**
20
+ * @url https://kosukhin.github.io/patron.site/#/utils/remove-patron-from-pools
21
+ */
22
+ export const removePatronFromPools = (patron: GuestObjectType) => {
23
+ if (patron === undefined) {
24
+ throw new Error("removePatronFromPools didnt receive patron argument");
25
+ }
26
+ poolSets.forEach((pool) => {
27
+ pool.delete(patron);
28
+ });
29
+ };
30
+
31
+ /**
32
+ * @url https://kosukhin.github.io/patron.site/#/utils/is-patron-in-pools
33
+ */
34
+ export const isPatronInPools = (patron: GuestObjectType) => {
35
+ if (patron === undefined) {
36
+ throw new Error("isPatronInPools didnt receive patron argument");
37
+ }
38
+ let inPool = false;
39
+ poolSets.forEach((pool) => {
40
+ if (!inPool) {
41
+ inPool = pool.has(patron);
42
+ }
43
+ });
44
+ return inPool;
45
+ };
46
+
47
+ export interface PoolType<T = any> extends GuestObjectType<T> {
48
+ add(guest: GuestObjectType<T>): this;
49
+ distribute(receiving: T, possiblePatron: GuestObjectType<T>): this;
50
+ remove(patron: GuestObjectType<T>): this;
51
+ size(): number;
52
+ }
53
+
54
+ /**
55
+ * @url https://kosukhin.github.io/patron.site/#/patron/patron-pool
56
+ */
57
+ export class PatronPool<T> implements PoolType<T> {
58
+ private patrons: Set<GuestObjectType<T>>;
59
+
60
+ public give: (value: T) => this;
61
+
62
+ public constructor(private initiator: unknown) {
63
+ this.patrons = new Set<GuestObjectType<T>>();
64
+ poolSets.set(this, this.patrons);
65
+ const doReceive = (value: T) => {
66
+ this.patrons.forEach((target) => {
67
+ this.sendValueToGuest(value, target);
68
+ });
69
+ };
70
+ this.give = (value: T) => {
71
+ doReceive(value);
72
+ return this;
73
+ };
74
+ }
75
+
76
+ public size(): number {
77
+ return this.patrons.size;
78
+ }
79
+
80
+ public add(shouldBePatron: GuestType<T>) {
81
+ if (!shouldBePatron) {
82
+ throw new Error("PatronPool add method received nothing!");
83
+ }
84
+ if (
85
+ typeof shouldBePatron !== "function" &&
86
+ shouldBePatron.introduction &&
87
+ shouldBePatron.introduction() === "patron"
88
+ ) {
89
+ this.patrons.add(shouldBePatron);
90
+ }
91
+ return this;
92
+ }
93
+
94
+ public remove(patron: GuestObjectType<T>) {
95
+ this.patrons.delete(patron);
96
+ return this;
97
+ }
98
+
99
+ public distribute(receiving: T, possiblePatron: GuestType<T>): this {
100
+ this.add(possiblePatron);
101
+ this.sendValueToGuest(receiving, possiblePatron);
102
+ return this;
103
+ }
104
+
105
+ private sendValueToGuest(value: T, guest: GuestType<T>) {
106
+ const isDisposed = this.guestDisposed(value, guest);
107
+
108
+ if (!isDisposed) {
109
+ give(value, guest);
110
+ }
111
+ }
112
+
113
+ private guestDisposed(value: T, guest: GuestType<T>) {
114
+ if ((guest as GuestDisposableType).disposed?.(value)) {
115
+ this.remove(guest as GuestObjectType);
116
+ return true;
117
+ }
118
+
119
+ return false;
120
+ }
121
+ }
@@ -0,0 +1,12 @@
1
+ import { Private } from "./Private";
2
+ import { expect, test } from "vitest";
3
+
4
+ test("Private.test", () => {
5
+ const privateNum = new Private((val) => {
6
+ return {
7
+ num: val,
8
+ };
9
+ });
10
+
11
+ expect(JSON.stringify(privateNum.get(11))).toBe('{"num":11}');
12
+ });
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @url https://kosukhin.github.io/patron.site/#/utils/private
3
+ */
4
+ export interface PrivateType<T> {
5
+ get<R extends unknown[], CT = null>(...args: R): CT extends null ? T : CT;
6
+ }
7
+
8
+ export class Private<T> implements PrivateType<T> {
9
+ public constructor(private buildingFn: (...args: any[]) => T) {
10
+ if (buildingFn === undefined) {
11
+ throw new Error("Private didnt receive buildingFn argument");
12
+ }
13
+ }
14
+
15
+ public get<R extends unknown[], CT = null>(
16
+ ...args: R
17
+ ): CT extends null ? T : CT {
18
+ return this.buildingFn(...args) as CT extends null ? T : CT;
19
+ }
20
+ }