@vived/core 1.5.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/README.md +1 -48
  2. package/dist/cjs/AppObject/AppObjectComponent.js +8 -10
  3. package/dist/cjs/AppObject/AppObjectComponent.js.map +1 -1
  4. package/dist/cjs/AppObject/AppObjectEntityRepo.js +99 -11
  5. package/dist/cjs/AppObject/AppObjectEntityRepo.js.map +1 -1
  6. package/dist/cjs/AppObject/AppObjectPM.js +106 -6
  7. package/dist/cjs/AppObject/AppObjectPM.js.map +1 -1
  8. package/dist/cjs/AppObject/AppObjectRepo.js +11 -1
  9. package/dist/cjs/AppObject/AppObjectRepo.js.map +1 -1
  10. package/dist/cjs/AppObject/AppObjectSingletonEntity.js +40 -0
  11. package/dist/cjs/AppObject/AppObjectSingletonEntity.js.map +1 -0
  12. package/dist/cjs/AppObject/AppObjectSingletonEntityRepo.js +54 -0
  13. package/dist/cjs/AppObject/AppObjectSingletonEntityRepo.js.map +1 -0
  14. package/dist/cjs/AppObject/AppObjectSingletonPM.js +69 -0
  15. package/dist/cjs/AppObject/AppObjectSingletonPM.js.map +1 -0
  16. package/dist/cjs/AppObject/AppObjectSingletonUC.js +60 -0
  17. package/dist/cjs/AppObject/AppObjectSingletonUC.js.map +1 -0
  18. package/dist/cjs/AppObject/index.js +4 -0
  19. package/dist/cjs/AppObject/index.js.map +1 -1
  20. package/dist/cjs/DomainFactories/Entities/DomainFactoryRepo.js +5 -0
  21. package/dist/cjs/DomainFactories/Entities/DomainFactoryRepo.js.map +1 -1
  22. package/dist/cjs/Entities/ObserverList.js +6 -0
  23. package/dist/cjs/Entities/ObserverList.js.map +1 -1
  24. package/dist/cjs/ExampleFeature/Entities/ExampleRepo.js +11 -22
  25. package/dist/cjs/ExampleFeature/Entities/ExampleRepo.js.map +1 -1
  26. package/dist/cjs/ExampleFeature/Entities/ExampleSingletonEntity.js +1 -3
  27. package/dist/cjs/ExampleFeature/Entities/ExampleSingletonEntity.js.map +1 -1
  28. package/dist/cjs/ExampleFeature/Factory/ExampleFeatureFactory.js +65 -0
  29. package/dist/cjs/ExampleFeature/Factory/ExampleFeatureFactory.js.map +1 -0
  30. package/dist/cjs/ExampleFeature/PMs/ExamplePM.js +5 -13
  31. package/dist/cjs/ExampleFeature/PMs/ExamplePM.js.map +1 -1
  32. package/dist/cjs/ExampleFeature/PMs/ExampleSingletonPM.js +8 -12
  33. package/dist/cjs/ExampleFeature/PMs/ExampleSingletonPM.js.map +1 -1
  34. package/dist/cjs/ExampleFeature/UCs/EditExampleStringUC.js +0 -4
  35. package/dist/cjs/ExampleFeature/UCs/EditExampleStringUC.js.map +1 -1
  36. package/dist/cjs/ExampleFeature/UCs/ToggleExampleBooleanUC.js +2 -8
  37. package/dist/cjs/ExampleFeature/UCs/ToggleExampleBooleanUC.js.map +1 -1
  38. package/dist/cjs/index.js +0 -1
  39. package/dist/cjs/index.js.map +1 -1
  40. package/dist/esm/AppObject/AppObjectComponent.js +8 -10
  41. package/dist/esm/AppObject/AppObjectComponent.js.map +1 -1
  42. package/dist/esm/AppObject/AppObjectEntityRepo.js +99 -11
  43. package/dist/esm/AppObject/AppObjectEntityRepo.js.map +1 -1
  44. package/dist/esm/AppObject/AppObjectPM.js +107 -7
  45. package/dist/esm/AppObject/AppObjectPM.js.map +1 -1
  46. package/dist/esm/AppObject/AppObjectRepo.js +11 -1
  47. package/dist/esm/AppObject/AppObjectRepo.js.map +1 -1
  48. package/dist/esm/AppObject/AppObjectSingletonEntity.js +36 -0
  49. package/dist/esm/AppObject/AppObjectSingletonEntity.js.map +1 -0
  50. package/dist/esm/AppObject/AppObjectSingletonEntityRepo.js +50 -0
  51. package/dist/esm/AppObject/AppObjectSingletonEntityRepo.js.map +1 -0
  52. package/dist/esm/AppObject/AppObjectSingletonPM.js +65 -0
  53. package/dist/esm/AppObject/AppObjectSingletonPM.js.map +1 -0
  54. package/dist/esm/AppObject/AppObjectSingletonUC.js +56 -0
  55. package/dist/esm/AppObject/AppObjectSingletonUC.js.map +1 -0
  56. package/dist/esm/AppObject/index.js +4 -0
  57. package/dist/esm/AppObject/index.js.map +1 -1
  58. package/dist/esm/DomainFactories/Entities/DomainFactoryRepo.js +4 -0
  59. package/dist/esm/DomainFactories/Entities/DomainFactoryRepo.js.map +1 -1
  60. package/dist/esm/Entities/ObserverList.js +6 -0
  61. package/dist/esm/Entities/ObserverList.js.map +1 -1
  62. package/dist/esm/ExampleFeature/Entities/ExampleRepo.js +11 -22
  63. package/dist/esm/ExampleFeature/Entities/ExampleRepo.js.map +1 -1
  64. package/dist/esm/ExampleFeature/Entities/ExampleSingletonEntity.js +2 -4
  65. package/dist/esm/ExampleFeature/Entities/ExampleSingletonEntity.js.map +1 -1
  66. package/dist/esm/ExampleFeature/Factory/ExampleFeatureFactory.js +60 -0
  67. package/dist/esm/ExampleFeature/Factory/ExampleFeatureFactory.js.map +1 -0
  68. package/dist/esm/ExampleFeature/PMs/ExamplePM.js +5 -13
  69. package/dist/esm/ExampleFeature/PMs/ExamplePM.js.map +1 -1
  70. package/dist/esm/ExampleFeature/PMs/ExampleSingletonPM.js +9 -13
  71. package/dist/esm/ExampleFeature/PMs/ExampleSingletonPM.js.map +1 -1
  72. package/dist/esm/ExampleFeature/UCs/EditExampleStringUC.js +0 -4
  73. package/dist/esm/ExampleFeature/UCs/EditExampleStringUC.js.map +1 -1
  74. package/dist/esm/ExampleFeature/UCs/ToggleExampleBooleanUC.js +3 -9
  75. package/dist/esm/ExampleFeature/UCs/ToggleExampleBooleanUC.js.map +1 -1
  76. package/dist/esm/index.js +0 -1
  77. package/dist/esm/index.js.map +1 -1
  78. package/dist/types/AppObject/AppObjectComponent.d.ts +6 -4
  79. package/dist/types/AppObject/AppObjectComponent.d.ts.map +1 -1
  80. package/dist/types/AppObject/AppObjectEntityRepo.d.ts +72 -7
  81. package/dist/types/AppObject/AppObjectEntityRepo.d.ts.map +1 -1
  82. package/dist/types/AppObject/AppObjectPM.d.ts +82 -2
  83. package/dist/types/AppObject/AppObjectPM.d.ts.map +1 -1
  84. package/dist/types/AppObject/AppObjectRepo.d.ts +13 -0
  85. package/dist/types/AppObject/AppObjectRepo.d.ts.map +1 -1
  86. package/dist/types/AppObject/AppObjectSingletonEntity.d.ts +31 -0
  87. package/dist/types/AppObject/AppObjectSingletonEntity.d.ts.map +1 -0
  88. package/dist/types/AppObject/AppObjectSingletonEntityRepo.d.ts +46 -0
  89. package/dist/types/AppObject/AppObjectSingletonEntityRepo.d.ts.map +1 -0
  90. package/dist/types/AppObject/AppObjectSingletonPM.d.ts +60 -0
  91. package/dist/types/AppObject/AppObjectSingletonPM.d.ts.map +1 -0
  92. package/dist/types/AppObject/AppObjectSingletonUC.d.ts +51 -0
  93. package/dist/types/AppObject/AppObjectSingletonUC.d.ts.map +1 -0
  94. package/dist/types/AppObject/index.d.ts +4 -0
  95. package/dist/types/AppObject/index.d.ts.map +1 -1
  96. package/dist/types/DomainFactories/Entities/DomainFactoryRepo.d.ts +1 -0
  97. package/dist/types/DomainFactories/Entities/DomainFactoryRepo.d.ts.map +1 -1
  98. package/dist/types/Entities/ObserverList.d.ts +4 -0
  99. package/dist/types/Entities/ObserverList.d.ts.map +1 -1
  100. package/dist/types/ExampleFeature/Entities/ExampleRepo.d.ts +0 -4
  101. package/dist/types/ExampleFeature/Entities/ExampleRepo.d.ts.map +1 -1
  102. package/dist/types/ExampleFeature/Entities/ExampleSingletonEntity.d.ts +2 -2
  103. package/dist/types/ExampleFeature/Entities/ExampleSingletonEntity.d.ts.map +1 -1
  104. package/dist/types/ExampleFeature/Factory/ExampleFeatureFactory.d.ts +44 -0
  105. package/dist/types/ExampleFeature/Factory/ExampleFeatureFactory.d.ts.map +1 -0
  106. package/dist/types/ExampleFeature/PMs/ExampleSingletonPM.d.ts +4 -4
  107. package/dist/types/ExampleFeature/PMs/ExampleSingletonPM.d.ts.map +1 -1
  108. package/dist/types/ExampleFeature/UCs/ToggleExampleBooleanUC.d.ts +2 -2
  109. package/dist/types/ExampleFeature/UCs/ToggleExampleBooleanUC.d.ts.map +1 -1
  110. package/dist/types/index.d.ts +0 -1
  111. package/dist/types/index.d.ts.map +1 -1
  112. package/package.json +2 -2
  113. package/dist/cjs/ExampleFeature/Adapters/index.js +0 -19
  114. package/dist/cjs/ExampleFeature/Adapters/index.js.map +0 -1
  115. package/dist/cjs/ExampleFeature/Controllers/index.js +0 -19
  116. package/dist/cjs/ExampleFeature/Controllers/index.js.map +0 -1
  117. package/dist/cjs/ExampleFeature/Entities/index.js +0 -20
  118. package/dist/cjs/ExampleFeature/Entities/index.js.map +0 -1
  119. package/dist/cjs/ExampleFeature/Factory/index.js +0 -18
  120. package/dist/cjs/ExampleFeature/Factory/index.js.map +0 -1
  121. package/dist/cjs/ExampleFeature/Factory/setupExampleFeature.js +0 -29
  122. package/dist/cjs/ExampleFeature/Factory/setupExampleFeature.js.map +0 -1
  123. package/dist/cjs/ExampleFeature/Mocks/index.js +0 -21
  124. package/dist/cjs/ExampleFeature/Mocks/index.js.map +0 -1
  125. package/dist/cjs/ExampleFeature/PMs/index.js +0 -19
  126. package/dist/cjs/ExampleFeature/PMs/index.js.map +0 -1
  127. package/dist/cjs/ExampleFeature/UCs/index.js +0 -19
  128. package/dist/cjs/ExampleFeature/UCs/index.js.map +0 -1
  129. package/dist/cjs/ExampleFeature/index.js +0 -24
  130. package/dist/cjs/ExampleFeature/index.js.map +0 -1
  131. package/dist/esm/ExampleFeature/Adapters/index.js +0 -3
  132. package/dist/esm/ExampleFeature/Adapters/index.js.map +0 -1
  133. package/dist/esm/ExampleFeature/Controllers/index.js +0 -3
  134. package/dist/esm/ExampleFeature/Controllers/index.js.map +0 -1
  135. package/dist/esm/ExampleFeature/Entities/index.js +0 -4
  136. package/dist/esm/ExampleFeature/Entities/index.js.map +0 -1
  137. package/dist/esm/ExampleFeature/Factory/index.js +0 -2
  138. package/dist/esm/ExampleFeature/Factory/index.js.map +0 -1
  139. package/dist/esm/ExampleFeature/Factory/setupExampleFeature.js +0 -26
  140. package/dist/esm/ExampleFeature/Factory/setupExampleFeature.js.map +0 -1
  141. package/dist/esm/ExampleFeature/Mocks/index.js +0 -5
  142. package/dist/esm/ExampleFeature/Mocks/index.js.map +0 -1
  143. package/dist/esm/ExampleFeature/PMs/index.js +0 -3
  144. package/dist/esm/ExampleFeature/PMs/index.js.map +0 -1
  145. package/dist/esm/ExampleFeature/UCs/index.js +0 -3
  146. package/dist/esm/ExampleFeature/UCs/index.js.map +0 -1
  147. package/dist/esm/ExampleFeature/index.js +0 -8
  148. package/dist/esm/ExampleFeature/index.js.map +0 -1
  149. package/dist/types/ExampleFeature/Adapters/index.d.ts +0 -3
  150. package/dist/types/ExampleFeature/Adapters/index.d.ts.map +0 -1
  151. package/dist/types/ExampleFeature/Controllers/index.d.ts +0 -3
  152. package/dist/types/ExampleFeature/Controllers/index.d.ts.map +0 -1
  153. package/dist/types/ExampleFeature/Entities/index.d.ts +0 -4
  154. package/dist/types/ExampleFeature/Entities/index.d.ts.map +0 -1
  155. package/dist/types/ExampleFeature/Factory/index.d.ts +0 -2
  156. package/dist/types/ExampleFeature/Factory/index.d.ts.map +0 -1
  157. package/dist/types/ExampleFeature/Factory/setupExampleFeature.d.ts +0 -17
  158. package/dist/types/ExampleFeature/Factory/setupExampleFeature.d.ts.map +0 -1
  159. package/dist/types/ExampleFeature/Mocks/index.d.ts +0 -5
  160. package/dist/types/ExampleFeature/Mocks/index.d.ts.map +0 -1
  161. package/dist/types/ExampleFeature/PMs/index.d.ts +0 -3
  162. package/dist/types/ExampleFeature/PMs/index.d.ts.map +0 -1
  163. package/dist/types/ExampleFeature/UCs/index.d.ts +0 -3
  164. package/dist/types/ExampleFeature/UCs/index.d.ts.map +0 -1
  165. package/dist/types/ExampleFeature/index.d.ts +0 -8
  166. package/dist/types/ExampleFeature/index.d.ts.map +0 -1
package/README.md CHANGED
@@ -66,54 +66,7 @@ The package includes a fully implemented `ExampleFeature` that demonstrates the
66
66
  - **Controllers/** - Simplified API for UI interaction
67
67
  - **Adapters/** - Connect UI frameworks to PMs
68
68
  - **Mocks/** - Test doubles for unit testing
69
-
70
- ### Implementation Patterns
71
- The example demonstrates:
72
- - Observable entities with memoized properties
73
- - Presentation managers with view model transformation
74
- - Use cases that implement business logic
75
- - Controllers that provide a simple UI-friendly API
76
- - Component registration and retrieval
77
- - Singleton component access
78
- - Test patterns for each component type
79
-
80
- ### Sample Usage
81
-
82
- ```typescript
83
- // Create a repository and an app object
84
- const repo = makeAppObjectRepo();
85
- const appObject = repo.getOrCreate("myObject");
86
-
87
- // Add an entity component to hold state
88
- class MyEntity extends AppObjectEntity {
89
- private _value = 0;
90
-
91
- get value() { return this._value; }
92
- set value(newValue: number) {
93
- this._value = newValue;
94
- this.notifyOnChange();
95
- }
96
- }
97
-
98
- // Add the entity to the app object
99
- const entity = new MyEntity(appObject, "MyEntity");
100
-
101
- // Create a presentation manager
102
- class MyPM extends AppObjectPM<{value: number}> {
103
- vmsAreEqual(a: {value: number}, b: {value: number}): boolean {
104
- return a.value === b.value;
105
- }
106
-
107
- updateViewModel() {
108
- const entity = this.getCachedLocalComponent<MyEntity>("MyEntity");
109
- if (entity) {
110
- this.doUpdateView({value: entity.value});
111
- }
112
- }
113
- }
114
-
115
- // The architecture enables clean, testable, and maintainable code
116
- ```
69
+ - **Factory/** - Factories for creating the features at runtime
117
70
 
118
71
  Refer to the `ExampleFeature` directory for a complete implementation example that shows the interaction between all component types.
119
72
 
@@ -45,17 +45,16 @@ class AppObjectComponent {
45
45
  * Results are cached for better performance in repeated calls
46
46
  *
47
47
  * @param type The component type identifier to look up
48
- * @returns The singleton component cast to type T, or undefined if not found
48
+ * @returns The singleton component cast to type T
49
+ * @throws Error if the component is not found
49
50
  */
50
51
  getCachedSingleton(type) {
51
52
  if (!this.cachedComponents.has(type)) {
52
53
  const component = this.appObjects.getSingleton(type);
53
54
  if (!component) {
54
- this.warn("Unable to get cached singleton type " + type);
55
- }
56
- else {
57
- this.cachedComponents.set(type, component);
55
+ throw new Error("Unable to get cached singleton type " + type);
58
56
  }
57
+ this.cachedComponents.set(type, component);
59
58
  }
60
59
  return this.cachedComponents.get(type);
61
60
  }
@@ -64,17 +63,16 @@ class AppObjectComponent {
64
63
  * Results are cached for better performance in repeated calls
65
64
  *
66
65
  * @param type The component type identifier to look up
67
- * @returns The component cast to type T, or undefined if not found
66
+ * @returns The component cast to type T
67
+ * @throws Error if the component is not found
68
68
  */
69
69
  getCachedLocalComponent(type) {
70
70
  if (!this.cachedComponents.has(type)) {
71
71
  const component = this.appObject.getComponent(type);
72
72
  if (!component) {
73
- this.warn("Unable to get local component of type " + type);
74
- }
75
- else {
76
- this.cachedComponents.set(type, component);
73
+ throw new Error("Unable to get local component of type " + type);
77
74
  }
75
+ this.cachedComponents.set(type, component);
78
76
  }
79
77
  return this.cachedComponents.get(type);
80
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AppObjectComponent.js","sourceRoot":"","sources":["../../../src/AppObject/AppObjectComponent.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppObject } from \"./AppObject\";\r\nimport { AppObjectRepo } from \"./AppObjectRepo\";\r\n\r\n/**\r\n * Enumeration of the different types of components in the architecture.\r\n * Each type serves a specific purpose in the application structure.\r\n */\r\nexport enum AppObjectComponentType {\r\n /** Stores and manages application state */\r\n ENTITY = \"Entity\",\r\n \r\n /** Transforms application state into view models */\r\n PM = \"Presentation Manager\",\r\n \r\n /** Implements business logic and coordinates between layers */\r\n UC = \"Use Case\",\r\n \r\n /** Handles user inputs and external events */\r\n CONTROLLER = \"Controller\",\r\n \r\n /** Renders UI elements and interacts with the DOM/rendering system */\r\n VIEW = \"View\",\r\n \r\n /** Default type for components that don't fit the standard categories */\r\n UNKNOWN = \"Unknown\",\r\n}\r\n\r\n/**\r\n * Base class for all components in the AppObject architecture.\r\n * \r\n * Components attach to AppObjects and provide specific functionality based on their type.\r\n * The architecture follows a clean separation of concerns, with each component type\r\n * having a well-defined responsibility in the application.\r\n * \r\n * Components can communicate with each other through various mechanisms:\r\n * - Direct access via parent AppObject\r\n * - Repository-level singleton access\r\n * - Observer patterns for reactive updates\r\n */\r\nexport class AppObjectComponent {\r\n /** The type category of this component */\r\n readonly componentType: AppObjectComponentType = AppObjectComponentType.UNKNOWN;\r\n \r\n /** Unique type identifier for this specific component */\r\n readonly type: string;\r\n \r\n /** The parent AppObject this component is attached to */\r\n readonly appObject: AppObject;\r\n \r\n /**\r\n * Convenience accessor for the repository containing all AppObjects\r\n * @returns The application's AppObjectRepo\r\n */\r\n get appObjects(): AppObjectRepo {\r\n return this.appObject.appObjectRepo;\r\n }\r\n\r\n /** Cache for components to avoid repeated lookups */\r\n private cachedComponents = new Map<string, AppObjectComponent>();\r\n \r\n /**\r\n * Retrieves a singleton component of the specified type from the repository\r\n * Results are cached for better performance in repeated calls\r\n * \r\n * @param type The component type identifier to look up\r\n * @returns The singleton component cast to type T, or undefined if not found\r\n */\r\n getCachedSingleton<T extends AppObjectComponent>(\r\n type: string\r\n ): T | undefined {\r\n if (!this.cachedComponents.has(type)) {\r\n const component = this.appObjects.getSingleton(type);\r\n if (!component) {\r\n this.warn(\"Unable to get cached singleton type \" + type);\r\n } else {\r\n this.cachedComponents.set(type, component);\r\n }\r\n }\r\n\r\n return this.cachedComponents.get(type) as T;\r\n }\r\n\r\n /**\r\n * Retrieves a component from the same AppObject as this component\r\n * Results are cached for better performance in repeated calls\r\n * \r\n * @param type The component type identifier to look up\r\n * @returns The component cast to type T, or undefined if not found\r\n */\r\n getCachedLocalComponent<T extends AppObjectComponent>(\r\n type: string\r\n ): T | undefined {\r\n if (!this.cachedComponents.has(type)) {\r\n const component = this.appObject.getComponent(type);\r\n\r\n if (!component) {\r\n this.warn(\"Unable to get local component of type \" + type);\r\n } else {\r\n this.cachedComponents.set(type, component);\r\n }\r\n }\r\n\r\n return this.cachedComponents.get(type) as T;\r\n }\r\n\r\n /**\r\n * Retrieves a singleton component from the repository with customizable logging\r\n * Unlike getCachedSingleton, results are not cached\r\n * \r\n * @param type The component type identifier to look up\r\n * @param logType The severity level for logging if component isn't found\r\n * @returns The singleton component cast to type T, or undefined if not found\r\n */\r\n getSingleton<T extends AppObjectComponent>(\r\n type: string,\r\n logType: \"LOG\" | \"WARN\" | \"ERROR\" = \"WARN\"\r\n ): T | undefined {\r\n const comp = this.appObjects.getSingleton<T>(type);\r\n\r\n if (!comp) {\r\n const msg = \"Unable to get singleton type \" + type;\r\n switch (logType) {\r\n case \"ERROR\":\r\n this.error(msg);\r\n break;\r\n case \"LOG\":\r\n this.log(msg);\r\n break;\r\n case \"WARN\":\r\n this.warn(msg);\r\n break;\r\n }\r\n }\r\n\r\n return comp;\r\n }\r\n\r\n /**\r\n * Cleans up resources used by this component\r\n * Removes itself from the parent AppObject if it's still attached\r\n */\r\n dispose() {\r\n if (this.appObject.getComponent(this.type) === this) {\r\n this.appObject.removeComponent(this.type);\r\n }\r\n }\r\n\r\n /**\r\n * Logs an informational message to the application's logging system\r\n * Messages are prefixed with the AppObject ID and component type for easier debugging\r\n * \r\n * @param message The message to log\r\n */\r\n log(message: string) {\r\n this.appObjects.submitLog(`${this.appObject.id}/${this.type}`, message);\r\n }\r\n\r\n /**\r\n * Logs a warning message to the application's logging system\r\n * Messages are prefixed with the AppObject ID and component type for easier debugging\r\n * \r\n * @param message The warning message to log\r\n */\r\n warn(message: string) {\r\n this.appObjects.submitWarning(`${this.appObject.id}/${this.type}`, message);\r\n }\r\n\r\n /**\r\n * Logs an error message to the application's logging system\r\n * Messages are prefixed with the AppObject ID and component type for easier debugging\r\n * \r\n * @param message The error message to log\r\n */\r\n error(message: string) {\r\n this.appObjects.submitError(`${this.appObject.id}/${this.type}`, message);\r\n }\r\n\r\n /**\r\n * Creates a new component and attaches it to the specified AppObject\r\n * \r\n * @param appObject The parent AppObject this component will be attached to\r\n * @param type The unique type identifier for this component\r\n */\r\n constructor(appObject: AppObject, type: string) {\r\n this.appObject = appObject;\r\n this.type = type;\r\n appObject.addComponent(this);\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"AppObjectComponent.js","sourceRoot":"","sources":["../../../src/AppObject/AppObjectComponent.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppObject } from \"./AppObject\";\r\nimport { AppObjectRepo } from \"./AppObjectRepo\";\r\n\r\n/**\r\n * Enumeration of the different types of components in the architecture.\r\n * Each type serves a specific purpose in the application structure.\r\n */\r\nexport enum AppObjectComponentType {\r\n /** Stores and manages application state */\r\n ENTITY = \"Entity\",\r\n\r\n /** Transforms application state into view models */\r\n PM = \"Presentation Manager\",\r\n\r\n /** Implements business logic and coordinates between layers */\r\n UC = \"Use Case\",\r\n\r\n /** Handles user inputs and external events */\r\n CONTROLLER = \"Controller\",\r\n\r\n /** Renders UI elements and interacts with the DOM/rendering system */\r\n VIEW = \"View\",\r\n\r\n /** Default type for components that don't fit the standard categories */\r\n UNKNOWN = \"Unknown\",\r\n}\r\n\r\n/**\r\n * Base class for all components in the AppObject architecture.\r\n *\r\n * Components attach to AppObjects and provide specific functionality based on their type.\r\n * The architecture follows a clean separation of concerns, with each component type\r\n * having a well-defined responsibility in the application.\r\n *\r\n * Components can communicate with each other through various mechanisms:\r\n * - Direct access via parent AppObject\r\n * - Repository-level singleton access\r\n * - Observer patterns for reactive updates\r\n */\r\nexport class AppObjectComponent {\r\n /** The type category of this component */\r\n readonly componentType: AppObjectComponentType =\r\n AppObjectComponentType.UNKNOWN;\r\n\r\n /** Unique type identifier for this specific component */\r\n readonly type: string;\r\n\r\n /** The parent AppObject this component is attached to */\r\n readonly appObject: AppObject;\r\n\r\n /**\r\n * Convenience accessor for the repository containing all AppObjects\r\n * @returns The application's AppObjectRepo\r\n */\r\n get appObjects(): AppObjectRepo {\r\n return this.appObject.appObjectRepo;\r\n }\r\n\r\n /** Cache for components to avoid repeated lookups */\r\n private cachedComponents = new Map<string, AppObjectComponent>();\r\n\r\n /**\r\n * Retrieves a singleton component of the specified type from the repository\r\n * Results are cached for better performance in repeated calls\r\n *\r\n * @param type The component type identifier to look up\r\n * @returns The singleton component cast to type T\r\n * @throws Error if the component is not found\r\n */\r\n getCachedSingleton<T extends AppObjectComponent>(type: string): T {\r\n if (!this.cachedComponents.has(type)) {\r\n const component = this.appObjects.getSingleton(type);\r\n if (!component) {\r\n throw new Error(\"Unable to get cached singleton type \" + type);\r\n }\r\n this.cachedComponents.set(type, component);\r\n }\r\n\r\n return this.cachedComponents.get(type) as T;\r\n }\r\n\r\n /**\r\n * Retrieves a component from the same AppObject as this component\r\n * Results are cached for better performance in repeated calls\r\n *\r\n * @param type The component type identifier to look up\r\n * @returns The component cast to type T\r\n * @throws Error if the component is not found\r\n */\r\n getCachedLocalComponent<T extends AppObjectComponent>(type: string): T {\r\n if (!this.cachedComponents.has(type)) {\r\n const component = this.appObject.getComponent(type);\r\n\r\n if (!component) {\r\n throw new Error(\"Unable to get local component of type \" + type);\r\n }\r\n this.cachedComponents.set(type, component);\r\n }\r\n\r\n return this.cachedComponents.get(type) as T;\r\n }\r\n\r\n /**\r\n * Retrieves a singleton component from the repository with customizable logging\r\n * Unlike getCachedSingleton, results are not cached\r\n *\r\n * @param type The component type identifier to look up\r\n * @param logType The severity level for logging if component isn't found\r\n * @returns The singleton component cast to type T, or undefined if not found\r\n */\r\n getSingleton<T extends AppObjectComponent>(\r\n type: string,\r\n logType: \"LOG\" | \"WARN\" | \"ERROR\" = \"WARN\"\r\n ): T | undefined {\r\n const comp = this.appObjects.getSingleton<T>(type);\r\n\r\n if (!comp) {\r\n const msg = \"Unable to get singleton type \" + type;\r\n switch (logType) {\r\n case \"ERROR\":\r\n this.error(msg);\r\n break;\r\n case \"LOG\":\r\n this.log(msg);\r\n break;\r\n case \"WARN\":\r\n this.warn(msg);\r\n break;\r\n }\r\n }\r\n\r\n return comp;\r\n }\r\n\r\n /**\r\n * Cleans up resources used by this component\r\n * Removes itself from the parent AppObject if it's still attached\r\n */\r\n dispose() {\r\n if (this.appObject.getComponent(this.type) === this) {\r\n this.appObject.removeComponent(this.type);\r\n }\r\n }\r\n\r\n /**\r\n * Logs an informational message to the application's logging system\r\n * Messages are prefixed with the AppObject ID and component type for easier debugging\r\n *\r\n * @param message The message to log\r\n */\r\n log(message: string) {\r\n this.appObjects.submitLog(`${this.appObject.id}/${this.type}`, message);\r\n }\r\n\r\n /**\r\n * Logs a warning message to the application's logging system\r\n * Messages are prefixed with the AppObject ID and component type for easier debugging\r\n *\r\n * @param message The warning message to log\r\n */\r\n warn(message: string) {\r\n this.appObjects.submitWarning(`${this.appObject.id}/${this.type}`, message);\r\n }\r\n\r\n /**\r\n * Logs an error message to the application's logging system\r\n * Messages are prefixed with the AppObject ID and component type for easier debugging\r\n *\r\n * @param message The error message to log\r\n */\r\n error(message: string) {\r\n this.appObjects.submitError(`${this.appObject.id}/${this.type}`, message);\r\n }\r\n\r\n /**\r\n * Creates a new component and attaches it to the specified AppObject\r\n *\r\n * @param appObject The parent AppObject this component will be attached to\r\n * @param type The unique type identifier for this component\r\n */\r\n constructor(appObject: AppObject, type: string) {\r\n this.appObject = appObject;\r\n this.type = type;\r\n appObject.addComponent(this);\r\n }\r\n}\r\n"]}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AppObjectEntityRepo = void 0;
4
4
  const Entities_1 = require("../Entities");
5
+ const Utilities_1 = require("../Utilities");
5
6
  const AppObjectEntity_1 = require("./AppObjectEntity");
6
7
  /**
7
8
  * A repository for managing collections of AppObjectEntity instances.
@@ -10,20 +11,32 @@ const AppObjectEntity_1 = require("./AppObjectEntity");
10
11
  * entities that are associated with specific AppObjects. It implements the observer
11
12
  * pattern to notify listeners when entities are added or removed.
12
13
  *
14
+ * Derived classes should override the `entityFactory` method to provide custom
15
+ * entity creation logic for the `create` method.
16
+ *
13
17
  * @template T - The type of entities managed by this repository, must extend AppObjectEntity
14
18
  * @extends AppObjectEntity
15
19
  *
16
20
  * @example
17
21
  * ```typescript
18
- * // Create a repository for player entities
19
- * const playerRepo = new AppObjectEntityRepo<PlayerEntity>();
22
+ * // Create a custom repository with entity factory
23
+ * class PlayerRepo extends AppObjectEntityRepo<PlayerEntity> {
24
+ * entityFactory(id: string): PlayerEntity {
25
+ * const appObject = makeAppObject(id, this.appObjects);
26
+ * return new PlayerEntity(appObject);
27
+ * }
28
+ * }
29
+ *
30
+ * const playerRepo = new PlayerRepo(repoAppObject);
31
+ *
32
+ * // Create a new player with auto-generated ID
33
+ * const player = playerRepo.create();
20
34
  *
21
- * // Add a new player
22
- * const player = new PlayerEntity(appObject);
23
- * playerRepo.add(player);
35
+ * // Create a new player with specific ID
36
+ * const specificPlayer = playerRepo.create("player1");
24
37
  *
25
- * // Get a player by its AppObject ID
26
- * const retrievedPlayer = playerRepo.getForAppObject("player1");
38
+ * // Get a player by its ID
39
+ * const retrievedPlayer = playerRepo.getById("player1");
27
40
  * ```
28
41
  */
29
42
  class AppObjectEntityRepo extends AppObjectEntity_1.AppObjectEntity {
@@ -64,23 +77,33 @@ class AppObjectEntityRepo extends AppObjectEntity_1.AppObjectEntity {
64
77
  this.removeEntityRemovedObserver = (observer) => {
65
78
  this.onEntityRemovedObservers.remove(observer);
66
79
  };
80
+ /**
81
+ * Checks if an entity exists for the given ID.
82
+ *
83
+ * @param {string} id - The ID of the AppObject
84
+ * @returns {boolean} True if an entity exists for the given ID, false otherwise
85
+ */
86
+ this.has = (id) => {
87
+ return this.entityLookup.has(id);
88
+ };
67
89
  /**
68
90
  * Checks if an entity exists for the given AppObject ID.
69
91
  *
70
92
  * @param {string} appObjectID - The ID of the AppObject
71
93
  * @returns {boolean} True if an entity exists for the given AppObject ID, false otherwise
94
+ * @deprecated Use has instead
72
95
  */
73
96
  this.hasForAppObject = (appObjectID) => {
74
- return this.entityLookup.has(appObjectID);
97
+ return this.has(appObjectID);
75
98
  };
76
99
  /**
77
- * Removes the entity associated with the specified AppObject ID.
100
+ * Removes the entity associated with the specified ID.
78
101
  *
79
102
  * Notifies all registered observers after the entity is removed.
80
103
  *
81
104
  * @param {string} id - The ID of the AppObject whose entity should be removed
82
105
  */
83
- this.removeForAppObject = (id) => {
106
+ this.removeById = (id) => {
84
107
  const existing = this.entityLookup.get(id);
85
108
  if (!existing)
86
109
  return;
@@ -89,14 +112,50 @@ class AppObjectEntityRepo extends AppObjectEntity_1.AppObjectEntity {
89
112
  this.notifyOnChange();
90
113
  this.onEntityRemovedObservers.notify(existing);
91
114
  };
115
+ /**
116
+ * Removes the entity associated with the specified AppObject ID.
117
+ *
118
+ * Notifies all registered observers after the entity is removed.
119
+ *
120
+ * @param {string} id - The ID of the AppObject whose entity should be removed
121
+ * @deprecated Use removeById instead
122
+ */
123
+ this.removeForAppObject = (id) => {
124
+ this.removeById(id);
125
+ };
126
+ /**
127
+ * Removes all entities from the repository.
128
+ *
129
+ * Unsubscribes from all entity change observers and notifies all registered
130
+ * removal observers for each entity before clearing the repository.
131
+ */
132
+ this.deleteAll = () => {
133
+ const entities = Array.from(this.entityLookup.values());
134
+ entities.forEach((entity) => {
135
+ entity.removeChangeObserver(this.notifyOnChange);
136
+ this.onEntityRemovedObservers.notify(entity);
137
+ });
138
+ this.entityLookup.clear();
139
+ this.notifyOnChange();
140
+ };
141
+ /**
142
+ * Gets the entity associated with the specified ID.
143
+ *
144
+ * @param {string} id - The ID of the AppObject
145
+ * @returns {T | undefined} The entity if found, undefined otherwise
146
+ */
147
+ this.getById = (id) => {
148
+ return this.entityLookup.get(id);
149
+ };
92
150
  /**
93
151
  * Gets the entity associated with the specified AppObject ID.
94
152
  *
95
153
  * @param {string} appObjectID - The ID of the AppObject
96
154
  * @returns {T | undefined} The entity if found, undefined otherwise
155
+ * @deprecated Use getById instead
97
156
  */
98
157
  this.getForAppObject = (appObjectID) => {
99
- return this.entityLookup.get(appObjectID);
158
+ return this.getById(appObjectID);
100
159
  };
101
160
  /**
102
161
  * Gets all entities in the repository.
@@ -125,6 +184,35 @@ class AppObjectEntityRepo extends AppObjectEntity_1.AppObjectEntity {
125
184
  this.notifyOnChange();
126
185
  this.onEntityAddedObservers.notify(entity);
127
186
  }
187
+ /**
188
+ * Creates a new entity with the specified or auto-generated ID and adds it to the repository.
189
+ *
190
+ * This method uses the `entityFactory` method to create the entity instance.
191
+ * If no ID is provided, a unique ID is generated automatically.
192
+ *
193
+ * @param {string} [id] - Optional ID for the entity. If not provided, a unique ID is generated.
194
+ * @returns {T} The newly created entity
195
+ */
196
+ create(id) {
197
+ const idToUse = id ?? (0, Utilities_1.generateUniqueID)();
198
+ const entity = this.entityFactory(idToUse);
199
+ this.add(entity);
200
+ return entity;
201
+ }
202
+ /**
203
+ * Factory method for creating entity instances.
204
+ *
205
+ * This method must be overridden in derived classes to provide custom entity creation logic.
206
+ * It is called by the `create` method to instantiate new entities.
207
+ *
208
+ * @param {string} id - The ID to use for the new entity
209
+ * @returns {T} A new entity instance
210
+ * @throws {Error} If not overridden in derived class
211
+ */
212
+ entityFactory(id) {
213
+ // Override this method in derived classes to provide entity creation logic
214
+ throw new Error("Entity factory not implemented.");
215
+ }
128
216
  }
129
217
  exports.AppObjectEntityRepo = AppObjectEntityRepo;
130
218
  //# sourceMappingURL=AppObjectEntityRepo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppObjectEntityRepo.js","sourceRoot":"","sources":["../../../src/AppObject/AppObjectEntityRepo.ts"],"names":[],"mappings":";;;AAAA,0CAA2C;AAC3C,uDAAoD;AAEpD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAa,mBAEX,SAAQ,iCAAe;IAFzB;;QAGU,iBAAY,GAAG,IAAI,GAAG,EAAa,CAAC;QAEpC,2BAAsB,GAAG,IAAI,uBAAY,EAAK,CAAC;QACvD;;;;WAIG;QACH,2BAAsB,GAAG,CAAC,QAAkC,EAAE,EAAE;YAC9D,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5C,CAAC,CAAC;QAEF;;;;WAIG;QACH,8BAAyB,GAAG,CAAC,QAAkC,EAAQ,EAAE;YACvE,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/C,CAAC,CAAC;QAEM,6BAAwB,GAAG,IAAI,uBAAY,EAAK,CAAC;QACzD;;;;WAIG;QACH,6BAAwB,GAAG,CAAC,QAAoC,EAAE,EAAE;YAClE,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9C,CAAC,CAAC;QAEF;;;;WAIG;QACH,gCAA2B,GAAG,CAC5B,QAAoC,EAC9B,EAAE;YACR,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjD,CAAC,CAAC;QAEF;;;;;WAKG;QACH,oBAAe,GAAG,CAAC,WAAmB,EAAW,EAAE;YACjD,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC5C,CAAC,CAAC;QAsBF;;;;;;WAMG;QACH,uBAAkB,GAAG,CAAC,EAAU,EAAE,EAAE;YAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3C,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAEtB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC7B,QAAQ,CAAC,oBAAoB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACnD,IAAI,CAAC,cAAc,EAAE,CAAC;YACtB,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjD,CAAC,CAAC;QAEF;;;;;WAKG;QACH,oBAAe,GAAG,CAAC,WAAmB,EAAiB,EAAE;YACvD,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC5C,CAAC,CAAC;QAEF;;;;WAIG;QACH,WAAM,GAAG,GAAQ,EAAE;YACjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;QAChD,CAAC,CAAC;IACJ,CAAC;IAvDC;;;;;;;OAOG;IACH,GAAG,CAAC,MAAS;QACX,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC5D,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,oBAAoB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACrD,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACnD,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC9C,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;CAqCF;AA9GD,kDA8GC","sourcesContent":["import { ObserverList } from \"../Entities\";\r\nimport { AppObjectEntity } from \"./AppObjectEntity\";\r\n\r\n/**\r\n * A repository for managing collections of AppObjectEntity instances.\r\n *\r\n * This generic class provides a centralized way to store, retrieve, and manage\r\n * entities that are associated with specific AppObjects. It implements the observer\r\n * pattern to notify listeners when entities are added or removed.\r\n *\r\n * @template T - The type of entities managed by this repository, must extend AppObjectEntity\r\n * @extends AppObjectEntity\r\n *\r\n * @example\r\n * ```typescript\r\n * // Create a repository for player entities\r\n * const playerRepo = new AppObjectEntityRepo<PlayerEntity>();\r\n *\r\n * // Add a new player\r\n * const player = new PlayerEntity(appObject);\r\n * playerRepo.add(player);\r\n *\r\n * // Get a player by its AppObject ID\r\n * const retrievedPlayer = playerRepo.getForAppObject(\"player1\");\r\n * ```\r\n */\r\nexport class AppObjectEntityRepo<\r\n T extends AppObjectEntity,\r\n> extends AppObjectEntity {\r\n private entityLookup = new Map<string, T>();\r\n\r\n private onEntityAddedObservers = new ObserverList<T>();\r\n /**\r\n * Registers an observer to be notified when an entity is added to the repository.\r\n *\r\n * @param {(addedEntity: T) => void} observer - The callback function to invoke when an entity is added\r\n */\r\n addEntityAddedObserver = (observer: (addedEntity: T) => void) => {\r\n this.onEntityAddedObservers.add(observer);\r\n };\r\n\r\n /**\r\n * Removes an observer previously registered for entity addition notifications.\r\n *\r\n * @param {(addedEntity: T) => void} observer - The callback function to remove\r\n */\r\n removeEntityAddedObserver = (observer: (addedEntity: T) => void): void => {\r\n this.onEntityAddedObservers.remove(observer);\r\n };\r\n\r\n private onEntityRemovedObservers = new ObserverList<T>();\r\n /**\r\n * Registers an observer to be notified when an entity is removed from the repository.\r\n *\r\n * @param {(removedEntity: T) => void} observer - The callback function to invoke when an entity is removed\r\n */\r\n addEntityRemovedObserver = (observer: (removedEntity: T) => void) => {\r\n this.onEntityRemovedObservers.add(observer);\r\n };\r\n\r\n /**\r\n * Removes an observer previously registered for entity removal notifications.\r\n *\r\n * @param {(removedEntity: T) => void} observer - The callback function to remove\r\n */\r\n removeEntityRemovedObserver = (\r\n observer: (removedEntity: T) => void\r\n ): void => {\r\n this.onEntityRemovedObservers.remove(observer);\r\n };\r\n\r\n /**\r\n * Checks if an entity exists for the given AppObject ID.\r\n *\r\n * @param {string} appObjectID - The ID of the AppObject\r\n * @returns {boolean} True if an entity exists for the given AppObject ID, false otherwise\r\n */\r\n hasForAppObject = (appObjectID: string): boolean => {\r\n return this.entityLookup.has(appObjectID);\r\n };\r\n\r\n /**\r\n * Adds an entity to the repository.\r\n *\r\n * If an entity with the same AppObject ID already exists, it is replaced.\r\n * Notifies all registered observers after the entity is added.\r\n *\r\n * @param {T} entity - The entity to add\r\n */\r\n add(entity: T) {\r\n const existing = this.entityLookup.get(entity.appObject.id);\r\n if (existing) {\r\n existing.removeChangeObserver(this.notifyOnChange);\r\n }\r\n\r\n this.entityLookup.set(entity.appObject.id, entity);\r\n entity.addChangeObserver(this.notifyOnChange);\r\n this.notifyOnChange();\r\n this.onEntityAddedObservers.notify(entity);\r\n }\r\n\r\n /**\r\n * Removes the entity associated with the specified AppObject ID.\r\n *\r\n * Notifies all registered observers after the entity is removed.\r\n *\r\n * @param {string} id - The ID of the AppObject whose entity should be removed\r\n */\r\n removeForAppObject = (id: string) => {\r\n const existing = this.entityLookup.get(id);\r\n if (!existing) return;\r\n\r\n this.entityLookup.delete(id);\r\n existing.removeChangeObserver(this.notifyOnChange);\r\n this.notifyOnChange();\r\n this.onEntityRemovedObservers.notify(existing);\r\n };\r\n\r\n /**\r\n * Gets the entity associated with the specified AppObject ID.\r\n *\r\n * @param {string} appObjectID - The ID of the AppObject\r\n * @returns {T | undefined} The entity if found, undefined otherwise\r\n */\r\n getForAppObject = (appObjectID: string): T | undefined => {\r\n return this.entityLookup.get(appObjectID);\r\n };\r\n\r\n /**\r\n * Gets all entities in the repository.\r\n *\r\n * @returns {T[]} An array of all entities\r\n */\r\n getAll = (): T[] => {\r\n return Array.from(this.entityLookup.values());\r\n };\r\n}\r\n"]}
1
+ {"version":3,"file":"AppObjectEntityRepo.js","sourceRoot":"","sources":["../../../src/AppObject/AppObjectEntityRepo.ts"],"names":[],"mappings":"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","sourcesContent":["import { ObserverList } from \"../Entities\";\r\nimport { generateUniqueID } from \"../Utilities\";\r\nimport { AppObjectEntity } from \"./AppObjectEntity\";\r\n\r\n/**\r\n * A repository for managing collections of AppObjectEntity instances.\r\n *\r\n * This generic class provides a centralized way to store, retrieve, and manage\r\n * entities that are associated with specific AppObjects. It implements the observer\r\n * pattern to notify listeners when entities are added or removed.\r\n *\r\n * Derived classes should override the `entityFactory` method to provide custom\r\n * entity creation logic for the `create` method.\r\n *\r\n * @template T - The type of entities managed by this repository, must extend AppObjectEntity\r\n * @extends AppObjectEntity\r\n *\r\n * @example\r\n * ```typescript\r\n * // Create a custom repository with entity factory\r\n * class PlayerRepo extends AppObjectEntityRepo<PlayerEntity> {\r\n * entityFactory(id: string): PlayerEntity {\r\n * const appObject = makeAppObject(id, this.appObjects);\r\n * return new PlayerEntity(appObject);\r\n * }\r\n * }\r\n *\r\n * const playerRepo = new PlayerRepo(repoAppObject);\r\n *\r\n * // Create a new player with auto-generated ID\r\n * const player = playerRepo.create();\r\n *\r\n * // Create a new player with specific ID\r\n * const specificPlayer = playerRepo.create(\"player1\");\r\n *\r\n * // Get a player by its ID\r\n * const retrievedPlayer = playerRepo.getById(\"player1\");\r\n * ```\r\n */\r\nexport class AppObjectEntityRepo<\r\n T extends AppObjectEntity,\r\n> extends AppObjectEntity {\r\n private entityLookup = new Map<string, T>();\r\n\r\n private onEntityAddedObservers = new ObserverList<T>();\r\n /**\r\n * Registers an observer to be notified when an entity is added to the repository.\r\n *\r\n * @param {(addedEntity: T) => void} observer - The callback function to invoke when an entity is added\r\n */\r\n addEntityAddedObserver = (observer: (addedEntity: T) => void) => {\r\n this.onEntityAddedObservers.add(observer);\r\n };\r\n\r\n /**\r\n * Removes an observer previously registered for entity addition notifications.\r\n *\r\n * @param {(addedEntity: T) => void} observer - The callback function to remove\r\n */\r\n removeEntityAddedObserver = (observer: (addedEntity: T) => void): void => {\r\n this.onEntityAddedObservers.remove(observer);\r\n };\r\n\r\n private onEntityRemovedObservers = new ObserverList<T>();\r\n /**\r\n * Registers an observer to be notified when an entity is removed from the repository.\r\n *\r\n * @param {(removedEntity: T) => void} observer - The callback function to invoke when an entity is removed\r\n */\r\n addEntityRemovedObserver = (observer: (removedEntity: T) => void) => {\r\n this.onEntityRemovedObservers.add(observer);\r\n };\r\n\r\n /**\r\n * Removes an observer previously registered for entity removal notifications.\r\n *\r\n * @param {(removedEntity: T) => void} observer - The callback function to remove\r\n */\r\n removeEntityRemovedObserver = (\r\n observer: (removedEntity: T) => void\r\n ): void => {\r\n this.onEntityRemovedObservers.remove(observer);\r\n };\r\n\r\n /**\r\n * Checks if an entity exists for the given ID.\r\n *\r\n * @param {string} id - The ID of the AppObject\r\n * @returns {boolean} True if an entity exists for the given ID, false otherwise\r\n */\r\n has = (id: string): boolean => {\r\n return this.entityLookup.has(id);\r\n };\r\n\r\n /**\r\n * Checks if an entity exists for the given AppObject ID.\r\n *\r\n * @param {string} appObjectID - The ID of the AppObject\r\n * @returns {boolean} True if an entity exists for the given AppObject ID, false otherwise\r\n * @deprecated Use has instead\r\n */\r\n hasForAppObject = (appObjectID: string): boolean => {\r\n return this.has(appObjectID);\r\n };\r\n\r\n /**\r\n * Adds an entity to the repository.\r\n *\r\n * If an entity with the same AppObject ID already exists, it is replaced.\r\n * Notifies all registered observers after the entity is added.\r\n *\r\n * @param {T} entity - The entity to add\r\n */\r\n add(entity: T) {\r\n const existing = this.entityLookup.get(entity.appObject.id);\r\n if (existing) {\r\n existing.removeChangeObserver(this.notifyOnChange);\r\n }\r\n\r\n this.entityLookup.set(entity.appObject.id, entity);\r\n entity.addChangeObserver(this.notifyOnChange);\r\n this.notifyOnChange();\r\n this.onEntityAddedObservers.notify(entity);\r\n }\r\n\r\n /**\r\n * Creates a new entity with the specified or auto-generated ID and adds it to the repository.\r\n *\r\n * This method uses the `entityFactory` method to create the entity instance.\r\n * If no ID is provided, a unique ID is generated automatically.\r\n *\r\n * @param {string} [id] - Optional ID for the entity. If not provided, a unique ID is generated.\r\n * @returns {T} The newly created entity\r\n */\r\n create(id?: string): T {\r\n const idToUse = id ?? generateUniqueID();\r\n const entity = this.entityFactory(idToUse);\r\n this.add(entity);\r\n return entity;\r\n }\r\n\r\n /**\r\n * Factory method for creating entity instances.\r\n *\r\n * This method must be overridden in derived classes to provide custom entity creation logic.\r\n * It is called by the `create` method to instantiate new entities.\r\n *\r\n * @param {string} id - The ID to use for the new entity\r\n * @returns {T} A new entity instance\r\n * @throws {Error} If not overridden in derived class\r\n */\r\n entityFactory(id: string): T {\r\n // Override this method in derived classes to provide entity creation logic\r\n throw new Error(\"Entity factory not implemented.\");\r\n }\r\n\r\n /**\r\n * Removes the entity associated with the specified ID.\r\n *\r\n * Notifies all registered observers after the entity is removed.\r\n *\r\n * @param {string} id - The ID of the AppObject whose entity should be removed\r\n */\r\n removeById = (id: string) => {\r\n const existing = this.entityLookup.get(id);\r\n if (!existing) return;\r\n\r\n this.entityLookup.delete(id);\r\n existing.removeChangeObserver(this.notifyOnChange);\r\n this.notifyOnChange();\r\n this.onEntityRemovedObservers.notify(existing);\r\n };\r\n\r\n /**\r\n * Removes the entity associated with the specified AppObject ID.\r\n *\r\n * Notifies all registered observers after the entity is removed.\r\n *\r\n * @param {string} id - The ID of the AppObject whose entity should be removed\r\n * @deprecated Use removeById instead\r\n */\r\n removeForAppObject = (id: string) => {\r\n this.removeById(id);\r\n };\r\n\r\n /**\r\n * Removes all entities from the repository.\r\n *\r\n * Unsubscribes from all entity change observers and notifies all registered\r\n * removal observers for each entity before clearing the repository.\r\n */\r\n deleteAll = () => {\r\n const entities = Array.from(this.entityLookup.values());\r\n\r\n entities.forEach((entity) => {\r\n entity.removeChangeObserver(this.notifyOnChange);\r\n this.onEntityRemovedObservers.notify(entity);\r\n });\r\n\r\n this.entityLookup.clear();\r\n this.notifyOnChange();\r\n };\r\n\r\n /**\r\n * Gets the entity associated with the specified ID.\r\n *\r\n * @param {string} id - The ID of the AppObject\r\n * @returns {T | undefined} The entity if found, undefined otherwise\r\n */\r\n getById = (id: string): T | undefined => {\r\n return this.entityLookup.get(id);\r\n };\r\n\r\n /**\r\n * Gets the entity associated with the specified AppObject ID.\r\n *\r\n * @param {string} appObjectID - The ID of the AppObject\r\n * @returns {T | undefined} The entity if found, undefined otherwise\r\n * @deprecated Use getById instead\r\n */\r\n getForAppObject = (appObjectID: string): T | undefined => {\r\n return this.getById(appObjectID);\r\n };\r\n\r\n /**\r\n * Gets all entities in the repository.\r\n *\r\n * @returns {T[]} An array of all entities\r\n */\r\n getAll = (): T[] => {\r\n return Array.from(this.entityLookup.values());\r\n };\r\n}\r\n"]}
@@ -24,13 +24,21 @@ class AppObjectPM extends AppObjectComponent_1.AppObjectComponent {
24
24
  /** Identifies this as a Presentation Manager component */
25
25
  this.componentType = AppObjectComponent_1.AppObjectComponentType.PM;
26
26
  /** List of view update functions to notify when the view model changes */
27
- this.observerList = new Entities_1.ObserverList();
27
+ this.views = new Entities_1.ObserverList();
28
+ /**
29
+ * List of entities being observed by this PM.
30
+ * Used for automatic cleanup during disposal.
31
+ */
32
+ this.observedEntities = [];
28
33
  }
29
34
  /**
30
35
  * Gets the most recently generated view model
31
- * @returns The last view model or undefined if none has been generated
36
+ * @returns The last view model, or `defaultVM` if no view model has been generated yet,
37
+ * or undefined if neither exists
32
38
  */
33
39
  get lastVM() {
40
+ if (!this._lastVM)
41
+ return this.defaultVM;
34
42
  return this._lastVM;
35
43
  }
36
44
  /**
@@ -40,11 +48,92 @@ class AppObjectPM extends AppObjectComponent_1.AppObjectComponent {
40
48
  * @param updateView Function to call with updated view models
41
49
  */
42
50
  addView(updateView) {
43
- this.observerList.add(updateView);
51
+ if (this.views.length === 0) {
52
+ // There are no views yet - generate the initial view model
53
+ this.formVM();
54
+ }
55
+ this.views.add(updateView);
44
56
  // Immediately update the view with current view model if one exists
45
57
  if (this._lastVM !== undefined) {
46
58
  updateView(this._lastVM);
47
59
  }
60
+ this.onViewAdded();
61
+ }
62
+ /**
63
+ * Called when an observed entity changes.
64
+ * If views are registered, this method calls `formVM()` to regenerate the view model.
65
+ *
66
+ * This method is automatically invoked when entities registered via `observeEntity()`
67
+ * notify their observers. It implements lazy evaluation - view models are only
68
+ * formed when there are views to receive them.
69
+ */
70
+ onEntityChanged() {
71
+ if (this.views.length === 0) {
72
+ return;
73
+ }
74
+ else {
75
+ this.formVM();
76
+ }
77
+ }
78
+ /**
79
+ * Forms and updates the view model based on current entity state.
80
+ *
81
+ * Override this method in derived classes to:
82
+ * 1. Read data from observed entities
83
+ * 2. Transform the data into a view model
84
+ * 3. Call `doUpdateView(vm)` with the new view model
85
+ *
86
+ * This method is only called when at least one view has been registered,
87
+ * implementing lazy evaluation to avoid unnecessary computation.
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * formVM(): void {
92
+ * const entity = this.getCachedLocalComponent<MyEntity>(MyEntity.type);
93
+ * if (entity) {
94
+ * this.doUpdateView({
95
+ * displayName: entity.name,
96
+ * isActive: entity.active
97
+ * });
98
+ * }
99
+ * }
100
+ * ```
101
+ */
102
+ formVM() {
103
+ // To be implemented by derived classes
104
+ // Form up the VM and then call doUpdateView(vm: T)
105
+ // This will only be called if at least one view has been registered
106
+ }
107
+ onViewAdded() {
108
+ // Can be overridden by derived classes to react when the first view is added
109
+ }
110
+ /**
111
+ * Registers an entity to be observed for changes.
112
+ *
113
+ * When the entity notifies of changes (via `notifyOnChange()`), this PM will
114
+ * automatically call `onEntityChanged()`, which in turn calls `formVM()` if
115
+ * views are registered.
116
+ *
117
+ * The entity observer is automatically cleaned up when this PM is disposed.
118
+ *
119
+ * @param entity The entity to observe for changes
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * constructor(appObj: AppObject) {
124
+ * super(appObj, MyPM.type);
125
+ * const entity = appObj.getComponent<MyEntity>(MyEntity.type);
126
+ * if (entity) {
127
+ * this.observeEntity(entity);
128
+ * }
129
+ * }
130
+ * ```
131
+ */
132
+ observeEntity(entity) {
133
+ entity.addChangeObserver(() => {
134
+ this.onEntityChanged();
135
+ });
136
+ this.observedEntities.push(entity);
48
137
  }
49
138
  /**
50
139
  * Unregisters a previously added view update function
@@ -52,7 +141,7 @@ class AppObjectPM extends AppObjectComponent_1.AppObjectComponent {
52
141
  * @param updateView The view update function to remove
53
142
  */
54
143
  removeView(updateView) {
55
- this.observerList.remove(updateView);
144
+ this.views.remove(updateView);
56
145
  }
57
146
  /**
58
147
  * Updates the view model and notifies all registered views if the model has changed
@@ -69,13 +158,24 @@ class AppObjectPM extends AppObjectComponent_1.AppObjectComponent {
69
158
  return;
70
159
  }
71
160
  this._lastVM = vm;
72
- this.observerList.notify(vm);
161
+ this.views.notify(vm);
73
162
  }
74
163
  /**
75
164
  * Cleans up resources and detaches this PM from its parent AppObject
165
+ *
166
+ * This method:
167
+ * 1. Removes change observers from all observed entities
168
+ * 2. Clears all view observers
169
+ * 3. Removes this component from its parent AppObject if still attached
170
+ * 4. Calls the parent class dispose method
76
171
  */
77
172
  dispose() {
78
- this.observerList.clear();
173
+ this.observedEntities.forEach((entity) => {
174
+ entity.removeChangeObserver(() => {
175
+ this.onEntityChanged();
176
+ });
177
+ });
178
+ this.views.clear();
79
179
  if (this.appObject.getComponent(this.type) === this) {
80
180
  this.appObject.removeComponent(this.type);
81
181
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AppObjectPM.js","sourceRoot":"","sources":["../../../src/AppObject/AppObjectPM.ts"],"names":[],"mappings":";;;AAAA,0CAA2C;AAC3C,6DAAkF;AAElF;;;;;;;;;;;;;;GAcG;AACH,MAAsB,WAAe,SAAQ,uCAAkB;IAA/D;;QACE,0DAA0D;QACjD,kBAAa,GAAG,2CAAsB,CAAC,EAAE,CAAC;QAuBnD,0EAA0E;QAClE,iBAAY,GAAG,IAAI,uBAAY,EAAK,CAAC;IAuD/C,CAAC;IAhEC;;;OAGG;IACH,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAKD;;;;;OAKG;IACH,OAAO,CAAC,UAA2B;QACjC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAElC,oEAAoE;QACpE,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAC/B,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,UAA2B;QACpC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACvC,CAAC;IAED;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAK;QAChB,+CAA+C;QAC/C,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;YACvD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,OAAO;QACL,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACpD,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC;QACD,KAAK,CAAC,OAAO,EAAE,CAAC;IAClB,CAAC;CACF;AAjFD,kCAiFC","sourcesContent":["import { ObserverList } from \"../Entities\";\r\nimport { AppObjectComponent, AppObjectComponentType } from \"./AppObjectComponent\";\r\n\r\n/**\r\n * Presentation Manager (PM) component that transforms application state into view models\r\n * \r\n * AppObjectPM acts as a mediator between application state (entities) and views.\r\n * It transforms raw application data into a format that's optimized for presentation,\r\n * implementing the presentation model or MVVM pattern.\r\n * \r\n * A PM typically:\r\n * 1. Observes entity changes\r\n * 2. Transforms entity data into view models\r\n * 3. Notifies attached views when view models change\r\n * 4. Handles view model caching and optimization\r\n * \r\n * @typeparam T The view model type this PM produces\r\n */\r\nexport abstract class AppObjectPM<T> extends AppObjectComponent {\r\n /** Identifies this as a Presentation Manager component */\r\n readonly componentType = AppObjectComponentType.PM;\r\n \r\n /**\r\n * Compares two view models to determine if they're equivalent\r\n * Used to prevent unnecessary view updates when the view model hasn't changed\r\n * \r\n * @param a First view model to compare\r\n * @param b Second view model to compare\r\n * @returns True if the view models are considered equal, false otherwise\r\n */\r\n abstract vmsAreEqual(a: T, b: T): boolean;\r\n\r\n /** The most recently generated view model */\r\n private _lastVM?: T;\r\n \r\n /**\r\n * Gets the most recently generated view model\r\n * @returns The last view model or undefined if none has been generated\r\n */\r\n get lastVM(): T | undefined {\r\n return this._lastVM;\r\n }\r\n\r\n /** List of view update functions to notify when the view model changes */\r\n private observerList = new ObserverList<T>();\r\n\r\n /**\r\n * Registers a view update function to be called when the view model changes\r\n * If a view model already exists, the provided function is called immediately with that model\r\n * \r\n * @param updateView Function to call with updated view models\r\n */\r\n addView(updateView: (vm: T) => void): void {\r\n this.observerList.add(updateView);\r\n\r\n // Immediately update the view with current view model if one exists\r\n if (this._lastVM !== undefined) {\r\n updateView(this._lastVM);\r\n }\r\n }\r\n\r\n /**\r\n * Unregisters a previously added view update function\r\n * \r\n * @param updateView The view update function to remove\r\n */\r\n removeView(updateView: (vm: T) => void): void {\r\n this.observerList.remove(updateView);\r\n }\r\n\r\n /**\r\n * Updates the view model and notifies all registered views if the model has changed\r\n * This method should be called by derived classes when the view model needs to be updated\r\n * \r\n * The method performs equality checking to prevent unnecessary updates when\r\n * the new view model is equivalent to the previous one\r\n * \r\n * @param vm The new view model\r\n */\r\n doUpdateView(vm: T) {\r\n // Skip update if the view model hasn't changed\r\n if (this._lastVM && this.vmsAreEqual(this._lastVM, vm)) {\r\n return;\r\n }\r\n\r\n this._lastVM = vm;\r\n this.observerList.notify(vm);\r\n }\r\n\r\n /**\r\n * Cleans up resources and detaches this PM from its parent AppObject\r\n */\r\n dispose() {\r\n this.observerList.clear();\r\n if (this.appObject.getComponent(this.type) === this) {\r\n this.appObject.removeComponent(this.type);\r\n }\r\n super.dispose();\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"AppObjectPM.js","sourceRoot":"","sources":["../../../src/AppObject/AppObjectPM.ts"],"names":[],"mappings":"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","sourcesContent":["import { ObserverList } from \"../Entities\";\r\nimport {\r\n AppObjectComponent,\r\n AppObjectComponentType,\r\n} from \"./AppObjectComponent\";\r\nimport { AppObjectEntity } from \"./AppObjectEntity\";\r\n\r\n/**\r\n * Presentation Manager (PM) component that transforms application state into view models\r\n *\r\n * AppObjectPM acts as a mediator between application state (entities) and views.\r\n * It transforms raw application data into a format that's optimized for presentation,\r\n * implementing the presentation model or MVVM pattern.\r\n *\r\n * A PM typically:\r\n * 1. Observes entity changes\r\n * 2. Transforms entity data into view models\r\n * 3. Notifies attached views when view models change\r\n * 4. Handles view model caching and optimization\r\n *\r\n * @typeparam T The view model type this PM produces\r\n */\r\nexport abstract class AppObjectPM<T> extends AppObjectComponent {\r\n /** Identifies this as a Presentation Manager component */\r\n readonly componentType = AppObjectComponentType.PM;\r\n\r\n /**\r\n * Compares two view models to determine if they're equivalent\r\n * Used to prevent unnecessary view updates when the view model hasn't changed\r\n *\r\n * @param a First view model to compare\r\n * @param b Second view model to compare\r\n * @returns True if the view models are considered equal, false otherwise\r\n */\r\n abstract vmsAreEqual(a: T, b: T): boolean;\r\n\r\n /** The most recently generated view model */\r\n private _lastVM?: T;\r\n\r\n /**\r\n * Optional default view model to return when no view model has been generated yet.\r\n * If set, this value will be returned by the `lastVM` getter before any view model\r\n * has been created via `doUpdateView`.\r\n *\r\n * This is useful for providing initial state to views without requiring immediate\r\n * view model generation.\r\n */\r\n public defaultVM?: T;\r\n\r\n /**\r\n * Gets the most recently generated view model\r\n * @returns The last view model, or `defaultVM` if no view model has been generated yet,\r\n * or undefined if neither exists\r\n */\r\n get lastVM(): T | undefined {\r\n if (!this._lastVM) return this.defaultVM;\r\n return this._lastVM;\r\n }\r\n\r\n /** List of view update functions to notify when the view model changes */\r\n private views = new ObserverList<T>();\r\n\r\n /**\r\n * List of entities being observed by this PM.\r\n * Used for automatic cleanup during disposal.\r\n */\r\n private observedEntities: AppObjectEntity[] = [];\r\n\r\n /**\r\n * Registers a view update function to be called when the view model changes\r\n * If a view model already exists, the provided function is called immediately with that model\r\n *\r\n * @param updateView Function to call with updated view models\r\n */\r\n addView(updateView: (vm: T) => void): void {\r\n if (this.views.length === 0) {\r\n // There are no views yet - generate the initial view model\r\n this.formVM();\r\n }\r\n\r\n this.views.add(updateView);\r\n \r\n // Immediately update the view with current view model if one exists\r\n if (this._lastVM !== undefined) {\r\n updateView(this._lastVM);\r\n }\r\n\r\n this.onViewAdded();\r\n }\r\n\r\n /**\r\n * Called when an observed entity changes.\r\n * If views are registered, this method calls `formVM()` to regenerate the view model.\r\n *\r\n * This method is automatically invoked when entities registered via `observeEntity()`\r\n * notify their observers. It implements lazy evaluation - view models are only\r\n * formed when there are views to receive them.\r\n */\r\n onEntityChanged(): void {\r\n if (this.views.length === 0) {\r\n return;\r\n } else {\r\n this.formVM();\r\n }\r\n }\r\n\r\n /**\r\n * Forms and updates the view model based on current entity state.\r\n *\r\n * Override this method in derived classes to:\r\n * 1. Read data from observed entities\r\n * 2. Transform the data into a view model\r\n * 3. Call `doUpdateView(vm)` with the new view model\r\n *\r\n * This method is only called when at least one view has been registered,\r\n * implementing lazy evaluation to avoid unnecessary computation.\r\n *\r\n * @example\r\n * ```typescript\r\n * formVM(): void {\r\n * const entity = this.getCachedLocalComponent<MyEntity>(MyEntity.type);\r\n * if (entity) {\r\n * this.doUpdateView({\r\n * displayName: entity.name,\r\n * isActive: entity.active\r\n * });\r\n * }\r\n * }\r\n * ```\r\n */\r\n formVM(): void {\r\n // To be implemented by derived classes\r\n // Form up the VM and then call doUpdateView(vm: T)\r\n // This will only be called if at least one view has been registered\r\n }\r\n\r\n onViewAdded(): void {\r\n // Can be overridden by derived classes to react when the first view is added\r\n }\r\n\r\n /**\r\n * Registers an entity to be observed for changes.\r\n *\r\n * When the entity notifies of changes (via `notifyOnChange()`), this PM will\r\n * automatically call `onEntityChanged()`, which in turn calls `formVM()` if\r\n * views are registered.\r\n *\r\n * The entity observer is automatically cleaned up when this PM is disposed.\r\n *\r\n * @param entity The entity to observe for changes\r\n *\r\n * @example\r\n * ```typescript\r\n * constructor(appObj: AppObject) {\r\n * super(appObj, MyPM.type);\r\n * const entity = appObj.getComponent<MyEntity>(MyEntity.type);\r\n * if (entity) {\r\n * this.observeEntity(entity);\r\n * }\r\n * }\r\n * ```\r\n */\r\n protected observeEntity(entity: AppObjectEntity): void {\r\n entity.addChangeObserver(() => {\r\n this.onEntityChanged();\r\n });\r\n\r\n this.observedEntities.push(entity);\r\n }\r\n\r\n /**\r\n * Unregisters a previously added view update function\r\n *\r\n * @param updateView The view update function to remove\r\n */\r\n removeView(updateView: (vm: T) => void): void {\r\n this.views.remove(updateView);\r\n }\r\n\r\n /**\r\n * Updates the view model and notifies all registered views if the model has changed\r\n * This method should be called by derived classes when the view model needs to be updated\r\n *\r\n * The method performs equality checking to prevent unnecessary updates when\r\n * the new view model is equivalent to the previous one\r\n *\r\n * @param vm The new view model\r\n */\r\n doUpdateView(vm: T) {\r\n // Skip update if the view model hasn't changed\r\n if (this._lastVM && this.vmsAreEqual(this._lastVM, vm)) {\r\n return;\r\n }\r\n\r\n this._lastVM = vm;\r\n this.views.notify(vm);\r\n }\r\n\r\n /**\r\n * Cleans up resources and detaches this PM from its parent AppObject\r\n *\r\n * This method:\r\n * 1. Removes change observers from all observed entities\r\n * 2. Clears all view observers\r\n * 3. Removes this component from its parent AppObject if still attached\r\n * 4. Calls the parent class dispose method\r\n */\r\n dispose() {\r\n this.observedEntities.forEach((entity) => {\r\n entity.removeChangeObserver(() => {\r\n this.onEntityChanged();\r\n });\r\n });\r\n\r\n this.views.clear();\r\n if (this.appObject.getComponent(this.type) === this) {\r\n this.appObject.removeComponent(this.type);\r\n }\r\n super.dispose();\r\n }\r\n}\r\n"]}
@@ -127,10 +127,20 @@ class AppObjectRepoImp extends AppObjectRepo {
127
127
  }
128
128
  registerSingleton(component) {
129
129
  if (this.singletons.has(component.type)) {
130
- this.submitWarning("AppObjectRepo", `Singleton for type ${component.type} already exists. Relpacing`);
130
+ this.submitWarning("AppObjectRepo", `Singleton for type ${component.type} already exists. Replacing`);
131
131
  }
132
132
  this.singletons.set(component.type, component);
133
133
  }
134
+ unregisterSingleton(type) {
135
+ this.singletons.delete(type);
136
+ }
137
+ hasSingleton(type) {
138
+ if (this.singletons.has(type)) {
139
+ return true;
140
+ }
141
+ const components = this.getAllComponents(type);
142
+ return components.length === 1;
143
+ }
134
144
  getSingleton(type) {
135
145
  if (this.singletons.has(type)) {
136
146
  return this.singletons.get(type);