@relax.js/core 1.0.4 → 1.0.5

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 (228) hide show
  1. package/dist/DependencyInjection.d.ts +3 -3
  2. package/dist/collections/LinkedList.d.ts +9 -8
  3. package/dist/collections/index.js +1 -1
  4. package/dist/collections/index.js.map +3 -3
  5. package/dist/collections/index.mjs +1 -1
  6. package/dist/collections/index.mjs.map +3 -3
  7. package/dist/di/index.js +1 -1
  8. package/dist/di/index.js.map +2 -2
  9. package/dist/di/index.mjs +1 -1
  10. package/dist/di/index.mjs.map +2 -2
  11. package/dist/elements/index.js +1 -1
  12. package/dist/elements/index.js.map +1 -1
  13. package/dist/forms/FormValidator.d.ts +2 -2
  14. package/dist/forms/ValidationRules.d.ts +2 -6
  15. package/dist/forms/index.js +1 -1
  16. package/dist/forms/index.js.map +3 -3
  17. package/dist/forms/index.mjs +1 -1
  18. package/dist/forms/index.mjs.map +3 -3
  19. package/dist/forms/setFormData.d.ts +39 -1
  20. package/dist/html/index.js +1 -1
  21. package/dist/html/index.js.map +3 -3
  22. package/dist/html/index.mjs +1 -1
  23. package/dist/html/index.mjs.map +3 -3
  24. package/dist/http/ServerSentEvents.d.ts +1 -1
  25. package/dist/http/SimpleWebSocket.d.ts +1 -1
  26. package/dist/http/index.js +1 -1
  27. package/dist/http/index.js.map +3 -3
  28. package/dist/http/index.mjs +1 -1
  29. package/dist/http/index.mjs.map +3 -3
  30. package/dist/i18n/icu.d.ts +1 -1
  31. package/dist/i18n/index.js +1 -1
  32. package/dist/i18n/index.js.map +2 -2
  33. package/dist/i18n/index.mjs +1 -1
  34. package/dist/i18n/index.mjs.map +2 -2
  35. package/dist/index.js +3 -3
  36. package/dist/index.js.map +3 -3
  37. package/dist/index.mjs +3 -3
  38. package/dist/index.mjs.map +3 -3
  39. package/dist/routing/NavigateRouteEvent.d.ts +4 -4
  40. package/dist/routing/index.js +2 -2
  41. package/dist/routing/index.js.map +3 -3
  42. package/dist/routing/index.mjs +3 -3
  43. package/dist/routing/index.mjs.map +3 -3
  44. package/dist/routing/navigation.d.ts +1 -1
  45. package/dist/templates/NodeTemplate.d.ts +1 -1
  46. package/dist/utils/index.d.ts +1 -1
  47. package/dist/utils/index.js +1 -1
  48. package/dist/utils/index.js.map +3 -3
  49. package/dist/utils/index.mjs +1 -1
  50. package/dist/utils/index.mjs.map +3 -3
  51. package/docs/GettingStarted.md +7 -0
  52. package/docs/api.json +34 -12
  53. package/docs/forms/reading-writing.md +101 -1
  54. package/docs/setup/bootstrapping.md +154 -0
  55. package/docs/setup/build-and-deploy.md +183 -0
  56. package/docs/setup/project-structure.md +170 -0
  57. package/docs/setup/vite.md +175 -0
  58. package/package.json +3 -2
  59. package/docs/api/.nojekyll +0 -1
  60. package/docs/api/assets/hierarchy.js +0 -1
  61. package/docs/api/assets/highlight.css +0 -120
  62. package/docs/api/assets/icons.js +0 -18
  63. package/docs/api/assets/icons.svg +0 -1
  64. package/docs/api/assets/main.js +0 -60
  65. package/docs/api/assets/navigation.js +0 -1
  66. package/docs/api/assets/search.js +0 -1
  67. package/docs/api/assets/style.css +0 -1633
  68. package/docs/api/classes/http.WebSocketClient.html +0 -26
  69. package/docs/api/classes/i18n.LocaleChangeEvent.html +0 -66
  70. package/docs/api/classes/index.Blueprint.html +0 -3
  71. package/docs/api/classes/index.BoundNode.html +0 -3
  72. package/docs/api/classes/index.DigitsValidation.html +0 -10
  73. package/docs/api/classes/index.FormValidator.html +0 -32
  74. package/docs/api/classes/index.HttpError.html +0 -13
  75. package/docs/api/classes/index.LinkedList.html +0 -26
  76. package/docs/api/classes/index.NavigateRouteEvent.html +0 -76
  77. package/docs/api/classes/index.Node.html +0 -15
  78. package/docs/api/classes/index.PageSelectedEvent.html +0 -61
  79. package/docs/api/classes/index.Pager.html +0 -4
  80. package/docs/api/classes/index.RangeValidation.html +0 -15
  81. package/docs/api/classes/index.RelaxError.html +0 -17
  82. package/docs/api/classes/index.RequiredValidation.html +0 -10
  83. package/docs/api/classes/index.RouteError.html +0 -11
  84. package/docs/api/classes/index.RouteGuardError.html +0 -12
  85. package/docs/api/classes/index.RouteLink.html +0 -779
  86. package/docs/api/classes/index.RouteTarget.html +0 -788
  87. package/docs/api/classes/index.SSEClient.html +0 -13
  88. package/docs/api/classes/index.SSEDataEvent.html +0 -63
  89. package/docs/api/classes/index.ServiceCollection.html +0 -28
  90. package/docs/api/classes/index.ServiceContainer.html +0 -24
  91. package/docs/api/classes/index.SortChangeEvent.html +0 -61
  92. package/docs/api/classes/index.TableRenderer.html +0 -5
  93. package/docs/api/classes/index.TableSorter.html +0 -4
  94. package/docs/api/enums/index.GuardResult.html +0 -9
  95. package/docs/api/functions/elements.formError.html +0 -6
  96. package/docs/api/functions/elements.selectOne.html +0 -6
  97. package/docs/api/functions/i18n.getCurrentLocale.html +0 -3
  98. package/docs/api/functions/i18n.loadNamespace.html +0 -7
  99. package/docs/api/functions/i18n.loadNamespaces.html +0 -6
  100. package/docs/api/functions/i18n.onMissingTranslation.html +0 -7
  101. package/docs/api/functions/i18n.setLocale.html +0 -7
  102. package/docs/api/functions/i18n.setMessageFormatter.html +0 -7
  103. package/docs/api/functions/i18n.t.html +0 -9
  104. package/docs/api/functions/index.BooleanConverter.html +0 -6
  105. package/docs/api/functions/index.ContainerService.html +0 -13
  106. package/docs/api/functions/index.DateConverter.html +0 -11
  107. package/docs/api/functions/index.Inject.html +0 -16
  108. package/docs/api/functions/index.NumberConverter.html +0 -5
  109. package/docs/api/functions/index.RegisterValidator.html +0 -7
  110. package/docs/api/functions/index.applyPipes.html +0 -17
  111. package/docs/api/functions/index.asyncHandler.html +0 -11
  112. package/docs/api/functions/index.capitalizePipe.html +0 -4
  113. package/docs/api/functions/index.clearPendingNavigations.html +0 -1
  114. package/docs/api/functions/index.compileTemplate.html +0 -26
  115. package/docs/api/functions/index.configure.html +0 -5
  116. package/docs/api/functions/index.createBluePrint.html +0 -1
  117. package/docs/api/functions/index.createConverterFromDataType.html +0 -4
  118. package/docs/api/functions/index.createConverterFromInputType.html +0 -5
  119. package/docs/api/functions/index.createPipeRegistry.html +0 -12
  120. package/docs/api/functions/index.currencyPipe.html +0 -9
  121. package/docs/api/functions/index.datePipe.html +0 -9
  122. package/docs/api/functions/index.daysAgoPipe.html +0 -8
  123. package/docs/api/functions/index.defaultPipe.html +0 -5
  124. package/docs/api/functions/index.defineRoutes.html +0 -8
  125. package/docs/api/functions/index.del.html +0 -8
  126. package/docs/api/functions/index.findRouteByName.html +0 -5
  127. package/docs/api/functions/index.findRouteByUrl.html +0 -4
  128. package/docs/api/functions/index.firstPipe.html +0 -4
  129. package/docs/api/functions/index.generateSequentialId.html +0 -21
  130. package/docs/api/functions/index.get.html +0 -9
  131. package/docs/api/functions/index.getDataConverter.html +0 -11
  132. package/docs/api/functions/index.getParentComponent.html +0 -18
  133. package/docs/api/functions/index.getValidator.html +0 -4
  134. package/docs/api/functions/index.html.html +0 -19
  135. package/docs/api/functions/index.joinPipe.html +0 -5
  136. package/docs/api/functions/index.keysPipe.html +0 -4
  137. package/docs/api/functions/index.lastPipe.html +0 -4
  138. package/docs/api/functions/index.lowercasePipe.html +0 -4
  139. package/docs/api/functions/index.mapFormToClass.html +0 -17
  140. package/docs/api/functions/index.matchRoute.html +0 -5
  141. package/docs/api/functions/index.navigate.html +0 -8
  142. package/docs/api/functions/index.onError.html +0 -8
  143. package/docs/api/functions/index.piecesPipe.html +0 -8
  144. package/docs/api/functions/index.post.html +0 -9
  145. package/docs/api/functions/index.printRoutes.html +0 -2
  146. package/docs/api/functions/index.put.html +0 -9
  147. package/docs/api/functions/index.readData.html +0 -17
  148. package/docs/api/functions/index.registerRouteTarget.html +0 -9
  149. package/docs/api/functions/index.reportError.html +0 -10
  150. package/docs/api/functions/index.request.html +0 -8
  151. package/docs/api/functions/index.resolveValue.html +0 -18
  152. package/docs/api/functions/index.setFetch.html +0 -6
  153. package/docs/api/functions/index.setFormData.html +0 -17
  154. package/docs/api/functions/index.shortenPipe.html +0 -5
  155. package/docs/api/functions/index.startRouting.html +0 -6
  156. package/docs/api/functions/index.ternaryPipe.html +0 -6
  157. package/docs/api/functions/index.trimPipe.html +0 -4
  158. package/docs/api/functions/index.unregisterRouteTarget.html +0 -3
  159. package/docs/api/functions/index.uppercasePipe.html +0 -4
  160. package/docs/api/hierarchy.html +0 -1
  161. package/docs/api/index.html +0 -323
  162. package/docs/api/interfaces/http.SimpleDataEvent.html +0 -3
  163. package/docs/api/interfaces/http.WebSocketAbstraction.html +0 -9
  164. package/docs/api/interfaces/http.WebSocketCodec.html +0 -4
  165. package/docs/api/interfaces/http.WebSocketOptions.html +0 -20
  166. package/docs/api/interfaces/index.CompiledTemplate.html +0 -10
  167. package/docs/api/interfaces/index.DataLoader.html +0 -19
  168. package/docs/api/interfaces/index.EngineConfig.html +0 -11
  169. package/docs/api/interfaces/index.ErrorContext.html +0 -4
  170. package/docs/api/interfaces/index.FormReaderOptions.html +0 -8
  171. package/docs/api/interfaces/index.HttpOptions.html +0 -16
  172. package/docs/api/interfaces/index.HttpResponse.html +0 -17
  173. package/docs/api/interfaces/index.LoadRoute.html +0 -7
  174. package/docs/api/interfaces/index.NavigateOptions.html +0 -7
  175. package/docs/api/interfaces/index.PipeRegistry.html +0 -12
  176. package/docs/api/interfaces/index.RegistrationOptions.html +0 -22
  177. package/docs/api/interfaces/index.RenderTemplate.html +0 -7
  178. package/docs/api/interfaces/index.RequestOptions.html +0 -11
  179. package/docs/api/interfaces/index.Routable.html +0 -10
  180. package/docs/api/interfaces/index.Route.html +0 -13
  181. package/docs/api/interfaces/index.RouteGuard.html +0 -2
  182. package/docs/api/interfaces/index.RouteValue.html +0 -6
  183. package/docs/api/interfaces/index.SSEOptions.html +0 -24
  184. package/docs/api/interfaces/index.ValidationContext.html +0 -8
  185. package/docs/api/interfaces/index.ValidatorOptions.html +0 -14
  186. package/docs/api/media/Architecture.md +0 -333
  187. package/docs/api/media/DependencyInjection.md +0 -277
  188. package/docs/api/media/GettingStarted.md +0 -231
  189. package/docs/api/media/HttpClient.md +0 -459
  190. package/docs/api/media/Pipes.md +0 -211
  191. package/docs/api/media/Routing.md +0 -332
  192. package/docs/api/media/WhyRelaxjs.md +0 -336
  193. package/docs/api/media/forms.md +0 -99
  194. package/docs/api/media/html.md +0 -175
  195. package/docs/api/media/i18n.md +0 -354
  196. package/docs/api/media/utilities.md +0 -143
  197. package/docs/api/media/validation.md +0 -351
  198. package/docs/api/modules/collections_Index.html +0 -1
  199. package/docs/api/modules/di.html +0 -1
  200. package/docs/api/modules/elements.html +0 -1
  201. package/docs/api/modules/forms.html +0 -1
  202. package/docs/api/modules/html.html +0 -1
  203. package/docs/api/modules/http.html +0 -1
  204. package/docs/api/modules/i18n.html +0 -1
  205. package/docs/api/modules/index.html +0 -1
  206. package/docs/api/modules/routing.html +0 -1
  207. package/docs/api/modules/utils.html +0 -1
  208. package/docs/api/modules.html +0 -1
  209. package/docs/api/types/http.WebSocketFactory.html +0 -2
  210. package/docs/api/types/i18n.MessageFormatter.html +0 -3
  211. package/docs/api/types/i18n.MissingTranslationHandler.html +0 -1
  212. package/docs/api/types/index.Constructor.html +0 -7
  213. package/docs/api/types/index.ConverterFunc.html +0 -2
  214. package/docs/api/types/index.DataType.html +0 -2
  215. package/docs/api/types/index.InputType.html +0 -2
  216. package/docs/api/types/index.PipeFunction.html +0 -6
  217. package/docs/api/types/index.RouteData.html +0 -1
  218. package/docs/api/types/index.RouteMatchResult.html +0 -9
  219. package/docs/api/types/index.RouteParamType.html +0 -1
  220. package/docs/api/types/index.RouteSegmentType.html +0 -2
  221. package/docs/api/types/index.SSEEventFactory.html +0 -5
  222. package/docs/api/types/index.ServiceScope.html +0 -10
  223. package/docs/api/types/index.SortColumn.html +0 -3
  224. package/docs/api/variables/i18n.formatICU.html +0 -3
  225. package/docs/api/variables/index.container.html +0 -6
  226. package/docs/api/variables/index.defaultPipes.html +0 -6
  227. package/docs/api/variables/index.internalRoutes.html +0 -1
  228. package/docs/api/variables/index.serviceCollection.html +0 -6
@@ -141,8 +141,8 @@ declare class Registration {
141
141
  scope: ServiceScope;
142
142
  inject: (string | Constructor)[];
143
143
  properties: Record<string, string | Constructor>;
144
- key?: string;
145
- instance?: unknown;
144
+ key?: string | undefined;
145
+ instance?: unknown | undefined;
146
146
  /**
147
147
  * Creates a new registration record.
148
148
  *
@@ -153,7 +153,7 @@ declare class Registration {
153
153
  * @param key - Optional string identifier
154
154
  * @param instance - Optional pre-created instance
155
155
  */
156
- constructor(classConstructor: Constructor, scope: ServiceScope, inject: (string | Constructor)[], properties?: Record<string, string | Constructor>, key?: string, instance?: unknown);
156
+ constructor(classConstructor: Constructor, scope: ServiceScope, inject: (string | Constructor)[], properties?: Record<string, string | Constructor>, key?: string | undefined, instance?: unknown | undefined);
157
157
  }
158
158
  /**
159
159
  * Registry that stores service registration metadata.
@@ -27,8 +27,8 @@ export declare class Node<T> {
27
27
  * A trivial linked list implementation.
28
28
  */
29
29
  export declare class LinkedList<T> {
30
- private _first?;
31
- private _last?;
30
+ private _first;
31
+ private _last;
32
32
  private _length;
33
33
  /**
34
34
  * Add a value to the beginning of the list.
@@ -40,6 +40,7 @@ export declare class LinkedList<T> {
40
40
  * @param value Value that should be contained in a node.
41
41
  */
42
42
  addLast(value: T): void;
43
+ private createNode;
43
44
  /**
44
45
  * Remove a node from the beginning of the list.
45
46
  * @returns Value contained in the first node.
@@ -57,19 +58,19 @@ export declare class LinkedList<T> {
57
58
  */
58
59
  get length(): number;
59
60
  /**
60
- * First ndoe.
61
+ * First node, or `null` if the list is empty.
61
62
  */
62
- get first(): Node<T> | undefined;
63
+ get first(): Node<T> | null;
63
64
  /**
64
- * Contained value of the first node.
65
+ * Contained value of the first node, or `undefined` if the list is empty.
65
66
  */
66
67
  get firstValue(): T | undefined;
67
68
  /**
68
- * Last node.
69
+ * Last node, or `null` if the list is empty.
69
70
  */
70
- get last(): Node<T> | undefined;
71
+ get last(): Node<T> | null;
71
72
  /**
72
- * Contained value of the last node.
73
+ * Contained value of the last node, or `undefined` if the list is empty.
73
74
  */
74
75
  get lastValue(): T | undefined;
75
76
  }
@@ -1,2 +1,2 @@
1
- var u=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var g=Object.prototype.hasOwnProperty;var v=(i,t)=>{for(var e in t)u(i,e,{get:t[e],enumerable:!0})},f=(i,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of d(t))!g.call(i,s)&&s!==e&&u(i,s,{get:()=>t[s],enumerable:!(r=p(t,s))||r.enumerable});return i};var _=i=>f(u({},"__esModule",{value:!0}),i);var m={};v(m,{LinkedList:()=>l,Node:()=>n,PageSelectedEvent:()=>a,Pager:()=>o});module.exports=_(m);var n=class{constructor(t,e){this.value=t;this.removeCallback=e;this.next=null;this.prev=null}remove(){this.prev.next=this.next,this.next.prev=this.prev,this.removeCallback()}},l=class{constructor(){this._length=0}addFirst(t){let e=new n(t,()=>this._length--);this._first?(e.next=this._first,this._first.prev=e,this._first=e):(this._first=e,this._last=this._first),this._length++}addLast(t){let e=new n(t,()=>this._length--);this._first?(e.prev=this._last,this._last.next=e,this._last=e):(this._first=e,this._last=this._first),this._length++}removeFirst(){if(!this.first)throw new Error("The list is empty.");let t=this._first.value;return this._first=this._first.next,this._length--,t}removeLast(){if(!this.last)throw new Error("The list is empty.");let t=this._last.value;return this._last=this._last.prev,this._length--,t}get length(){return this._length}get first(){return this._first}get firstValue(){return this._first?.value}get last(){return this._last}get lastValue(){return this._last?.value}};var a=class extends Event{constructor(e){super("pageselected",{bubbles:!0,composed:!0});this.page=e}},o=class{constructor(t,e,r){this.currentPage=1;this.container=t,this.totalCount=e,this.pageSize=r,this.render()}render(){this.container.innerHTML="";let t=Math.max(1,Math.ceil(this.totalCount/this.pageSize)),e=(r,s,c=!1)=>{let h=document.createElement("button");return h.textContent=r,h.disabled=c,h.addEventListener("click",()=>this.selectPage(s)),h};this.container.appendChild(e("Previous",this.currentPage-1,this.currentPage===1));for(let r=1;r<=t;r++){let s=e(r.toString(),r);r===this.currentPage&&s.classList.add("selected"),this.container.appendChild(s)}this.container.appendChild(e("Next",this.currentPage+1,this.currentPage===t))}selectPage(t){let e=Math.max(1,Math.ceil(this.totalCount/this.pageSize));t<1||t>e||t===this.currentPage||(this.currentPage=t,this.render(),this.container.dispatchEvent(new a(this.currentPage)))}update(t){this.totalCount=t;let e=Math.max(1,Math.ceil(this.totalCount/this.pageSize));this.currentPage>e&&(this.currentPage=e),this.render()}getCurrentPage(){return this.currentPage}};
1
+ "use strict";var u=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var _=Object.prototype.hasOwnProperty;var f=(s,e)=>{for(var t in e)u(s,t,{get:e[t],enumerable:!0})},g=(s,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of d(e))!_.call(s,r)&&r!==t&&u(s,r,{get:()=>e[r],enumerable:!(i=p(e,r))||i.enumerable});return s};var v=s=>g(u({},"__esModule",{value:!0}),s);var m={};f(m,{LinkedList:()=>h,Node:()=>n,PageSelectedEvent:()=>a,Pager:()=>o});module.exports=v(m);var n=class{constructor(e,t){this.value=e;this.removeCallback=t;this.next=null;this.prev=null}remove(){this.prev&&(this.prev.next=this.next),this.next&&(this.next.prev=this.prev),this.removeCallback()}},h=class{constructor(){this._first=null;this._last=null;this._length=0}addFirst(e){let t=this.createNode(e);this._first?(t.next=this._first,this._first.prev=t,this._first=t):(this._first=t,this._last=this._first),this._length++}addLast(e){let t=this.createNode(e);this._last?(t.prev=this._last,this._last.next=t,this._last=t):(this._first=t,this._last=t),this._length++}createNode(e){let t;return t=new n(e,()=>{this._first===t&&(this._first=t.next),this._last===t&&(this._last=t.prev),this._length--}),t}removeFirst(){if(!this._first)throw new Error("The list is empty.");let e=this._first.value;return this._first=this._first.next,this._first||(this._last=null),this._length--,e}removeLast(){if(!this._last)throw new Error("The list is empty.");let e=this._last.value;return this._last=this._last.prev,this._last||(this._first=null),this._length--,e}get length(){return this._length}get first(){return this._first}get firstValue(){return this._first?.value}get last(){return this._last}get lastValue(){return this._last?.value}};var a=class extends Event{constructor(t){super("pageselected",{bubbles:!0,composed:!0});this.page=t}},o=class{constructor(e,t,i){this.currentPage=1;this.container=e,this.totalCount=t,this.pageSize=i,this.render()}render(){this.container.innerHTML="";let e=Math.max(1,Math.ceil(this.totalCount/this.pageSize)),t=(i,r,c=!1)=>{let l=document.createElement("button");return l.textContent=i,l.disabled=c,l.addEventListener("click",()=>this.selectPage(r)),l};this.container.appendChild(t("Previous",this.currentPage-1,this.currentPage===1));for(let i=1;i<=e;i++){let r=t(i.toString(),i);i===this.currentPage&&r.classList.add("selected"),this.container.appendChild(r)}this.container.appendChild(t("Next",this.currentPage+1,this.currentPage===e))}selectPage(e){let t=Math.max(1,Math.ceil(this.totalCount/this.pageSize));e<1||e>t||e===this.currentPage||(this.currentPage=e,this.render(),this.container.dispatchEvent(new a(this.currentPage)))}update(e){this.totalCount=e;let t=Math.max(1,Math.ceil(this.totalCount/this.pageSize));this.currentPage>t&&(this.currentPage=t),this.render()}getCurrentPage(){return this.currentPage}};
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/collections/Index.ts", "../../src/collections/LinkedList.ts", "../../src/collections/Pager.ts"],
4
- "sourcesContent": ["export {LinkedList, Node} from \"./LinkedList\";\nexport { Pager, PageSelectedEvent } from \"./Pager\";\nexport { type DataLoader } from \"./DataLoader\";", "/**\r\n * A node in the @see LinkedList.\r\n */\r\nexport class Node<T> {\r\n /**\r\n * Next node unless last one.\r\n */\r\n public next: Node<T> | null = null;\r\n /**\r\n * Previous node unless first one.\r\n */\r\n public prev: Node<T> | null = null;\r\n\r\n /**\r\n * Constructor.\r\n * @param value Value contained in the node.\r\n */\r\n constructor(public value: T, private removeCallback: () => void) {}\r\n\r\n /**\r\n * Remove this node.\r\n * Will notify the list of the update to ensure correct element count.\r\n */\r\n remove() {\r\n this.prev.next = this.next;\r\n this.next.prev = this.prev;\r\n this.removeCallback();\r\n }\r\n}\r\n\r\n/**\r\n * A trivial linked list implementation.\r\n */\r\nexport class LinkedList<T> {\r\n private _first?: Node<T>;\r\n private _last?: Node<T>;\r\n private _length = 0;\r\n\r\n /**\r\n * Add a value to the beginning of the list.\r\n * @param value Value that should be contained in the node.\r\n */\r\n addFirst(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.next = this._first;\r\n this._first.prev = newNode;\r\n this._first = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Add a value to the end of the list.\r\n * @param value Value that should be contained in a node.\r\n */\r\n addLast(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.prev = this._last;\r\n this._last.next = newNode;\r\n this._last = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Remove a node from the beginning of the list.\r\n * @returns Value contained in the first node.\r\n */\r\n removeFirst(): T {\r\n if (!this.first) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._first.value;\r\n this._first = this._first.next;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Remove a node from the end of the list.\r\n * @returns Value contained in the last node.\r\n */\r\n removeLast(): T {\r\n if (!this.last) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._last.value;\r\n this._last = this._last.prev;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Number of nodes in the list.\r\n *\r\n * The count works as long as you do not manually remove nodes (by assigning next/prev to the neighbors).\r\n */\r\n get length(): number {\r\n return this._length;\r\n }\r\n\r\n /**\r\n * First ndoe.\r\n */\r\n get first(): Node<T> | undefined {\r\n return this._first;\r\n }\r\n\r\n /**\r\n * Contained value of the first node.\r\n */\r\n get firstValue(): T | undefined {\r\n return this._first?.value;\r\n }\r\n\r\n /**\r\n * Last node.\r\n */\r\n get last(): Node<T> | undefined {\r\n return this._last;\r\n }\r\n\r\n /**\r\n * Contained value of the last node.\r\n */\r\n get lastValue(): T | undefined {\r\n return this._last?.value;\r\n }\r\n}\r\n", "export class PageSelectedEvent extends Event {\r\n constructor(public page: number) {\r\n super('pageselected', {\r\n bubbles: true,\r\n composed: true,\r\n });\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementEventMap {\r\n 'pageselected': PageSelectedEvent;\r\n }\r\n}\r\n\r\nexport class Pager {\r\n private container: HTMLElement;\r\n private totalCount: number;\r\n private pageSize: number;\r\n private currentPage: number = 1;\r\n\r\n constructor(container: HTMLElement, totalCount: number, pageSize: number) {\r\n this.container = container;\r\n this.totalCount = totalCount;\r\n this.pageSize = pageSize;\r\n\r\n this.render();\r\n }\r\n\r\n private render() {\r\n this.container.innerHTML = '';\r\n\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n\r\n const createButton = (label: string, page: number, disabled: boolean = false) => {\r\n const btn = document.createElement('button');\r\n btn.textContent = label;\r\n btn.disabled = disabled;\r\n btn.addEventListener('click', () => this.selectPage(page));\r\n return btn;\r\n };\r\n\r\n this.container.appendChild(\r\n createButton('Previous', this.currentPage - 1, this.currentPage === 1)\r\n );\r\n\r\n for (let i = 1; i <= pageCount; i++) {\r\n const btn = createButton(i.toString(), i);\r\n if (i === this.currentPage) {\r\n btn.classList.add('selected');\r\n }\r\n this.container.appendChild(btn);\r\n }\r\n\r\n this.container.appendChild(\r\n createButton('Next', this.currentPage + 1, this.currentPage === pageCount)\r\n );\r\n }\r\n\r\n private selectPage(page: number) {\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (page < 1 || page > pageCount || page === this.currentPage) return;\r\n\r\n this.currentPage = page;\r\n this.render();\r\n\r\n this.container.dispatchEvent(new PageSelectedEvent(this.currentPage));\r\n }\r\n\r\n public update(totalCount: number) {\r\n this.totalCount = totalCount;\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (this.currentPage > pageCount) {\r\n this.currentPage = pageCount;\r\n }\r\n this.render();\r\n }\r\n\r\n public getCurrentPage(): number {\r\n return this.currentPage;\r\n }\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": ["Index_exports", "__export", "LinkedList", "Node", "PageSelectedEvent", "Pager", "__toCommonJS", "Node", "value", "removeCallback", "LinkedList", "newNode", "PageSelectedEvent", "page", "Pager", "container", "totalCount", "pageSize", "pageCount", "createButton", "label", "disabled", "btn", "i"]
4
+ "sourcesContent": ["export {LinkedList, Node} from \"./LinkedList\";\nexport { Pager, PageSelectedEvent } from \"./Pager\";\nexport { type DataLoader } from \"./DataLoader\";", "/**\r\n * A node in the @see LinkedList.\r\n */\r\nexport class Node<T> {\r\n /**\r\n * Next node unless last one.\r\n */\r\n public next: Node<T> | null = null;\r\n /**\r\n * Previous node unless first one.\r\n */\r\n public prev: Node<T> | null = null;\r\n\r\n /**\r\n * Constructor.\r\n * @param value Value contained in the node.\r\n */\r\n constructor(public value: T, private removeCallback: () => void) {}\r\n\r\n /**\r\n * Remove this node.\r\n * Will notify the list of the update to ensure correct element count.\r\n */\r\n remove() {\r\n if (this.prev) this.prev.next = this.next;\r\n if (this.next) this.next.prev = this.prev;\r\n this.removeCallback();\r\n }\r\n}\r\n\r\n/**\r\n * A trivial linked list implementation.\r\n */\r\nexport class LinkedList<T> {\r\n private _first: Node<T> | null = null;\r\n private _last: Node<T> | null = null;\r\n private _length = 0;\r\n\r\n /**\r\n * Add a value to the beginning of the list.\r\n * @param value Value that should be contained in the node.\r\n */\r\n addFirst(value: T) {\r\n const newNode = this.createNode(value);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.next = this._first;\r\n this._first.prev = newNode;\r\n this._first = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Add a value to the end of the list.\r\n * @param value Value that should be contained in a node.\r\n */\r\n addLast(value: T) {\r\n const newNode = this.createNode(value);\r\n if (!this._last) {\r\n this._first = newNode;\r\n this._last = newNode;\r\n } else {\r\n newNode.prev = this._last;\r\n this._last.next = newNode;\r\n this._last = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n private createNode(value: T): Node<T> {\r\n let node: Node<T>;\r\n node = new Node(value, () => {\r\n if (this._first === node) this._first = node.next;\r\n if (this._last === node) this._last = node.prev;\r\n this._length--;\r\n });\r\n return node;\r\n }\r\n\r\n /**\r\n * Remove a node from the beginning of the list.\r\n * @returns Value contained in the first node.\r\n */\r\n removeFirst(): T {\r\n if (!this._first) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._first.value;\r\n this._first = this._first.next;\r\n if (!this._first) this._last = null;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Remove a node from the end of the list.\r\n * @returns Value contained in the last node.\r\n */\r\n removeLast(): T {\r\n if (!this._last) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._last.value;\r\n this._last = this._last.prev;\r\n if (!this._last) this._first = null;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Number of nodes in the list.\r\n *\r\n * The count works as long as you do not manually remove nodes (by assigning next/prev to the neighbors).\r\n */\r\n get length(): number {\r\n return this._length;\r\n }\r\n\r\n /**\r\n * First node, or `null` if the list is empty.\r\n */\r\n get first(): Node<T> | null {\r\n return this._first;\r\n }\r\n\r\n /**\r\n * Contained value of the first node, or `undefined` if the list is empty.\r\n */\r\n get firstValue(): T | undefined {\r\n return this._first?.value;\r\n }\r\n\r\n /**\r\n * Last node, or `null` if the list is empty.\r\n */\r\n get last(): Node<T> | null {\r\n return this._last;\r\n }\r\n\r\n /**\r\n * Contained value of the last node, or `undefined` if the list is empty.\r\n */\r\n get lastValue(): T | undefined {\r\n return this._last?.value;\r\n }\r\n}\r\n", "export class PageSelectedEvent extends Event {\r\n constructor(public page: number) {\r\n super('pageselected', {\r\n bubbles: true,\r\n composed: true,\r\n });\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementEventMap {\r\n 'pageselected': PageSelectedEvent;\r\n }\r\n}\r\n\r\nexport class Pager {\r\n private container: HTMLElement;\r\n private totalCount: number;\r\n private pageSize: number;\r\n private currentPage: number = 1;\r\n\r\n constructor(container: HTMLElement, totalCount: number, pageSize: number) {\r\n this.container = container;\r\n this.totalCount = totalCount;\r\n this.pageSize = pageSize;\r\n\r\n this.render();\r\n }\r\n\r\n private render() {\r\n this.container.innerHTML = '';\r\n\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n\r\n const createButton = (label: string, page: number, disabled: boolean = false) => {\r\n const btn = document.createElement('button');\r\n btn.textContent = label;\r\n btn.disabled = disabled;\r\n btn.addEventListener('click', () => this.selectPage(page));\r\n return btn;\r\n };\r\n\r\n this.container.appendChild(\r\n createButton('Previous', this.currentPage - 1, this.currentPage === 1)\r\n );\r\n\r\n for (let i = 1; i <= pageCount; i++) {\r\n const btn = createButton(i.toString(), i);\r\n if (i === this.currentPage) {\r\n btn.classList.add('selected');\r\n }\r\n this.container.appendChild(btn);\r\n }\r\n\r\n this.container.appendChild(\r\n createButton('Next', this.currentPage + 1, this.currentPage === pageCount)\r\n );\r\n }\r\n\r\n private selectPage(page: number) {\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (page < 1 || page > pageCount || page === this.currentPage) return;\r\n\r\n this.currentPage = page;\r\n this.render();\r\n\r\n this.container.dispatchEvent(new PageSelectedEvent(this.currentPage));\r\n }\r\n\r\n public update(totalCount: number) {\r\n this.totalCount = totalCount;\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (this.currentPage > pageCount) {\r\n this.currentPage = pageCount;\r\n }\r\n this.render();\r\n }\r\n\r\n public getCurrentPage(): number {\r\n return this.currentPage;\r\n }\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": ["Index_exports", "__export", "LinkedList", "Node", "PageSelectedEvent", "Pager", "__toCommonJS", "Node", "value", "removeCallback", "LinkedList", "newNode", "node", "PageSelectedEvent", "page", "Pager", "container", "totalCount", "pageSize", "pageCount", "createButton", "label", "disabled", "btn"]
7
7
  }
@@ -1,2 +1,2 @@
1
- var i=class{constructor(e,t){this.value=e;this.removeCallback=t;this.next=null;this.prev=null}remove(){this.prev.next=this.next,this.next.prev=this.prev,this.removeCallback()}},l=class{constructor(){this._length=0}addFirst(e){let t=new i(e,()=>this._length--);this._first?(t.next=this._first,this._first.prev=t,this._first=t):(this._first=t,this._last=this._first),this._length++}addLast(e){let t=new i(e,()=>this._length--);this._first?(t.prev=this._last,this._last.next=t,this._last=t):(this._first=t,this._last=this._first),this._length++}removeFirst(){if(!this.first)throw new Error("The list is empty.");let e=this._first.value;return this._first=this._first.next,this._length--,e}removeLast(){if(!this.last)throw new Error("The list is empty.");let e=this._last.value;return this._last=this._last.prev,this._length--,e}get length(){return this._length}get first(){return this._first}get firstValue(){return this._first?.value}get last(){return this._last}get lastValue(){return this._last?.value}};var a=class extends Event{constructor(t){super("pageselected",{bubbles:!0,composed:!0});this.page=t}},o=class{constructor(e,t,r){this.currentPage=1;this.container=e,this.totalCount=t,this.pageSize=r,this.render()}render(){this.container.innerHTML="";let e=Math.max(1,Math.ceil(this.totalCount/this.pageSize)),t=(r,s,u=!1)=>{let n=document.createElement("button");return n.textContent=r,n.disabled=u,n.addEventListener("click",()=>this.selectPage(s)),n};this.container.appendChild(t("Previous",this.currentPage-1,this.currentPage===1));for(let r=1;r<=e;r++){let s=t(r.toString(),r);r===this.currentPage&&s.classList.add("selected"),this.container.appendChild(s)}this.container.appendChild(t("Next",this.currentPage+1,this.currentPage===e))}selectPage(e){let t=Math.max(1,Math.ceil(this.totalCount/this.pageSize));e<1||e>t||e===this.currentPage||(this.currentPage=e,this.render(),this.container.dispatchEvent(new a(this.currentPage)))}update(e){this.totalCount=e;let t=Math.max(1,Math.ceil(this.totalCount/this.pageSize));this.currentPage>t&&(this.currentPage=t),this.render()}getCurrentPage(){return this.currentPage}};export{l as LinkedList,i as Node,a as PageSelectedEvent,o as Pager};
1
+ var n=class{constructor(e,t){this.value=e;this.removeCallback=t;this.next=null;this.prev=null}remove(){this.prev&&(this.prev.next=this.next),this.next&&(this.next.prev=this.prev),this.removeCallback()}},h=class{constructor(){this._first=null;this._last=null;this._length=0}addFirst(e){let t=this.createNode(e);this._first?(t.next=this._first,this._first.prev=t,this._first=t):(this._first=t,this._last=this._first),this._length++}addLast(e){let t=this.createNode(e);this._last?(t.prev=this._last,this._last.next=t,this._last=t):(this._first=t,this._last=t),this._length++}createNode(e){let t;return t=new n(e,()=>{this._first===t&&(this._first=t.next),this._last===t&&(this._last=t.prev),this._length--}),t}removeFirst(){if(!this._first)throw new Error("The list is empty.");let e=this._first.value;return this._first=this._first.next,this._first||(this._last=null),this._length--,e}removeLast(){if(!this._last)throw new Error("The list is empty.");let e=this._last.value;return this._last=this._last.prev,this._last||(this._first=null),this._length--,e}get length(){return this._length}get first(){return this._first}get firstValue(){return this._first?.value}get last(){return this._last}get lastValue(){return this._last?.value}};var a=class extends Event{constructor(t){super("pageselected",{bubbles:!0,composed:!0});this.page=t}},o=class{constructor(e,t,i){this.currentPage=1;this.container=e,this.totalCount=t,this.pageSize=i,this.render()}render(){this.container.innerHTML="";let e=Math.max(1,Math.ceil(this.totalCount/this.pageSize)),t=(i,s,u=!1)=>{let r=document.createElement("button");return r.textContent=i,r.disabled=u,r.addEventListener("click",()=>this.selectPage(s)),r};this.container.appendChild(t("Previous",this.currentPage-1,this.currentPage===1));for(let i=1;i<=e;i++){let s=t(i.toString(),i);i===this.currentPage&&s.classList.add("selected"),this.container.appendChild(s)}this.container.appendChild(t("Next",this.currentPage+1,this.currentPage===e))}selectPage(e){let t=Math.max(1,Math.ceil(this.totalCount/this.pageSize));e<1||e>t||e===this.currentPage||(this.currentPage=e,this.render(),this.container.dispatchEvent(new a(this.currentPage)))}update(e){this.totalCount=e;let t=Math.max(1,Math.ceil(this.totalCount/this.pageSize));this.currentPage>t&&(this.currentPage=t),this.render()}getCurrentPage(){return this.currentPage}};export{h as LinkedList,n as Node,a as PageSelectedEvent,o as Pager};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/collections/LinkedList.ts", "../../src/collections/Pager.ts"],
4
- "sourcesContent": ["/**\r\n * A node in the @see LinkedList.\r\n */\r\nexport class Node<T> {\r\n /**\r\n * Next node unless last one.\r\n */\r\n public next: Node<T> | null = null;\r\n /**\r\n * Previous node unless first one.\r\n */\r\n public prev: Node<T> | null = null;\r\n\r\n /**\r\n * Constructor.\r\n * @param value Value contained in the node.\r\n */\r\n constructor(public value: T, private removeCallback: () => void) {}\r\n\r\n /**\r\n * Remove this node.\r\n * Will notify the list of the update to ensure correct element count.\r\n */\r\n remove() {\r\n this.prev.next = this.next;\r\n this.next.prev = this.prev;\r\n this.removeCallback();\r\n }\r\n}\r\n\r\n/**\r\n * A trivial linked list implementation.\r\n */\r\nexport class LinkedList<T> {\r\n private _first?: Node<T>;\r\n private _last?: Node<T>;\r\n private _length = 0;\r\n\r\n /**\r\n * Add a value to the beginning of the list.\r\n * @param value Value that should be contained in the node.\r\n */\r\n addFirst(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.next = this._first;\r\n this._first.prev = newNode;\r\n this._first = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Add a value to the end of the list.\r\n * @param value Value that should be contained in a node.\r\n */\r\n addLast(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.prev = this._last;\r\n this._last.next = newNode;\r\n this._last = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Remove a node from the beginning of the list.\r\n * @returns Value contained in the first node.\r\n */\r\n removeFirst(): T {\r\n if (!this.first) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._first.value;\r\n this._first = this._first.next;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Remove a node from the end of the list.\r\n * @returns Value contained in the last node.\r\n */\r\n removeLast(): T {\r\n if (!this.last) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._last.value;\r\n this._last = this._last.prev;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Number of nodes in the list.\r\n *\r\n * The count works as long as you do not manually remove nodes (by assigning next/prev to the neighbors).\r\n */\r\n get length(): number {\r\n return this._length;\r\n }\r\n\r\n /**\r\n * First ndoe.\r\n */\r\n get first(): Node<T> | undefined {\r\n return this._first;\r\n }\r\n\r\n /**\r\n * Contained value of the first node.\r\n */\r\n get firstValue(): T | undefined {\r\n return this._first?.value;\r\n }\r\n\r\n /**\r\n * Last node.\r\n */\r\n get last(): Node<T> | undefined {\r\n return this._last;\r\n }\r\n\r\n /**\r\n * Contained value of the last node.\r\n */\r\n get lastValue(): T | undefined {\r\n return this._last?.value;\r\n }\r\n}\r\n", "export class PageSelectedEvent extends Event {\r\n constructor(public page: number) {\r\n super('pageselected', {\r\n bubbles: true,\r\n composed: true,\r\n });\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementEventMap {\r\n 'pageselected': PageSelectedEvent;\r\n }\r\n}\r\n\r\nexport class Pager {\r\n private container: HTMLElement;\r\n private totalCount: number;\r\n private pageSize: number;\r\n private currentPage: number = 1;\r\n\r\n constructor(container: HTMLElement, totalCount: number, pageSize: number) {\r\n this.container = container;\r\n this.totalCount = totalCount;\r\n this.pageSize = pageSize;\r\n\r\n this.render();\r\n }\r\n\r\n private render() {\r\n this.container.innerHTML = '';\r\n\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n\r\n const createButton = (label: string, page: number, disabled: boolean = false) => {\r\n const btn = document.createElement('button');\r\n btn.textContent = label;\r\n btn.disabled = disabled;\r\n btn.addEventListener('click', () => this.selectPage(page));\r\n return btn;\r\n };\r\n\r\n this.container.appendChild(\r\n createButton('Previous', this.currentPage - 1, this.currentPage === 1)\r\n );\r\n\r\n for (let i = 1; i <= pageCount; i++) {\r\n const btn = createButton(i.toString(), i);\r\n if (i === this.currentPage) {\r\n btn.classList.add('selected');\r\n }\r\n this.container.appendChild(btn);\r\n }\r\n\r\n this.container.appendChild(\r\n createButton('Next', this.currentPage + 1, this.currentPage === pageCount)\r\n );\r\n }\r\n\r\n private selectPage(page: number) {\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (page < 1 || page > pageCount || page === this.currentPage) return;\r\n\r\n this.currentPage = page;\r\n this.render();\r\n\r\n this.container.dispatchEvent(new PageSelectedEvent(this.currentPage));\r\n }\r\n\r\n public update(totalCount: number) {\r\n this.totalCount = totalCount;\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (this.currentPage > pageCount) {\r\n this.currentPage = pageCount;\r\n }\r\n this.render();\r\n }\r\n\r\n public getCurrentPage(): number {\r\n return this.currentPage;\r\n }\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": ["Node", "value", "removeCallback", "LinkedList", "newNode", "PageSelectedEvent", "page", "Pager", "container", "totalCount", "pageSize", "pageCount", "createButton", "label", "disabled", "btn", "i"]
4
+ "sourcesContent": ["/**\r\n * A node in the @see LinkedList.\r\n */\r\nexport class Node<T> {\r\n /**\r\n * Next node unless last one.\r\n */\r\n public next: Node<T> | null = null;\r\n /**\r\n * Previous node unless first one.\r\n */\r\n public prev: Node<T> | null = null;\r\n\r\n /**\r\n * Constructor.\r\n * @param value Value contained in the node.\r\n */\r\n constructor(public value: T, private removeCallback: () => void) {}\r\n\r\n /**\r\n * Remove this node.\r\n * Will notify the list of the update to ensure correct element count.\r\n */\r\n remove() {\r\n if (this.prev) this.prev.next = this.next;\r\n if (this.next) this.next.prev = this.prev;\r\n this.removeCallback();\r\n }\r\n}\r\n\r\n/**\r\n * A trivial linked list implementation.\r\n */\r\nexport class LinkedList<T> {\r\n private _first: Node<T> | null = null;\r\n private _last: Node<T> | null = null;\r\n private _length = 0;\r\n\r\n /**\r\n * Add a value to the beginning of the list.\r\n * @param value Value that should be contained in the node.\r\n */\r\n addFirst(value: T) {\r\n const newNode = this.createNode(value);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.next = this._first;\r\n this._first.prev = newNode;\r\n this._first = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Add a value to the end of the list.\r\n * @param value Value that should be contained in a node.\r\n */\r\n addLast(value: T) {\r\n const newNode = this.createNode(value);\r\n if (!this._last) {\r\n this._first = newNode;\r\n this._last = newNode;\r\n } else {\r\n newNode.prev = this._last;\r\n this._last.next = newNode;\r\n this._last = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n private createNode(value: T): Node<T> {\r\n let node: Node<T>;\r\n node = new Node(value, () => {\r\n if (this._first === node) this._first = node.next;\r\n if (this._last === node) this._last = node.prev;\r\n this._length--;\r\n });\r\n return node;\r\n }\r\n\r\n /**\r\n * Remove a node from the beginning of the list.\r\n * @returns Value contained in the first node.\r\n */\r\n removeFirst(): T {\r\n if (!this._first) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._first.value;\r\n this._first = this._first.next;\r\n if (!this._first) this._last = null;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Remove a node from the end of the list.\r\n * @returns Value contained in the last node.\r\n */\r\n removeLast(): T {\r\n if (!this._last) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._last.value;\r\n this._last = this._last.prev;\r\n if (!this._last) this._first = null;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Number of nodes in the list.\r\n *\r\n * The count works as long as you do not manually remove nodes (by assigning next/prev to the neighbors).\r\n */\r\n get length(): number {\r\n return this._length;\r\n }\r\n\r\n /**\r\n * First node, or `null` if the list is empty.\r\n */\r\n get first(): Node<T> | null {\r\n return this._first;\r\n }\r\n\r\n /**\r\n * Contained value of the first node, or `undefined` if the list is empty.\r\n */\r\n get firstValue(): T | undefined {\r\n return this._first?.value;\r\n }\r\n\r\n /**\r\n * Last node, or `null` if the list is empty.\r\n */\r\n get last(): Node<T> | null {\r\n return this._last;\r\n }\r\n\r\n /**\r\n * Contained value of the last node, or `undefined` if the list is empty.\r\n */\r\n get lastValue(): T | undefined {\r\n return this._last?.value;\r\n }\r\n}\r\n", "export class PageSelectedEvent extends Event {\r\n constructor(public page: number) {\r\n super('pageselected', {\r\n bubbles: true,\r\n composed: true,\r\n });\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementEventMap {\r\n 'pageselected': PageSelectedEvent;\r\n }\r\n}\r\n\r\nexport class Pager {\r\n private container: HTMLElement;\r\n private totalCount: number;\r\n private pageSize: number;\r\n private currentPage: number = 1;\r\n\r\n constructor(container: HTMLElement, totalCount: number, pageSize: number) {\r\n this.container = container;\r\n this.totalCount = totalCount;\r\n this.pageSize = pageSize;\r\n\r\n this.render();\r\n }\r\n\r\n private render() {\r\n this.container.innerHTML = '';\r\n\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n\r\n const createButton = (label: string, page: number, disabled: boolean = false) => {\r\n const btn = document.createElement('button');\r\n btn.textContent = label;\r\n btn.disabled = disabled;\r\n btn.addEventListener('click', () => this.selectPage(page));\r\n return btn;\r\n };\r\n\r\n this.container.appendChild(\r\n createButton('Previous', this.currentPage - 1, this.currentPage === 1)\r\n );\r\n\r\n for (let i = 1; i <= pageCount; i++) {\r\n const btn = createButton(i.toString(), i);\r\n if (i === this.currentPage) {\r\n btn.classList.add('selected');\r\n }\r\n this.container.appendChild(btn);\r\n }\r\n\r\n this.container.appendChild(\r\n createButton('Next', this.currentPage + 1, this.currentPage === pageCount)\r\n );\r\n }\r\n\r\n private selectPage(page: number) {\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (page < 1 || page > pageCount || page === this.currentPage) return;\r\n\r\n this.currentPage = page;\r\n this.render();\r\n\r\n this.container.dispatchEvent(new PageSelectedEvent(this.currentPage));\r\n }\r\n\r\n public update(totalCount: number) {\r\n this.totalCount = totalCount;\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (this.currentPage > pageCount) {\r\n this.currentPage = pageCount;\r\n }\r\n this.render();\r\n }\r\n\r\n public getCurrentPage(): number {\r\n return this.currentPage;\r\n }\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": ["Node", "value", "removeCallback", "LinkedList", "newNode", "node", "PageSelectedEvent", "page", "Pager", "container", "totalCount", "pageSize", "pageCount", "createButton", "label", "disabled", "btn"]
7
7
  }
package/dist/di/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var d=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var x=(n,t)=>{for(var e in t)d(n,e,{get:t[e],enumerable:!0})},C=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of f(t))!h.call(n,s)&&s!==e&&d(n,s,{get:()=>t[s],enumerable:!(r=y(t,s))||r.enumerable});return n};var T=n=>C(d({},"__esModule",{value:!0}),n);var b={};x(b,{ContainerService:()=>j,Inject:()=>m,ServiceCollection:()=>a,ServiceContainer:()=>l,container:()=>v,serviceCollection:()=>g});module.exports=T(b);var u=class extends Error{constructor(e,r){super(e);this.context=r}},p=null;function o(n,t){let e=new u(n,t);if(p){let r=!1;if(p(e,{suppress(){r=!0}}),r)return null}return e}function m(n){return(t,e)=>function(){return v.resolve(n)}}function j(n){return t=>{let e=n??{inject:[]};e.key?g.register(t,e):g.registerByType(t,e)}}var c=class{constructor(t,e,r,s={},i,w){this.classConstructor=t;this.scope=e;this.inject=r;this.properties=s;this.key=i;this.instance=w}},a=class{constructor(){this.servicesByKey=new Map;this.servicesByClassName=new Map}register(t,e){this.validateRegistration(t,e);let r=new c(t,e.scope??"global",e.inject,e.properties??{},e.key,e.instance);e.key&&this.servicesByKey.set(e.key,r),this.servicesByClassName.set(t.name,r)}registerByType(t,e){this.checkNameCollision(t),e&&this.validateRegistration(t,e);let r=new c(t,e?.scope,e?.inject??[],e?.properties,e?.key,e?.instance);e?.key&&this.servicesByKey.set(e.key,r),this.servicesByClassName.set(t.name,r)}checkNameCollision(t){let e=this.servicesByClassName.get(t.name);if(e&&e.classConstructor!==t){let r=o("Service name collision: different class registered with same name",{service:t.name});if(r)throw r}}validateRegistration(t,e){if(this.checkNameCollision(t),e.key){let r=this.servicesByKey.get(e.key);if(r&&r.classConstructor!==t){let s=o("Service key already registered to a different class",{key:e.key,existingClass:r.classConstructor.name,newClass:t.name});if(s)throw s}}if(e.instance&&e.inject.length>0){let r=o("Service has both instance and inject (inject will be ignored)",{service:t.name});if(r)throw r}}tryGet(t){return typeof t=="string"?this.servicesByKey.get(t):this.servicesByClassName.get(t.name)}get(t){let e=this.tryGet(t);if(!e){let r=typeof t=="string"?t:t.name,s=o(`Failed to resolve service '${r}'`,{service:r,registeredTypes:Array.from(this.servicesByClassName.keys()),registeredKeys:Array.from(this.servicesByKey.keys())});if(s)throw s}return e}};var l=class{constructor(t){this.serviceCollection=t;this.instances=new Map}resolve(t){let e=typeof t=="string"?t:t.name;if(this.instances.has(e))return this.instances.get(e);let r=this.serviceCollection.get(t);if(!r){let i=o(`Failed to resolve service '${e}'`,{service:e});if(i)throw i;return}if(r.instance){let i=r.instance;return this.injectFields(i,r),this.instances.set(e,i),i}let s=this.createInstance(r);return r.scope==="global"&&this.instances.set(e,s),this.injectFields(s,r),s}createInstance(t){let e=t.classConstructor,r=t.inject.map(s=>this.resolve(s));return new e(...r)}injectFields(t,e){for(let[r,s]of Object.entries(e.properties))t[r]=this.resolve(s)}},g=new a,v=new l(g);
1
+ "use strict";var d=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var x=(n,t)=>{for(var e in t)d(n,e,{get:t[e],enumerable:!0})},C=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of f(t))!h.call(n,s)&&s!==e&&d(n,s,{get:()=>t[s],enumerable:!(r=y(t,s))||r.enumerable});return n};var T=n=>C(d({},"__esModule",{value:!0}),n);var j={};x(j,{ContainerService:()=>b,Inject:()=>m,ServiceCollection:()=>a,ServiceContainer:()=>l,container:()=>v,serviceCollection:()=>g});module.exports=T(j);var u=class extends Error{constructor(e,r){super(e);this.context=r}},p=null;function o(n,t){let e=new u(n,t);if(p){let r=!1;if(p(e,{suppress(){r=!0}}),r)return null}return e}function m(n){return(t,e)=>function(){return v.resolve(n)}}function b(n){return t=>{let e=n??{inject:[]};e.key?g.register(t,e):g.registerByType(t,e)}}var c=class{constructor(t,e,r,s={},i,w){this.classConstructor=t;this.scope=e;this.inject=r;this.properties=s;this.key=i;this.instance=w}},a=class{constructor(){this.servicesByKey=new Map;this.servicesByClassName=new Map}register(t,e){this.validateRegistration(t,e);let r=new c(t,e.scope??"global",e.inject,e.properties??{},e.key,e.instance);e.key&&this.servicesByKey.set(e.key,r),this.servicesByClassName.set(t.name,r)}registerByType(t,e){this.checkNameCollision(t),e&&this.validateRegistration(t,e);let r=new c(t,e?.scope??"global",e?.inject??[],e?.properties,e?.key,e?.instance);e?.key&&this.servicesByKey.set(e.key,r),this.servicesByClassName.set(t.name,r)}checkNameCollision(t){let e=this.servicesByClassName.get(t.name);if(e&&e.classConstructor!==t){let r=o("Service name collision: different class registered with same name",{service:t.name});if(r)throw r}}validateRegistration(t,e){if(this.checkNameCollision(t),e.key){let r=this.servicesByKey.get(e.key);if(r&&r.classConstructor!==t){let s=o("Service key already registered to a different class",{key:e.key,existingClass:r.classConstructor.name,newClass:t.name});if(s)throw s}}if(e.instance&&e.inject.length>0){let r=o("Service has both instance and inject (inject will be ignored)",{service:t.name});if(r)throw r}}tryGet(t){return typeof t=="string"?this.servicesByKey.get(t):this.servicesByClassName.get(t.name)}get(t){let e=this.tryGet(t);if(!e){let r=typeof t=="string"?t:t.name,s=o(`Failed to resolve service '${r}'`,{service:r,registeredTypes:Array.from(this.servicesByClassName.keys()),registeredKeys:Array.from(this.servicesByKey.keys())});if(s)throw s}return e}};var l=class{constructor(t){this.serviceCollection=t;this.instances=new Map}resolve(t){let e=typeof t=="string"?t:t.name;if(this.instances.has(e))return this.instances.get(e);let r=this.serviceCollection.get(t);if(!r){let i=o(`Failed to resolve service '${e}'`,{service:e});if(i)throw i;return}if(r.instance){let i=r.instance;return this.injectFields(i,r),this.instances.set(e,i),i}let s=this.createInstance(r);return r.scope==="global"&&this.instances.set(e,s),this.injectFields(s,r),s}createInstance(t){let e=t.classConstructor,r=t.inject.map(s=>this.resolve(s));return new e(...r)}injectFields(t,e){for(let[r,s]of Object.entries(e.properties))t[r]=this.resolve(s)}},g=new a,v=new l(g);
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/di/index.ts", "../../src/errors.ts", "../../src/DependencyInjection.ts"],
4
- "sourcesContent": ["export * from '../DependencyInjection';\r\n", "/**\r\n * Global error handling for Relaxjs.\r\n * Register a handler with `onError()` to intercept errors before they throw.\r\n * Call `ctx.suppress()` in the handler to prevent the error from being thrown.\r\n *\r\n * @example\r\n * import { onError } from 'relaxjs';\r\n *\r\n * onError((error, ctx) => {\r\n * logToService(error.message, error.context);\r\n * showToast(error.message);\r\n * ctx.suppress();\r\n * });\r\n */\r\n\r\n/**\r\n * Passed to error handlers to control error behavior.\r\n * Call `suppress()` to prevent the error from being thrown.\r\n */\r\nexport interface ErrorContext {\r\n suppress(): void;\r\n}\r\n\r\n/**\r\n * Error with structured context for debugging.\r\n * The `context` record contains details like route name, component tag, route data.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * console.log(error.context.route);\r\n * console.log(error.context.componentTagName);\r\n * });\r\n */\r\nexport class RelaxError extends Error {\r\n constructor(\r\n message: string,\r\n public context: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n }\r\n}\r\n\r\n/** @internal */\r\ntype ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;\r\n\r\nlet handler: ErrorHandler | null = null;\r\n\r\n/**\r\n * Registers a global error handler for Relaxjs errors.\r\n * The handler receives the error and an `ErrorContext`.\r\n * Call `ctx.suppress()` to prevent the error from being thrown.\r\n * Only one handler can be active at a time; subsequent calls replace the previous handler.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * if (error.context.route === 'optional-panel') {\r\n * ctx.suppress();\r\n * return;\r\n * }\r\n * showErrorDialog(error.message);\r\n * });\r\n */\r\nexport function onError(fn: ErrorHandler) {\r\n handler = fn;\r\n}\r\n\r\n/**\r\n * Reports an error through the global handler.\r\n * Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.\r\n * The caller is responsible for throwing the returned error.\r\n *\r\n * @param message - Human-readable error description\r\n * @param context - Structured data for debugging (route, component, params, cause, etc.)\r\n * @returns The error to throw, or `null` if suppressed\r\n *\r\n * @example\r\n * const error = reportError('Failed to load route component', {\r\n * route: 'user',\r\n * componentTagName: 'user-profile',\r\n * routeData: { id: 123 },\r\n * });\r\n * if (error) throw error;\r\n */\r\nexport function reportError(message: string, context: Record<string, unknown>): RelaxError | null {\r\n const error = new RelaxError(message, context);\r\n if (handler) {\r\n let suppressed = false;\r\n const ctx: ErrorContext = {\r\n suppress() { suppressed = true; },\r\n };\r\n handler(error, ctx);\r\n if (suppressed) {\r\n return null;\r\n }\r\n }\r\n return error;\r\n}\r\n\r\n/**\r\n * Wraps an async function into a synchronous callback suitable for addEventListener.\r\n * Catches promise rejections and reports them through the global error handler.\r\n *\r\n * @param fn - Async function to wrap\r\n * @returns Synchronous function that can be passed to addEventListener\r\n *\r\n * @example\r\n * button.addEventListener('click', asyncHandler(async (e) => {\r\n * await saveData();\r\n * }));\r\n *\r\n * @example\r\n * form.addEventListener('submit', asyncHandler(async (e) => {\r\n * e.preventDefault();\r\n * await submitForm();\r\n * }));\r\n */\r\nexport function asyncHandler<TArgs extends unknown[]>(\r\n fn: (...args: TArgs) => Promise<void>,\r\n): (...args: TArgs) => void {\r\n return function (this: any, ...args: TArgs) {\r\n fn.call(this, ...args).catch((cause: unknown) => {\r\n const error = reportError('Async callback failed', { cause });\r\n if (error) throw error;\r\n });\r\n };\r\n}\r\n", "import { reportError } from './errors';\r\n\r\n/**\r\n * Generic constructor type used for dependency registration and injection.\r\n * Represents any class constructor that can be used with the DI container.\r\n *\r\n * @template T - The type of object the constructor creates\r\n *\r\n * @example\r\n * // Use with service registration\r\n * class UserService {}\r\n * const ctor: Constructor<UserService> = UserService;\r\n * serviceCollection.registerByType(ctor, { inject: [] });\r\n */\r\nexport type Constructor<T extends object = object> = new (...args: any[]) => T;\r\n\r\n/**\r\n * Controls how service instances are shared across the container hierarchy.\r\n * Used when registering services to define their lifetime behavior.\r\n *\r\n * - `global`: Single instance shared everywhere (singleton pattern)\r\n * - `closest`: New instance per container scope (scoped lifetime)\r\n *\r\n * @example\r\n * // Singleton service - same instance everywhere\r\n * serviceCollection.register(LoggerService, { scope: 'global', inject: [] });\r\n *\r\n * // Scoped service - new instance per scope\r\n * serviceCollection.register(RequestContext, { scope: 'closest', inject: [] });\r\n */\r\nexport type ServiceScope = 'global' | 'closest';\r\n\r\n/**\r\n * Configuration options for registering a service in the DI container.\r\n * Controls identification, lifetime, and dependency resolution.\r\n *\r\n * @example\r\n * // Register with constructor injection\r\n * const options: RegistrationOptions = {\r\n * scope: 'global',\r\n * inject: [DatabaseConnection, ConfigService]\r\n * };\r\n * serviceCollection.register(UserRepository, options);\r\n *\r\n * @example\r\n * // Register with property injection\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * properties: { logger: Logger, config: 'appConfig' }\r\n * };\r\n *\r\n * @example\r\n * // Register with a pre-created instance\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * instance: existingService\r\n * };\r\n */\r\nexport interface RegistrationOptions {\r\n /** Service lifetime - 'global' for singleton, 'closest' for scoped */\r\n scope?: ServiceScope;\r\n /** Optional string key for resolving by name instead of type */\r\n key?: string;\r\n /** Pre-existing instance to use instead of creating new one */\r\n instance?: unknown;\r\n /** Types or keys for constructor parameters, in order */\r\n inject: (string | Constructor)[];\r\n /** Map of property names to their injection types/keys */\r\n properties?: Record<string, string | Constructor>;\r\n}\r\n\r\n/**\r\n * Field decorator that injects a service from the global DI container.\r\n * The service is resolved when the class instance is created (not at class definition time),\r\n * so services must be registered before the first instance is created.\r\n *\r\n * Works with web components regardless of how they are created:\r\n * - By the browser (HTML parsing): services are resolved during construction\r\n * - By application code (`document.createElement` or `new`): same behavior\r\n * - Injected fields are available in `connectedCallback` and all lifecycle methods\r\n *\r\n * @example\r\n * // Using `@Inject` in a web component\r\n * class UserPanel extends HTMLElement {\r\n * @Inject(UserService)\r\n * private userService!: UserService;\r\n *\r\n * connectedCallback() {\r\n * // userService is already resolved and ready to use\r\n * const user = this.userService.getCurrentUser();\r\n * this.render(user);\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // Services must be registered before components are created.\r\n * // In your app entry point (e.g. main.ts):\r\n * serviceCollection.registerByType(UserService, { inject: [ApiClient] });\r\n * serviceCollection.registerByType(ApiClient, { inject: [] });\r\n *\r\n * // Now components can be created (by browser or code)\r\n * customElements.define('user-panel', UserPanel);\r\n */\r\nexport function Inject<T extends object>(typeOrKey: Constructor<T> | string) {\r\n return (_: undefined, context: ClassFieldDecoratorContext) => {\r\n return function(this: any) {\r\n return container.resolve(typeOrKey);\r\n };\r\n };\r\n}\r\n\r\n// Temporary collector of property injections - cleared after registration\r\n//const propertyCollector = new WeakMap<object, Record<string, string>>();\r\n\r\n/**\r\n * Class decorator that registers a service in the global DI container.\r\n * Registration happens at class definition time (when the module loads),\r\n * so import the module before creating instances that depend on this service.\r\n *\r\n * For web components: use `@ContainerService` on services, not on the\r\n * components themselves. Components use `@Inject` to consume services.\r\n *\r\n * @param options - Registration configuration including scope and dependencies\r\n *\r\n * @example\r\n * // Register a service that components can inject\r\n * @ContainerService({ inject: [ApiClient] })\r\n * class UserService {\r\n * constructor(private api: ApiClient) {}\r\n * getCurrentUser() { return this.api.get('/user'); }\r\n * }\r\n *\r\n * // Component consumes the service\r\n * class UserPanel extends HTMLElement {\r\n * @Inject(UserService)\r\n * private userService!: UserService;\r\n * }\r\n *\r\n * @example\r\n * // Service with custom key for named resolution\r\n * @ContainerService({ key: 'primaryCache', scope: 'global', inject: [] })\r\n * class CacheService {}\r\n *\r\n * // Later resolve by key\r\n * const cache = container.resolve('primaryCache');\r\n */\r\nexport function ContainerService<T extends object>(\r\n options?: RegistrationOptions\r\n) {\r\n return (target: Constructor<T>) => {\r\n const opts = options ?? {inject: []};\r\n\r\n if (opts.key) {\r\n serviceCollection.register(target, opts);\r\n } else {\r\n serviceCollection.registerByType(target, opts);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Internal class representing a registered service's metadata.\r\n * Holds all information needed to create and configure service instances.\r\n *\r\n * @internal This is an implementation detail and should not be used directly.\r\n */\r\nclass Registration {\r\n /**\r\n * Creates a new registration record.\r\n *\r\n * @param classConstructor - The class constructor function\r\n * @param scope - Instance sharing behavior\r\n * @param inject - Constructor parameter dependencies\r\n * @param properties - Property injection mappings\r\n * @param key - Optional string identifier\r\n * @param instance - Optional pre-created instance\r\n */\r\n constructor(\r\n public classConstructor: Constructor,\r\n public scope: ServiceScope,\r\n public inject: (string | Constructor)[],\r\n public properties: Record<string, string | Constructor> = {},\r\n public key?: string,\r\n public instance?: unknown\r\n ) {}\r\n}\r\n\r\n/**\r\n * Registry that stores service registration metadata.\r\n * Use this to register services before they can be resolved by a ServiceContainer.\r\n *\r\n * Typically you'll use the global `serviceCollection` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Register a service by type\r\n * serviceCollection.registerByType(LoggerService, { inject: [] });\r\n *\r\n * // Register with a string key\r\n * serviceCollection.register(CacheService, { key: 'cache', inject: [] });\r\n *\r\n * // Check if service is registered\r\n * const reg = serviceCollection.tryGet(LoggerService);\r\n * if (reg) {\r\n * console.log('Logger is registered');\r\n * }\r\n */\r\nexport class ServiceCollection {\r\n private servicesByKey = new Map<string, Registration>();\r\n private servicesByClassName = new Map<string, Registration>();\r\n\r\n /**\r\n * Registers a service with full configuration options.\r\n * The service will be resolvable by both its class name and optional key.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Registration configuration\r\n */\r\n register<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(\r\n constructor,\r\n options.scope ?? 'global',\r\n options.inject,\r\n options.properties ?? {},\r\n options.key,\r\n options.instance\r\n );\r\n\r\n if (options.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n /**\r\n * Registers a service by its class type.\r\n * The service will be resolvable by its class constructor.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Optional registration configuration\r\n */\r\n registerByType<T extends object>(\r\n constructor: Constructor<T>,\r\n options?: RegistrationOptions\r\n ): void {\r\n this.checkNameCollision(constructor);\r\n if (options) this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(constructor, options?.scope, options?.inject ?? [], options?.properties, options?.key, options?.instance);\r\n if (options?.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n private checkNameCollision<T extends object>(constructor: Constructor<T>): void {\r\n const existing = this.servicesByClassName.get(constructor.name);\r\n if (existing && existing.classConstructor !== constructor) {\r\n const error = reportError('Service name collision: different class registered with same name', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n private validateRegistration<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.checkNameCollision(constructor);\r\n\r\n if (options.key) {\r\n const existingByKey = this.servicesByKey.get(options.key);\r\n if (existingByKey && existingByKey.classConstructor !== constructor) {\r\n const error = reportError('Service key already registered to a different class', {\r\n key: options.key,\r\n existingClass: existingByKey.classConstructor.name,\r\n newClass: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n if (options.instance && options.inject.length > 0) {\r\n const error = reportError('Service has both instance and inject (inject will be ignored)', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Attempts to retrieve a service registration.\r\n * Returns undefined if the service is not registered.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration or undefined\r\n */\r\n tryGet<T extends object>(key: string | Constructor<T>): Registration | undefined {\r\n if (typeof key === 'string') {\r\n return this.servicesByKey.get(key);\r\n }\r\n return this.servicesByClassName.get(key.name);\r\n }\r\n\r\n /**\r\n * Retrieves a service registration or throws if not found.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration\r\n * @throws Error if the service is not registered\r\n */\r\n get<T extends object>(key: string | Constructor<T>): Registration {\r\n const reg = this.tryGet(key);\r\n if (!reg) {\r\n const service = typeof key === 'string' ? key : key.name;\r\n const error = reportError(`Failed to resolve service '${service}'`, {\r\n service,\r\n registeredTypes: Array.from(this.servicesByClassName.keys()),\r\n registeredKeys: Array.from(this.servicesByKey.keys()),\r\n });\r\n if (error) throw error;\r\n }\r\n return reg!;\r\n }\r\n}\r\n\r\n/**\r\n * Internal storage for tracking injected fields during service resolution.\r\n * @internal\r\n */\r\nconst injectedFields = new WeakMap<object, Map<string, string>>();\r\n\r\n/**\r\n * IoC container that resolves and manages service instances.\r\n * Creates instances based on registrations in a ServiceCollection,\r\n * handling constructor injection, property injection, and lifetime management.\r\n *\r\n * Typically you'll use the global `container` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Resolve a service by class\r\n * const logger = container.resolve(LoggerService);\r\n *\r\n * // Resolve by string key\r\n * const cache = container.resolve<CacheService>('primaryCache');\r\n *\r\n * @example\r\n * // Full setup workflow\r\n * serviceCollection.register(UserService, {\r\n * inject: [DatabaseConnection],\r\n * scope: 'global'\r\n * });\r\n *\r\n * const userService = container.resolve(UserService);\r\n */\r\nexport class ServiceContainer {\r\n private instances = new Map<string, any>();\r\n\r\n /**\r\n * Creates a new container backed by the given service collection.\r\n *\r\n * @param serviceCollection - The registry containing service registrations\r\n */\r\n constructor(private serviceCollection: ServiceCollection) {}\r\n\r\n /**\r\n * Resolves a service instance by class type or string key.\r\n * Creates the instance if not already cached (for global scope).\r\n * Handles constructor and property injection automatically.\r\n *\r\n * @param keyOrType - Either a string key or class constructor\r\n * @returns The resolved service instance\r\n * @throws Error if the service is not registered\r\n *\r\n * @example\r\n * const service = container.resolve(MyService);\r\n */\r\n resolve<T extends object>(keyOrType: string | Constructor<T>): T {\r\n const key = typeof keyOrType === 'string' ? keyOrType : keyOrType.name;\r\n\r\n if (this.instances.has(key)) {\r\n return this.instances.get(key);\r\n }\r\n\r\n const registration = this.serviceCollection.get(keyOrType);\r\n if (!registration) {\r\n const error = reportError(`Failed to resolve service '${key}'`, { service: key });\r\n if (error) throw error;\r\n return undefined as unknown as T;\r\n }\r\n\r\n if (registration.instance) {\r\n const inst = registration.instance as T;\r\n this.injectFields(inst, registration);\r\n this.instances.set(key, inst);\r\n return inst;\r\n }\r\n\r\n const instance = this.createInstance<T>(registration);\r\n if (registration.scope === 'global') {\r\n this.instances.set(key, instance);\r\n }\r\n this.injectFields(instance, registration);\r\n\r\n return instance;\r\n }\r\n\r\n /**\r\n * Creates a new instance of a service, resolving all constructor dependencies.\r\n */\r\n private createInstance<T extends object>(registration: Registration): T {\r\n const constructor = registration.classConstructor as Constructor<T>;\r\n\r\n const dependencies = registration.inject.map(dep => this.resolve(dep));\r\n return new constructor(...dependencies);\r\n }\r\n\r\n /**\r\n * Injects dependencies into instance properties based on registration config.\r\n */\r\n private injectFields<T extends object>(instance: T, registration: Registration): void {\r\n for (const [fieldName, keyOrType] of Object.entries(registration.properties)) {\r\n (instance as any)[fieldName] = this.resolve(keyOrType);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Global service collection instance for registering services.\r\n * Use this to register services that can later be resolved by the container.\r\n *\r\n * @example\r\n * import { serviceCollection } from 'relaxjs';\r\n *\r\n * serviceCollection.register(MyService, { inject: [Dependency] });\r\n */\r\nexport const serviceCollection = new ServiceCollection();\r\n\r\n/**\r\n * Global service container instance for resolving dependencies.\r\n * Use this to obtain service instances with all dependencies injected.\r\n *\r\n * @example\r\n * import { container } from 'relaxjs';\r\n *\r\n * const service = container.resolve(MyService);\r\n */\r\nexport const container = new ServiceContainer(serviceCollection);"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export * from '../DependencyInjection';\r\n", "/**\r\n * Global error handling for Relaxjs.\r\n * Register a handler with `onError()` to intercept errors before they throw.\r\n * Call `ctx.suppress()` in the handler to prevent the error from being thrown.\r\n *\r\n * @example\r\n * import { onError } from 'relaxjs';\r\n *\r\n * onError((error, ctx) => {\r\n * logToService(error.message, error.context);\r\n * showToast(error.message);\r\n * ctx.suppress();\r\n * });\r\n */\r\n\r\n/**\r\n * Passed to error handlers to control error behavior.\r\n * Call `suppress()` to prevent the error from being thrown.\r\n */\r\nexport interface ErrorContext {\r\n suppress(): void;\r\n}\r\n\r\n/**\r\n * Error with structured context for debugging.\r\n * The `context` record contains details like route name, component tag, route data.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * console.log(error.context.route);\r\n * console.log(error.context.componentTagName);\r\n * });\r\n */\r\nexport class RelaxError extends Error {\r\n constructor(\r\n message: string,\r\n public context: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n }\r\n}\r\n\r\n/** @internal */\r\ntype ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;\r\n\r\nlet handler: ErrorHandler | null = null;\r\n\r\n/**\r\n * Registers a global error handler for Relaxjs errors.\r\n * The handler receives the error and an `ErrorContext`.\r\n * Call `ctx.suppress()` to prevent the error from being thrown.\r\n * Only one handler can be active at a time; subsequent calls replace the previous handler.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * if (error.context.route === 'optional-panel') {\r\n * ctx.suppress();\r\n * return;\r\n * }\r\n * showErrorDialog(error.message);\r\n * });\r\n */\r\nexport function onError(fn: ErrorHandler) {\r\n handler = fn;\r\n}\r\n\r\n/**\r\n * Reports an error through the global handler.\r\n * Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.\r\n * The caller is responsible for throwing the returned error.\r\n *\r\n * @param message - Human-readable error description\r\n * @param context - Structured data for debugging (route, component, params, cause, etc.)\r\n * @returns The error to throw, or `null` if suppressed\r\n *\r\n * @example\r\n * const error = reportError('Failed to load route component', {\r\n * route: 'user',\r\n * componentTagName: 'user-profile',\r\n * routeData: { id: 123 },\r\n * });\r\n * if (error) throw error;\r\n */\r\nexport function reportError(message: string, context: Record<string, unknown>): RelaxError | null {\r\n const error = new RelaxError(message, context);\r\n if (handler) {\r\n let suppressed = false;\r\n const ctx: ErrorContext = {\r\n suppress() { suppressed = true; },\r\n };\r\n handler(error, ctx);\r\n if (suppressed) {\r\n return null;\r\n }\r\n }\r\n return error;\r\n}\r\n\r\n/**\r\n * Wraps an async function into a synchronous callback suitable for addEventListener.\r\n * Catches promise rejections and reports them through the global error handler.\r\n *\r\n * @param fn - Async function to wrap\r\n * @returns Synchronous function that can be passed to addEventListener\r\n *\r\n * @example\r\n * button.addEventListener('click', asyncHandler(async (e) => {\r\n * await saveData();\r\n * }));\r\n *\r\n * @example\r\n * form.addEventListener('submit', asyncHandler(async (e) => {\r\n * e.preventDefault();\r\n * await submitForm();\r\n * }));\r\n */\r\nexport function asyncHandler<TArgs extends unknown[]>(\r\n fn: (...args: TArgs) => Promise<void>,\r\n): (...args: TArgs) => void {\r\n return function (this: any, ...args: TArgs) {\r\n fn.call(this, ...args).catch((cause: unknown) => {\r\n const error = reportError('Async callback failed', { cause });\r\n if (error) throw error;\r\n });\r\n };\r\n}\r\n", "import { reportError } from './errors';\r\n\r\n/**\r\n * Generic constructor type used for dependency registration and injection.\r\n * Represents any class constructor that can be used with the DI container.\r\n *\r\n * @template T - The type of object the constructor creates\r\n *\r\n * @example\r\n * // Use with service registration\r\n * class UserService {}\r\n * const ctor: Constructor<UserService> = UserService;\r\n * serviceCollection.registerByType(ctor, { inject: [] });\r\n */\r\nexport type Constructor<T extends object = object> = new (...args: any[]) => T;\r\n\r\n/**\r\n * Controls how service instances are shared across the container hierarchy.\r\n * Used when registering services to define their lifetime behavior.\r\n *\r\n * - `global`: Single instance shared everywhere (singleton pattern)\r\n * - `closest`: New instance per container scope (scoped lifetime)\r\n *\r\n * @example\r\n * // Singleton service - same instance everywhere\r\n * serviceCollection.register(LoggerService, { scope: 'global', inject: [] });\r\n *\r\n * // Scoped service - new instance per scope\r\n * serviceCollection.register(RequestContext, { scope: 'closest', inject: [] });\r\n */\r\nexport type ServiceScope = 'global' | 'closest';\r\n\r\n/**\r\n * Configuration options for registering a service in the DI container.\r\n * Controls identification, lifetime, and dependency resolution.\r\n *\r\n * @example\r\n * // Register with constructor injection\r\n * const options: RegistrationOptions = {\r\n * scope: 'global',\r\n * inject: [DatabaseConnection, ConfigService]\r\n * };\r\n * serviceCollection.register(UserRepository, options);\r\n *\r\n * @example\r\n * // Register with property injection\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * properties: { logger: Logger, config: 'appConfig' }\r\n * };\r\n *\r\n * @example\r\n * // Register with a pre-created instance\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * instance: existingService\r\n * };\r\n */\r\nexport interface RegistrationOptions {\r\n /** Service lifetime - 'global' for singleton, 'closest' for scoped */\r\n scope?: ServiceScope;\r\n /** Optional string key for resolving by name instead of type */\r\n key?: string;\r\n /** Pre-existing instance to use instead of creating new one */\r\n instance?: unknown;\r\n /** Types or keys for constructor parameters, in order */\r\n inject: (string | Constructor)[];\r\n /** Map of property names to their injection types/keys */\r\n properties?: Record<string, string | Constructor>;\r\n}\r\n\r\n/**\r\n * Field decorator that injects a service from the global DI container.\r\n * The service is resolved when the class instance is created (not at class definition time),\r\n * so services must be registered before the first instance is created.\r\n *\r\n * Works with web components regardless of how they are created:\r\n * - By the browser (HTML parsing): services are resolved during construction\r\n * - By application code (`document.createElement` or `new`): same behavior\r\n * - Injected fields are available in `connectedCallback` and all lifecycle methods\r\n *\r\n * @example\r\n * // Using `@Inject` in a web component\r\n * class UserPanel extends HTMLElement {\r\n * @Inject(UserService)\r\n * private userService!: UserService;\r\n *\r\n * connectedCallback() {\r\n * // userService is already resolved and ready to use\r\n * const user = this.userService.getCurrentUser();\r\n * this.render(user);\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // Services must be registered before components are created.\r\n * // In your app entry point (e.g. main.ts):\r\n * serviceCollection.registerByType(UserService, { inject: [ApiClient] });\r\n * serviceCollection.registerByType(ApiClient, { inject: [] });\r\n *\r\n * // Now components can be created (by browser or code)\r\n * customElements.define('user-panel', UserPanel);\r\n */\r\nexport function Inject<T extends object>(typeOrKey: Constructor<T> | string) {\r\n return (_: undefined, context: ClassFieldDecoratorContext) => {\r\n return function(this: any) {\r\n return container.resolve(typeOrKey);\r\n };\r\n };\r\n}\r\n\r\n// Temporary collector of property injections - cleared after registration\r\n//const propertyCollector = new WeakMap<object, Record<string, string>>();\r\n\r\n/**\r\n * Class decorator that registers a service in the global DI container.\r\n * Registration happens at class definition time (when the module loads),\r\n * so import the module before creating instances that depend on this service.\r\n *\r\n * For web components: use `@ContainerService` on services, not on the\r\n * components themselves. Components use `@Inject` to consume services.\r\n *\r\n * @param options - Registration configuration including scope and dependencies\r\n *\r\n * @example\r\n * // Register a service that components can inject\r\n * @ContainerService({ inject: [ApiClient] })\r\n * class UserService {\r\n * constructor(private api: ApiClient) {}\r\n * getCurrentUser() { return this.api.get('/user'); }\r\n * }\r\n *\r\n * // Component consumes the service\r\n * class UserPanel extends HTMLElement {\r\n * @Inject(UserService)\r\n * private userService!: UserService;\r\n * }\r\n *\r\n * @example\r\n * // Service with custom key for named resolution\r\n * @ContainerService({ key: 'primaryCache', scope: 'global', inject: [] })\r\n * class CacheService {}\r\n *\r\n * // Later resolve by key\r\n * const cache = container.resolve('primaryCache');\r\n */\r\nexport function ContainerService<T extends object>(\r\n options?: RegistrationOptions\r\n) {\r\n return (target: Constructor<T>) => {\r\n const opts = options ?? {inject: []};\r\n\r\n if (opts.key) {\r\n serviceCollection.register(target, opts);\r\n } else {\r\n serviceCollection.registerByType(target, opts);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Internal class representing a registered service's metadata.\r\n * Holds all information needed to create and configure service instances.\r\n *\r\n * @internal This is an implementation detail and should not be used directly.\r\n */\r\nclass Registration {\r\n /**\r\n * Creates a new registration record.\r\n *\r\n * @param classConstructor - The class constructor function\r\n * @param scope - Instance sharing behavior\r\n * @param inject - Constructor parameter dependencies\r\n * @param properties - Property injection mappings\r\n * @param key - Optional string identifier\r\n * @param instance - Optional pre-created instance\r\n */\r\n constructor(\r\n public classConstructor: Constructor,\r\n public scope: ServiceScope,\r\n public inject: (string | Constructor)[],\r\n public properties: Record<string, string | Constructor> = {},\r\n public key?: string,\r\n public instance?: unknown\r\n ) {}\r\n}\r\n\r\n/**\r\n * Registry that stores service registration metadata.\r\n * Use this to register services before they can be resolved by a ServiceContainer.\r\n *\r\n * Typically you'll use the global `serviceCollection` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Register a service by type\r\n * serviceCollection.registerByType(LoggerService, { inject: [] });\r\n *\r\n * // Register with a string key\r\n * serviceCollection.register(CacheService, { key: 'cache', inject: [] });\r\n *\r\n * // Check if service is registered\r\n * const reg = serviceCollection.tryGet(LoggerService);\r\n * if (reg) {\r\n * console.log('Logger is registered');\r\n * }\r\n */\r\nexport class ServiceCollection {\r\n private servicesByKey = new Map<string, Registration>();\r\n private servicesByClassName = new Map<string, Registration>();\r\n\r\n /**\r\n * Registers a service with full configuration options.\r\n * The service will be resolvable by both its class name and optional key.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Registration configuration\r\n */\r\n register<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(\r\n constructor,\r\n options.scope ?? 'global',\r\n options.inject,\r\n options.properties ?? {},\r\n options.key,\r\n options.instance\r\n );\r\n\r\n if (options.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n /**\r\n * Registers a service by its class type.\r\n * The service will be resolvable by its class constructor.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Optional registration configuration\r\n */\r\n registerByType<T extends object>(\r\n constructor: Constructor<T>,\r\n options?: RegistrationOptions\r\n ): void {\r\n this.checkNameCollision(constructor);\r\n if (options) this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(constructor, options?.scope ?? 'global', options?.inject ?? [], options?.properties, options?.key, options?.instance);\r\n if (options?.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n private checkNameCollision<T extends object>(constructor: Constructor<T>): void {\r\n const existing = this.servicesByClassName.get(constructor.name);\r\n if (existing && existing.classConstructor !== constructor) {\r\n const error = reportError('Service name collision: different class registered with same name', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n private validateRegistration<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.checkNameCollision(constructor);\r\n\r\n if (options.key) {\r\n const existingByKey = this.servicesByKey.get(options.key);\r\n if (existingByKey && existingByKey.classConstructor !== constructor) {\r\n const error = reportError('Service key already registered to a different class', {\r\n key: options.key,\r\n existingClass: existingByKey.classConstructor.name,\r\n newClass: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n if (options.instance && options.inject.length > 0) {\r\n const error = reportError('Service has both instance and inject (inject will be ignored)', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Attempts to retrieve a service registration.\r\n * Returns undefined if the service is not registered.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration or undefined\r\n */\r\n tryGet<T extends object>(key: string | Constructor<T>): Registration | undefined {\r\n if (typeof key === 'string') {\r\n return this.servicesByKey.get(key);\r\n }\r\n return this.servicesByClassName.get(key.name);\r\n }\r\n\r\n /**\r\n * Retrieves a service registration or throws if not found.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration\r\n * @throws Error if the service is not registered\r\n */\r\n get<T extends object>(key: string | Constructor<T>): Registration {\r\n const reg = this.tryGet(key);\r\n if (!reg) {\r\n const service = typeof key === 'string' ? key : key.name;\r\n const error = reportError(`Failed to resolve service '${service}'`, {\r\n service,\r\n registeredTypes: Array.from(this.servicesByClassName.keys()),\r\n registeredKeys: Array.from(this.servicesByKey.keys()),\r\n });\r\n if (error) throw error;\r\n }\r\n return reg!;\r\n }\r\n}\r\n\r\n/**\r\n * Internal storage for tracking injected fields during service resolution.\r\n * @internal\r\n */\r\nconst injectedFields = new WeakMap<object, Map<string, string>>();\r\n\r\n/**\r\n * IoC container that resolves and manages service instances.\r\n * Creates instances based on registrations in a ServiceCollection,\r\n * handling constructor injection, property injection, and lifetime management.\r\n *\r\n * Typically you'll use the global `container` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Resolve a service by class\r\n * const logger = container.resolve(LoggerService);\r\n *\r\n * // Resolve by string key\r\n * const cache = container.resolve<CacheService>('primaryCache');\r\n *\r\n * @example\r\n * // Full setup workflow\r\n * serviceCollection.register(UserService, {\r\n * inject: [DatabaseConnection],\r\n * scope: 'global'\r\n * });\r\n *\r\n * const userService = container.resolve(UserService);\r\n */\r\nexport class ServiceContainer {\r\n private instances = new Map<string, any>();\r\n\r\n /**\r\n * Creates a new container backed by the given service collection.\r\n *\r\n * @param serviceCollection - The registry containing service registrations\r\n */\r\n constructor(private serviceCollection: ServiceCollection) {}\r\n\r\n /**\r\n * Resolves a service instance by class type or string key.\r\n * Creates the instance if not already cached (for global scope).\r\n * Handles constructor and property injection automatically.\r\n *\r\n * @param keyOrType - Either a string key or class constructor\r\n * @returns The resolved service instance\r\n * @throws Error if the service is not registered\r\n *\r\n * @example\r\n * const service = container.resolve(MyService);\r\n */\r\n resolve<T extends object>(keyOrType: string | Constructor<T>): T {\r\n const key = typeof keyOrType === 'string' ? keyOrType : keyOrType.name;\r\n\r\n if (this.instances.has(key)) {\r\n return this.instances.get(key);\r\n }\r\n\r\n const registration = this.serviceCollection.get(keyOrType);\r\n if (!registration) {\r\n const error = reportError(`Failed to resolve service '${key}'`, { service: key });\r\n if (error) throw error;\r\n return undefined as unknown as T;\r\n }\r\n\r\n if (registration.instance) {\r\n const inst = registration.instance as T;\r\n this.injectFields(inst, registration);\r\n this.instances.set(key, inst);\r\n return inst;\r\n }\r\n\r\n const instance = this.createInstance<T>(registration);\r\n if (registration.scope === 'global') {\r\n this.instances.set(key, instance);\r\n }\r\n this.injectFields(instance, registration);\r\n\r\n return instance;\r\n }\r\n\r\n /**\r\n * Creates a new instance of a service, resolving all constructor dependencies.\r\n */\r\n private createInstance<T extends object>(registration: Registration): T {\r\n const constructor = registration.classConstructor as Constructor<T>;\r\n\r\n const dependencies = registration.inject.map(dep => this.resolve(dep));\r\n return new constructor(...dependencies);\r\n }\r\n\r\n /**\r\n * Injects dependencies into instance properties based on registration config.\r\n */\r\n private injectFields<T extends object>(instance: T, registration: Registration): void {\r\n for (const [fieldName, keyOrType] of Object.entries(registration.properties)) {\r\n (instance as any)[fieldName] = this.resolve(keyOrType);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Global service collection instance for registering services.\r\n * Use this to register services that can later be resolved by the container.\r\n *\r\n * @example\r\n * import { serviceCollection } from 'relaxjs';\r\n *\r\n * serviceCollection.register(MyService, { inject: [Dependency] });\r\n */\r\nexport const serviceCollection = new ServiceCollection();\r\n\r\n/**\r\n * Global service container instance for resolving dependencies.\r\n * Use this to obtain service instances with all dependencies injected.\r\n *\r\n * @example\r\n * import { container } from 'relaxjs';\r\n *\r\n * const service = container.resolve(MyService);\r\n */\r\nexport const container = new ServiceContainer(serviceCollection);"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,sBAAAE,EAAA,WAAAC,EAAA,sBAAAC,EAAA,qBAAAC,EAAA,cAAAC,EAAA,sBAAAC,IAAA,eAAAC,EAAAR,GCiCO,IAAMS,EAAN,cAAyB,KAAM,CAClC,YACIC,EACOC,EACT,CACE,MAAMD,CAAO,EAFN,aAAAC,CAGX,CACJ,EAKIC,EAA+B,KAsC5B,SAASC,EAAYC,EAAiBC,EAAqD,CAC9F,IAAMC,EAAQ,IAAIC,EAAWH,EAASC,CAAO,EAC7C,GAAIG,EAAS,CACT,IAAIC,EAAa,GAKjB,GADAD,EAAQF,EAHkB,CACtB,UAAW,CAAEG,EAAa,EAAM,CACpC,CACkB,EACdA,EACA,OAAO,IAEf,CACA,OAAOH,CACX,CCOO,SAASI,EAAyBC,EAAoC,CACzE,MAAO,CAACC,EAAcC,IACX,UAAoB,CACvB,OAAOC,EAAU,QAAQH,CAAS,CACtC,CAER,CAqCO,SAASI,EACZC,EACF,CACE,OAAQC,GAA2B,CAC/B,IAAMC,EAAOF,GAAW,CAAC,OAAQ,CAAC,CAAC,EAE/BE,EAAK,IACLC,EAAkB,SAASF,EAAQC,CAAI,EAEvCC,EAAkB,eAAeF,EAAQC,CAAI,CAErD,CACJ,CAQA,IAAME,EAAN,KAAmB,CAWf,YACWC,EACAC,EACAC,EACAC,EAAmD,CAAC,EACpDC,EACAC,EACT,CANS,sBAAAL,EACA,WAAAC,EACA,YAAAC,EACA,gBAAAC,EACA,SAAAC,EACA,cAAAC,CACR,CACP,EAqBaC,EAAN,KAAwB,CAAxB,cACH,KAAQ,cAAgB,IAAI,IAC5B,KAAQ,oBAAsB,IAAI,IASlC,SAA2BC,EAA6BZ,EAAoC,CACxF,KAAK,qBAAqBY,EAAaZ,CAAO,EAE9C,IAAMa,EAAM,IAAIT,EACZQ,EACAZ,EAAQ,OAAS,SACjBA,EAAQ,OACRA,EAAQ,YAAc,CAAC,EACvBA,EAAQ,IACRA,EAAQ,QACZ,EAEIA,EAAQ,KACR,KAAK,cAAc,IAAIA,EAAQ,IAAKa,CAAG,EAE3C,KAAK,oBAAoB,IAAID,EAAY,KAAMC,CAAG,CACtD,CASA,eACID,EACAZ,EACI,CACJ,KAAK,mBAAmBY,CAAW,EAC/BZ,GAAS,KAAK,qBAAqBY,EAAaZ,CAAO,EAE3D,IAAMa,EAAM,IAAIT,EAAaQ,EAAaZ,GAAS,OAAS,SAAUA,GAAS,QAAU,CAAC,EAAGA,GAAS,WAAYA,GAAS,IAAKA,GAAS,QAAQ,EAC7IA,GAAS,KACT,KAAK,cAAc,IAAIA,EAAQ,IAAKa,CAAG,EAE3C,KAAK,oBAAoB,IAAID,EAAY,KAAMC,CAAG,CACtD,CAEQ,mBAAqCD,EAAmC,CAC5E,IAAME,EAAW,KAAK,oBAAoB,IAAIF,EAAY,IAAI,EAC9D,GAAIE,GAAYA,EAAS,mBAAqBF,EAAa,CACvD,IAAMG,EAAQC,EAAY,oEAAqE,CAC3F,QAASJ,EAAY,IACzB,CAAC,EACD,GAAIG,EAAO,MAAMA,CACrB,CACJ,CAEQ,qBAAuCH,EAA6BZ,EAAoC,CAG5G,GAFA,KAAK,mBAAmBY,CAAW,EAE/BZ,EAAQ,IAAK,CACb,IAAMiB,EAAgB,KAAK,cAAc,IAAIjB,EAAQ,GAAG,EACxD,GAAIiB,GAAiBA,EAAc,mBAAqBL,EAAa,CACjE,IAAMG,EAAQC,EAAY,sDAAuD,CAC7E,IAAKhB,EAAQ,IACb,cAAeiB,EAAc,iBAAiB,KAC9C,SAAUL,EAAY,IAC1B,CAAC,EACD,GAAIG,EAAO,MAAMA,CACrB,CACJ,CAEA,GAAIf,EAAQ,UAAYA,EAAQ,OAAO,OAAS,EAAG,CAC/C,IAAMe,EAAQC,EAAY,gEAAiE,CACvF,QAASJ,EAAY,IACzB,CAAC,EACD,GAAIG,EAAO,MAAMA,CACrB,CACJ,CASA,OAAyBN,EAAwD,CAC7E,OAAI,OAAOA,GAAQ,SACR,KAAK,cAAc,IAAIA,CAAG,EAE9B,KAAK,oBAAoB,IAAIA,EAAI,IAAI,CAChD,CASA,IAAsBA,EAA4C,CAC9D,IAAMI,EAAM,KAAK,OAAOJ,CAAG,EAC3B,GAAI,CAACI,EAAK,CACN,IAAMK,EAAU,OAAOT,GAAQ,SAAWA,EAAMA,EAAI,KAC9CM,EAAQC,EAAY,8BAA8BE,CAAO,IAAK,CAChE,QAAAA,EACA,gBAAiB,MAAM,KAAK,KAAK,oBAAoB,KAAK,CAAC,EAC3D,eAAgB,MAAM,KAAK,KAAK,cAAc,KAAK,CAAC,CACxD,CAAC,EACD,GAAIH,EAAO,MAAMA,CACrB,CACA,OAAOF,CACX,CACJ,EA+BO,IAAMM,EAAN,KAAuB,CAQ1B,YAAoBC,EAAsC,CAAtC,uBAAAA,EAPpB,KAAQ,UAAY,IAAI,GAOmC,CAc3D,QAA0BC,EAAuC,CAC7D,IAAMC,EAAM,OAAOD,GAAc,SAAWA,EAAYA,EAAU,KAElE,GAAI,KAAK,UAAU,IAAIC,CAAG,EACtB,OAAO,KAAK,UAAU,IAAIA,CAAG,EAGjC,IAAMC,EAAe,KAAK,kBAAkB,IAAIF,CAAS,EACzD,GAAI,CAACE,EAAc,CACf,IAAMC,EAAQC,EAAY,8BAA8BH,CAAG,IAAK,CAAE,QAASA,CAAI,CAAC,EAChF,GAAIE,EAAO,MAAMA,EACjB,MACJ,CAEA,GAAID,EAAa,SAAU,CACvB,IAAMG,EAAOH,EAAa,SAC1B,YAAK,aAAaG,EAAMH,CAAY,EACpC,KAAK,UAAU,IAAID,EAAKI,CAAI,EACrBA,CACX,CAEA,IAAMC,EAAW,KAAK,eAAkBJ,CAAY,EACpD,OAAIA,EAAa,QAAU,UACvB,KAAK,UAAU,IAAID,EAAKK,CAAQ,EAEpC,KAAK,aAAaA,EAAUJ,CAAY,EAEjCI,CACX,CAKQ,eAAiCJ,EAA+B,CACpE,IAAMK,EAAcL,EAAa,iBAE3BM,EAAeN,EAAa,OAAO,IAAIO,GAAO,KAAK,QAAQA,CAAG,CAAC,EACrE,OAAO,IAAIF,EAAY,GAAGC,CAAY,CAC1C,CAKQ,aAA+BF,EAAaJ,EAAkC,CAClF,OAAW,CAACQ,EAAWV,CAAS,IAAK,OAAO,QAAQE,EAAa,UAAU,EACtEI,EAAiBI,CAAS,EAAI,KAAK,QAAQV,CAAS,CAE7D,CACJ,EAWaD,EAAoB,IAAIY,EAWxBC,EAAY,IAAId,EAAiBC,CAAiB",
6
6
  "names": ["index_exports", "__export", "ContainerService", "Inject", "ServiceCollection", "ServiceContainer", "container", "serviceCollection", "__toCommonJS", "RelaxError", "message", "context", "handler", "reportError", "message", "context", "error", "RelaxError", "handler", "suppressed", "Inject", "typeOrKey", "_", "context", "container", "ContainerService", "options", "target", "opts", "serviceCollection", "Registration", "classConstructor", "scope", "inject", "properties", "key", "instance", "ServiceCollection", "constructor", "reg", "existing", "error", "reportError", "existingByKey", "service", "ServiceContainer", "serviceCollection", "keyOrType", "key", "registration", "error", "reportError", "inst", "instance", "constructor", "dependencies", "dep", "fieldName", "ServiceCollection", "container"]
7
7
  }
package/dist/di/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var a=class extends Error{constructor(e,r){super(e);this.context=r}},u=null;function o(n,t){let e=new a(n,t);if(u){let r=!1;if(u(e,{suppress(){r=!0}}),r)return null}return e}function h(n){return(t,e)=>function(){return p.resolve(n)}}function x(n){return t=>{let e=n??{inject:[]};e.key?d.register(t,e):d.registerByType(t,e)}}var c=class{constructor(t,e,r,s={},i,v){this.classConstructor=t;this.scope=e;this.inject=r;this.properties=s;this.key=i;this.instance=v}},l=class{constructor(){this.servicesByKey=new Map;this.servicesByClassName=new Map}register(t,e){this.validateRegistration(t,e);let r=new c(t,e.scope??"global",e.inject,e.properties??{},e.key,e.instance);e.key&&this.servicesByKey.set(e.key,r),this.servicesByClassName.set(t.name,r)}registerByType(t,e){this.checkNameCollision(t),e&&this.validateRegistration(t,e);let r=new c(t,e?.scope,e?.inject??[],e?.properties,e?.key,e?.instance);e?.key&&this.servicesByKey.set(e.key,r),this.servicesByClassName.set(t.name,r)}checkNameCollision(t){let e=this.servicesByClassName.get(t.name);if(e&&e.classConstructor!==t){let r=o("Service name collision: different class registered with same name",{service:t.name});if(r)throw r}}validateRegistration(t,e){if(this.checkNameCollision(t),e.key){let r=this.servicesByKey.get(e.key);if(r&&r.classConstructor!==t){let s=o("Service key already registered to a different class",{key:e.key,existingClass:r.classConstructor.name,newClass:t.name});if(s)throw s}}if(e.instance&&e.inject.length>0){let r=o("Service has both instance and inject (inject will be ignored)",{service:t.name});if(r)throw r}}tryGet(t){return typeof t=="string"?this.servicesByKey.get(t):this.servicesByClassName.get(t.name)}get(t){let e=this.tryGet(t);if(!e){let r=typeof t=="string"?t:t.name,s=o(`Failed to resolve service '${r}'`,{service:r,registeredTypes:Array.from(this.servicesByClassName.keys()),registeredKeys:Array.from(this.servicesByKey.keys())});if(s)throw s}return e}};var g=class{constructor(t){this.serviceCollection=t;this.instances=new Map}resolve(t){let e=typeof t=="string"?t:t.name;if(this.instances.has(e))return this.instances.get(e);let r=this.serviceCollection.get(t);if(!r){let i=o(`Failed to resolve service '${e}'`,{service:e});if(i)throw i;return}if(r.instance){let i=r.instance;return this.injectFields(i,r),this.instances.set(e,i),i}let s=this.createInstance(r);return r.scope==="global"&&this.instances.set(e,s),this.injectFields(s,r),s}createInstance(t){let e=t.classConstructor,r=t.inject.map(s=>this.resolve(s));return new e(...r)}injectFields(t,e){for(let[r,s]of Object.entries(e.properties))t[r]=this.resolve(s)}},d=new l,p=new g(d);export{x as ContainerService,h as Inject,l as ServiceCollection,g as ServiceContainer,p as container,d as serviceCollection};
1
+ var a=class extends Error{constructor(e,r){super(e);this.context=r}},u=null;function o(n,t){let e=new a(n,t);if(u){let r=!1;if(u(e,{suppress(){r=!0}}),r)return null}return e}function h(n){return(t,e)=>function(){return p.resolve(n)}}function x(n){return t=>{let e=n??{inject:[]};e.key?d.register(t,e):d.registerByType(t,e)}}var c=class{constructor(t,e,r,s={},i,v){this.classConstructor=t;this.scope=e;this.inject=r;this.properties=s;this.key=i;this.instance=v}},l=class{constructor(){this.servicesByKey=new Map;this.servicesByClassName=new Map}register(t,e){this.validateRegistration(t,e);let r=new c(t,e.scope??"global",e.inject,e.properties??{},e.key,e.instance);e.key&&this.servicesByKey.set(e.key,r),this.servicesByClassName.set(t.name,r)}registerByType(t,e){this.checkNameCollision(t),e&&this.validateRegistration(t,e);let r=new c(t,e?.scope??"global",e?.inject??[],e?.properties,e?.key,e?.instance);e?.key&&this.servicesByKey.set(e.key,r),this.servicesByClassName.set(t.name,r)}checkNameCollision(t){let e=this.servicesByClassName.get(t.name);if(e&&e.classConstructor!==t){let r=o("Service name collision: different class registered with same name",{service:t.name});if(r)throw r}}validateRegistration(t,e){if(this.checkNameCollision(t),e.key){let r=this.servicesByKey.get(e.key);if(r&&r.classConstructor!==t){let s=o("Service key already registered to a different class",{key:e.key,existingClass:r.classConstructor.name,newClass:t.name});if(s)throw s}}if(e.instance&&e.inject.length>0){let r=o("Service has both instance and inject (inject will be ignored)",{service:t.name});if(r)throw r}}tryGet(t){return typeof t=="string"?this.servicesByKey.get(t):this.servicesByClassName.get(t.name)}get(t){let e=this.tryGet(t);if(!e){let r=typeof t=="string"?t:t.name,s=o(`Failed to resolve service '${r}'`,{service:r,registeredTypes:Array.from(this.servicesByClassName.keys()),registeredKeys:Array.from(this.servicesByKey.keys())});if(s)throw s}return e}};var g=class{constructor(t){this.serviceCollection=t;this.instances=new Map}resolve(t){let e=typeof t=="string"?t:t.name;if(this.instances.has(e))return this.instances.get(e);let r=this.serviceCollection.get(t);if(!r){let i=o(`Failed to resolve service '${e}'`,{service:e});if(i)throw i;return}if(r.instance){let i=r.instance;return this.injectFields(i,r),this.instances.set(e,i),i}let s=this.createInstance(r);return r.scope==="global"&&this.instances.set(e,s),this.injectFields(s,r),s}createInstance(t){let e=t.classConstructor,r=t.inject.map(s=>this.resolve(s));return new e(...r)}injectFields(t,e){for(let[r,s]of Object.entries(e.properties))t[r]=this.resolve(s)}},d=new l,p=new g(d);export{x as ContainerService,h as Inject,l as ServiceCollection,g as ServiceContainer,p as container,d as serviceCollection};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/errors.ts", "../../src/DependencyInjection.ts"],
4
- "sourcesContent": ["/**\r\n * Global error handling for Relaxjs.\r\n * Register a handler with `onError()` to intercept errors before they throw.\r\n * Call `ctx.suppress()` in the handler to prevent the error from being thrown.\r\n *\r\n * @example\r\n * import { onError } from 'relaxjs';\r\n *\r\n * onError((error, ctx) => {\r\n * logToService(error.message, error.context);\r\n * showToast(error.message);\r\n * ctx.suppress();\r\n * });\r\n */\r\n\r\n/**\r\n * Passed to error handlers to control error behavior.\r\n * Call `suppress()` to prevent the error from being thrown.\r\n */\r\nexport interface ErrorContext {\r\n suppress(): void;\r\n}\r\n\r\n/**\r\n * Error with structured context for debugging.\r\n * The `context` record contains details like route name, component tag, route data.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * console.log(error.context.route);\r\n * console.log(error.context.componentTagName);\r\n * });\r\n */\r\nexport class RelaxError extends Error {\r\n constructor(\r\n message: string,\r\n public context: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n }\r\n}\r\n\r\n/** @internal */\r\ntype ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;\r\n\r\nlet handler: ErrorHandler | null = null;\r\n\r\n/**\r\n * Registers a global error handler for Relaxjs errors.\r\n * The handler receives the error and an `ErrorContext`.\r\n * Call `ctx.suppress()` to prevent the error from being thrown.\r\n * Only one handler can be active at a time; subsequent calls replace the previous handler.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * if (error.context.route === 'optional-panel') {\r\n * ctx.suppress();\r\n * return;\r\n * }\r\n * showErrorDialog(error.message);\r\n * });\r\n */\r\nexport function onError(fn: ErrorHandler) {\r\n handler = fn;\r\n}\r\n\r\n/**\r\n * Reports an error through the global handler.\r\n * Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.\r\n * The caller is responsible for throwing the returned error.\r\n *\r\n * @param message - Human-readable error description\r\n * @param context - Structured data for debugging (route, component, params, cause, etc.)\r\n * @returns The error to throw, or `null` if suppressed\r\n *\r\n * @example\r\n * const error = reportError('Failed to load route component', {\r\n * route: 'user',\r\n * componentTagName: 'user-profile',\r\n * routeData: { id: 123 },\r\n * });\r\n * if (error) throw error;\r\n */\r\nexport function reportError(message: string, context: Record<string, unknown>): RelaxError | null {\r\n const error = new RelaxError(message, context);\r\n if (handler) {\r\n let suppressed = false;\r\n const ctx: ErrorContext = {\r\n suppress() { suppressed = true; },\r\n };\r\n handler(error, ctx);\r\n if (suppressed) {\r\n return null;\r\n }\r\n }\r\n return error;\r\n}\r\n\r\n/**\r\n * Wraps an async function into a synchronous callback suitable for addEventListener.\r\n * Catches promise rejections and reports them through the global error handler.\r\n *\r\n * @param fn - Async function to wrap\r\n * @returns Synchronous function that can be passed to addEventListener\r\n *\r\n * @example\r\n * button.addEventListener('click', asyncHandler(async (e) => {\r\n * await saveData();\r\n * }));\r\n *\r\n * @example\r\n * form.addEventListener('submit', asyncHandler(async (e) => {\r\n * e.preventDefault();\r\n * await submitForm();\r\n * }));\r\n */\r\nexport function asyncHandler<TArgs extends unknown[]>(\r\n fn: (...args: TArgs) => Promise<void>,\r\n): (...args: TArgs) => void {\r\n return function (this: any, ...args: TArgs) {\r\n fn.call(this, ...args).catch((cause: unknown) => {\r\n const error = reportError('Async callback failed', { cause });\r\n if (error) throw error;\r\n });\r\n };\r\n}\r\n", "import { reportError } from './errors';\r\n\r\n/**\r\n * Generic constructor type used for dependency registration and injection.\r\n * Represents any class constructor that can be used with the DI container.\r\n *\r\n * @template T - The type of object the constructor creates\r\n *\r\n * @example\r\n * // Use with service registration\r\n * class UserService {}\r\n * const ctor: Constructor<UserService> = UserService;\r\n * serviceCollection.registerByType(ctor, { inject: [] });\r\n */\r\nexport type Constructor<T extends object = object> = new (...args: any[]) => T;\r\n\r\n/**\r\n * Controls how service instances are shared across the container hierarchy.\r\n * Used when registering services to define their lifetime behavior.\r\n *\r\n * - `global`: Single instance shared everywhere (singleton pattern)\r\n * - `closest`: New instance per container scope (scoped lifetime)\r\n *\r\n * @example\r\n * // Singleton service - same instance everywhere\r\n * serviceCollection.register(LoggerService, { scope: 'global', inject: [] });\r\n *\r\n * // Scoped service - new instance per scope\r\n * serviceCollection.register(RequestContext, { scope: 'closest', inject: [] });\r\n */\r\nexport type ServiceScope = 'global' | 'closest';\r\n\r\n/**\r\n * Configuration options for registering a service in the DI container.\r\n * Controls identification, lifetime, and dependency resolution.\r\n *\r\n * @example\r\n * // Register with constructor injection\r\n * const options: RegistrationOptions = {\r\n * scope: 'global',\r\n * inject: [DatabaseConnection, ConfigService]\r\n * };\r\n * serviceCollection.register(UserRepository, options);\r\n *\r\n * @example\r\n * // Register with property injection\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * properties: { logger: Logger, config: 'appConfig' }\r\n * };\r\n *\r\n * @example\r\n * // Register with a pre-created instance\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * instance: existingService\r\n * };\r\n */\r\nexport interface RegistrationOptions {\r\n /** Service lifetime - 'global' for singleton, 'closest' for scoped */\r\n scope?: ServiceScope;\r\n /** Optional string key for resolving by name instead of type */\r\n key?: string;\r\n /** Pre-existing instance to use instead of creating new one */\r\n instance?: unknown;\r\n /** Types or keys for constructor parameters, in order */\r\n inject: (string | Constructor)[];\r\n /** Map of property names to their injection types/keys */\r\n properties?: Record<string, string | Constructor>;\r\n}\r\n\r\n/**\r\n * Field decorator that injects a service from the global DI container.\r\n * The service is resolved when the class instance is created (not at class definition time),\r\n * so services must be registered before the first instance is created.\r\n *\r\n * Works with web components regardless of how they are created:\r\n * - By the browser (HTML parsing): services are resolved during construction\r\n * - By application code (`document.createElement` or `new`): same behavior\r\n * - Injected fields are available in `connectedCallback` and all lifecycle methods\r\n *\r\n * @example\r\n * // Using `@Inject` in a web component\r\n * class UserPanel extends HTMLElement {\r\n * @Inject(UserService)\r\n * private userService!: UserService;\r\n *\r\n * connectedCallback() {\r\n * // userService is already resolved and ready to use\r\n * const user = this.userService.getCurrentUser();\r\n * this.render(user);\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // Services must be registered before components are created.\r\n * // In your app entry point (e.g. main.ts):\r\n * serviceCollection.registerByType(UserService, { inject: [ApiClient] });\r\n * serviceCollection.registerByType(ApiClient, { inject: [] });\r\n *\r\n * // Now components can be created (by browser or code)\r\n * customElements.define('user-panel', UserPanel);\r\n */\r\nexport function Inject<T extends object>(typeOrKey: Constructor<T> | string) {\r\n return (_: undefined, context: ClassFieldDecoratorContext) => {\r\n return function(this: any) {\r\n return container.resolve(typeOrKey);\r\n };\r\n };\r\n}\r\n\r\n// Temporary collector of property injections - cleared after registration\r\n//const propertyCollector = new WeakMap<object, Record<string, string>>();\r\n\r\n/**\r\n * Class decorator that registers a service in the global DI container.\r\n * Registration happens at class definition time (when the module loads),\r\n * so import the module before creating instances that depend on this service.\r\n *\r\n * For web components: use `@ContainerService` on services, not on the\r\n * components themselves. Components use `@Inject` to consume services.\r\n *\r\n * @param options - Registration configuration including scope and dependencies\r\n *\r\n * @example\r\n * // Register a service that components can inject\r\n * @ContainerService({ inject: [ApiClient] })\r\n * class UserService {\r\n * constructor(private api: ApiClient) {}\r\n * getCurrentUser() { return this.api.get('/user'); }\r\n * }\r\n *\r\n * // Component consumes the service\r\n * class UserPanel extends HTMLElement {\r\n * @Inject(UserService)\r\n * private userService!: UserService;\r\n * }\r\n *\r\n * @example\r\n * // Service with custom key for named resolution\r\n * @ContainerService({ key: 'primaryCache', scope: 'global', inject: [] })\r\n * class CacheService {}\r\n *\r\n * // Later resolve by key\r\n * const cache = container.resolve('primaryCache');\r\n */\r\nexport function ContainerService<T extends object>(\r\n options?: RegistrationOptions\r\n) {\r\n return (target: Constructor<T>) => {\r\n const opts = options ?? {inject: []};\r\n\r\n if (opts.key) {\r\n serviceCollection.register(target, opts);\r\n } else {\r\n serviceCollection.registerByType(target, opts);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Internal class representing a registered service's metadata.\r\n * Holds all information needed to create and configure service instances.\r\n *\r\n * @internal This is an implementation detail and should not be used directly.\r\n */\r\nclass Registration {\r\n /**\r\n * Creates a new registration record.\r\n *\r\n * @param classConstructor - The class constructor function\r\n * @param scope - Instance sharing behavior\r\n * @param inject - Constructor parameter dependencies\r\n * @param properties - Property injection mappings\r\n * @param key - Optional string identifier\r\n * @param instance - Optional pre-created instance\r\n */\r\n constructor(\r\n public classConstructor: Constructor,\r\n public scope: ServiceScope,\r\n public inject: (string | Constructor)[],\r\n public properties: Record<string, string | Constructor> = {},\r\n public key?: string,\r\n public instance?: unknown\r\n ) {}\r\n}\r\n\r\n/**\r\n * Registry that stores service registration metadata.\r\n * Use this to register services before they can be resolved by a ServiceContainer.\r\n *\r\n * Typically you'll use the global `serviceCollection` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Register a service by type\r\n * serviceCollection.registerByType(LoggerService, { inject: [] });\r\n *\r\n * // Register with a string key\r\n * serviceCollection.register(CacheService, { key: 'cache', inject: [] });\r\n *\r\n * // Check if service is registered\r\n * const reg = serviceCollection.tryGet(LoggerService);\r\n * if (reg) {\r\n * console.log('Logger is registered');\r\n * }\r\n */\r\nexport class ServiceCollection {\r\n private servicesByKey = new Map<string, Registration>();\r\n private servicesByClassName = new Map<string, Registration>();\r\n\r\n /**\r\n * Registers a service with full configuration options.\r\n * The service will be resolvable by both its class name and optional key.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Registration configuration\r\n */\r\n register<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(\r\n constructor,\r\n options.scope ?? 'global',\r\n options.inject,\r\n options.properties ?? {},\r\n options.key,\r\n options.instance\r\n );\r\n\r\n if (options.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n /**\r\n * Registers a service by its class type.\r\n * The service will be resolvable by its class constructor.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Optional registration configuration\r\n */\r\n registerByType<T extends object>(\r\n constructor: Constructor<T>,\r\n options?: RegistrationOptions\r\n ): void {\r\n this.checkNameCollision(constructor);\r\n if (options) this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(constructor, options?.scope, options?.inject ?? [], options?.properties, options?.key, options?.instance);\r\n if (options?.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n private checkNameCollision<T extends object>(constructor: Constructor<T>): void {\r\n const existing = this.servicesByClassName.get(constructor.name);\r\n if (existing && existing.classConstructor !== constructor) {\r\n const error = reportError('Service name collision: different class registered with same name', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n private validateRegistration<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.checkNameCollision(constructor);\r\n\r\n if (options.key) {\r\n const existingByKey = this.servicesByKey.get(options.key);\r\n if (existingByKey && existingByKey.classConstructor !== constructor) {\r\n const error = reportError('Service key already registered to a different class', {\r\n key: options.key,\r\n existingClass: existingByKey.classConstructor.name,\r\n newClass: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n if (options.instance && options.inject.length > 0) {\r\n const error = reportError('Service has both instance and inject (inject will be ignored)', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Attempts to retrieve a service registration.\r\n * Returns undefined if the service is not registered.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration or undefined\r\n */\r\n tryGet<T extends object>(key: string | Constructor<T>): Registration | undefined {\r\n if (typeof key === 'string') {\r\n return this.servicesByKey.get(key);\r\n }\r\n return this.servicesByClassName.get(key.name);\r\n }\r\n\r\n /**\r\n * Retrieves a service registration or throws if not found.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration\r\n * @throws Error if the service is not registered\r\n */\r\n get<T extends object>(key: string | Constructor<T>): Registration {\r\n const reg = this.tryGet(key);\r\n if (!reg) {\r\n const service = typeof key === 'string' ? key : key.name;\r\n const error = reportError(`Failed to resolve service '${service}'`, {\r\n service,\r\n registeredTypes: Array.from(this.servicesByClassName.keys()),\r\n registeredKeys: Array.from(this.servicesByKey.keys()),\r\n });\r\n if (error) throw error;\r\n }\r\n return reg!;\r\n }\r\n}\r\n\r\n/**\r\n * Internal storage for tracking injected fields during service resolution.\r\n * @internal\r\n */\r\nconst injectedFields = new WeakMap<object, Map<string, string>>();\r\n\r\n/**\r\n * IoC container that resolves and manages service instances.\r\n * Creates instances based on registrations in a ServiceCollection,\r\n * handling constructor injection, property injection, and lifetime management.\r\n *\r\n * Typically you'll use the global `container` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Resolve a service by class\r\n * const logger = container.resolve(LoggerService);\r\n *\r\n * // Resolve by string key\r\n * const cache = container.resolve<CacheService>('primaryCache');\r\n *\r\n * @example\r\n * // Full setup workflow\r\n * serviceCollection.register(UserService, {\r\n * inject: [DatabaseConnection],\r\n * scope: 'global'\r\n * });\r\n *\r\n * const userService = container.resolve(UserService);\r\n */\r\nexport class ServiceContainer {\r\n private instances = new Map<string, any>();\r\n\r\n /**\r\n * Creates a new container backed by the given service collection.\r\n *\r\n * @param serviceCollection - The registry containing service registrations\r\n */\r\n constructor(private serviceCollection: ServiceCollection) {}\r\n\r\n /**\r\n * Resolves a service instance by class type or string key.\r\n * Creates the instance if not already cached (for global scope).\r\n * Handles constructor and property injection automatically.\r\n *\r\n * @param keyOrType - Either a string key or class constructor\r\n * @returns The resolved service instance\r\n * @throws Error if the service is not registered\r\n *\r\n * @example\r\n * const service = container.resolve(MyService);\r\n */\r\n resolve<T extends object>(keyOrType: string | Constructor<T>): T {\r\n const key = typeof keyOrType === 'string' ? keyOrType : keyOrType.name;\r\n\r\n if (this.instances.has(key)) {\r\n return this.instances.get(key);\r\n }\r\n\r\n const registration = this.serviceCollection.get(keyOrType);\r\n if (!registration) {\r\n const error = reportError(`Failed to resolve service '${key}'`, { service: key });\r\n if (error) throw error;\r\n return undefined as unknown as T;\r\n }\r\n\r\n if (registration.instance) {\r\n const inst = registration.instance as T;\r\n this.injectFields(inst, registration);\r\n this.instances.set(key, inst);\r\n return inst;\r\n }\r\n\r\n const instance = this.createInstance<T>(registration);\r\n if (registration.scope === 'global') {\r\n this.instances.set(key, instance);\r\n }\r\n this.injectFields(instance, registration);\r\n\r\n return instance;\r\n }\r\n\r\n /**\r\n * Creates a new instance of a service, resolving all constructor dependencies.\r\n */\r\n private createInstance<T extends object>(registration: Registration): T {\r\n const constructor = registration.classConstructor as Constructor<T>;\r\n\r\n const dependencies = registration.inject.map(dep => this.resolve(dep));\r\n return new constructor(...dependencies);\r\n }\r\n\r\n /**\r\n * Injects dependencies into instance properties based on registration config.\r\n */\r\n private injectFields<T extends object>(instance: T, registration: Registration): void {\r\n for (const [fieldName, keyOrType] of Object.entries(registration.properties)) {\r\n (instance as any)[fieldName] = this.resolve(keyOrType);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Global service collection instance for registering services.\r\n * Use this to register services that can later be resolved by the container.\r\n *\r\n * @example\r\n * import { serviceCollection } from 'relaxjs';\r\n *\r\n * serviceCollection.register(MyService, { inject: [Dependency] });\r\n */\r\nexport const serviceCollection = new ServiceCollection();\r\n\r\n/**\r\n * Global service container instance for resolving dependencies.\r\n * Use this to obtain service instances with all dependencies injected.\r\n *\r\n * @example\r\n * import { container } from 'relaxjs';\r\n *\r\n * const service = container.resolve(MyService);\r\n */\r\nexport const container = new ServiceContainer(serviceCollection);"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\r\n * Global error handling for Relaxjs.\r\n * Register a handler with `onError()` to intercept errors before they throw.\r\n * Call `ctx.suppress()` in the handler to prevent the error from being thrown.\r\n *\r\n * @example\r\n * import { onError } from 'relaxjs';\r\n *\r\n * onError((error, ctx) => {\r\n * logToService(error.message, error.context);\r\n * showToast(error.message);\r\n * ctx.suppress();\r\n * });\r\n */\r\n\r\n/**\r\n * Passed to error handlers to control error behavior.\r\n * Call `suppress()` to prevent the error from being thrown.\r\n */\r\nexport interface ErrorContext {\r\n suppress(): void;\r\n}\r\n\r\n/**\r\n * Error with structured context for debugging.\r\n * The `context` record contains details like route name, component tag, route data.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * console.log(error.context.route);\r\n * console.log(error.context.componentTagName);\r\n * });\r\n */\r\nexport class RelaxError extends Error {\r\n constructor(\r\n message: string,\r\n public context: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n }\r\n}\r\n\r\n/** @internal */\r\ntype ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;\r\n\r\nlet handler: ErrorHandler | null = null;\r\n\r\n/**\r\n * Registers a global error handler for Relaxjs errors.\r\n * The handler receives the error and an `ErrorContext`.\r\n * Call `ctx.suppress()` to prevent the error from being thrown.\r\n * Only one handler can be active at a time; subsequent calls replace the previous handler.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * if (error.context.route === 'optional-panel') {\r\n * ctx.suppress();\r\n * return;\r\n * }\r\n * showErrorDialog(error.message);\r\n * });\r\n */\r\nexport function onError(fn: ErrorHandler) {\r\n handler = fn;\r\n}\r\n\r\n/**\r\n * Reports an error through the global handler.\r\n * Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.\r\n * The caller is responsible for throwing the returned error.\r\n *\r\n * @param message - Human-readable error description\r\n * @param context - Structured data for debugging (route, component, params, cause, etc.)\r\n * @returns The error to throw, or `null` if suppressed\r\n *\r\n * @example\r\n * const error = reportError('Failed to load route component', {\r\n * route: 'user',\r\n * componentTagName: 'user-profile',\r\n * routeData: { id: 123 },\r\n * });\r\n * if (error) throw error;\r\n */\r\nexport function reportError(message: string, context: Record<string, unknown>): RelaxError | null {\r\n const error = new RelaxError(message, context);\r\n if (handler) {\r\n let suppressed = false;\r\n const ctx: ErrorContext = {\r\n suppress() { suppressed = true; },\r\n };\r\n handler(error, ctx);\r\n if (suppressed) {\r\n return null;\r\n }\r\n }\r\n return error;\r\n}\r\n\r\n/**\r\n * Wraps an async function into a synchronous callback suitable for addEventListener.\r\n * Catches promise rejections and reports them through the global error handler.\r\n *\r\n * @param fn - Async function to wrap\r\n * @returns Synchronous function that can be passed to addEventListener\r\n *\r\n * @example\r\n * button.addEventListener('click', asyncHandler(async (e) => {\r\n * await saveData();\r\n * }));\r\n *\r\n * @example\r\n * form.addEventListener('submit', asyncHandler(async (e) => {\r\n * e.preventDefault();\r\n * await submitForm();\r\n * }));\r\n */\r\nexport function asyncHandler<TArgs extends unknown[]>(\r\n fn: (...args: TArgs) => Promise<void>,\r\n): (...args: TArgs) => void {\r\n return function (this: any, ...args: TArgs) {\r\n fn.call(this, ...args).catch((cause: unknown) => {\r\n const error = reportError('Async callback failed', { cause });\r\n if (error) throw error;\r\n });\r\n };\r\n}\r\n", "import { reportError } from './errors';\r\n\r\n/**\r\n * Generic constructor type used for dependency registration and injection.\r\n * Represents any class constructor that can be used with the DI container.\r\n *\r\n * @template T - The type of object the constructor creates\r\n *\r\n * @example\r\n * // Use with service registration\r\n * class UserService {}\r\n * const ctor: Constructor<UserService> = UserService;\r\n * serviceCollection.registerByType(ctor, { inject: [] });\r\n */\r\nexport type Constructor<T extends object = object> = new (...args: any[]) => T;\r\n\r\n/**\r\n * Controls how service instances are shared across the container hierarchy.\r\n * Used when registering services to define their lifetime behavior.\r\n *\r\n * - `global`: Single instance shared everywhere (singleton pattern)\r\n * - `closest`: New instance per container scope (scoped lifetime)\r\n *\r\n * @example\r\n * // Singleton service - same instance everywhere\r\n * serviceCollection.register(LoggerService, { scope: 'global', inject: [] });\r\n *\r\n * // Scoped service - new instance per scope\r\n * serviceCollection.register(RequestContext, { scope: 'closest', inject: [] });\r\n */\r\nexport type ServiceScope = 'global' | 'closest';\r\n\r\n/**\r\n * Configuration options for registering a service in the DI container.\r\n * Controls identification, lifetime, and dependency resolution.\r\n *\r\n * @example\r\n * // Register with constructor injection\r\n * const options: RegistrationOptions = {\r\n * scope: 'global',\r\n * inject: [DatabaseConnection, ConfigService]\r\n * };\r\n * serviceCollection.register(UserRepository, options);\r\n *\r\n * @example\r\n * // Register with property injection\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * properties: { logger: Logger, config: 'appConfig' }\r\n * };\r\n *\r\n * @example\r\n * // Register with a pre-created instance\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * instance: existingService\r\n * };\r\n */\r\nexport interface RegistrationOptions {\r\n /** Service lifetime - 'global' for singleton, 'closest' for scoped */\r\n scope?: ServiceScope;\r\n /** Optional string key for resolving by name instead of type */\r\n key?: string;\r\n /** Pre-existing instance to use instead of creating new one */\r\n instance?: unknown;\r\n /** Types or keys for constructor parameters, in order */\r\n inject: (string | Constructor)[];\r\n /** Map of property names to their injection types/keys */\r\n properties?: Record<string, string | Constructor>;\r\n}\r\n\r\n/**\r\n * Field decorator that injects a service from the global DI container.\r\n * The service is resolved when the class instance is created (not at class definition time),\r\n * so services must be registered before the first instance is created.\r\n *\r\n * Works with web components regardless of how they are created:\r\n * - By the browser (HTML parsing): services are resolved during construction\r\n * - By application code (`document.createElement` or `new`): same behavior\r\n * - Injected fields are available in `connectedCallback` and all lifecycle methods\r\n *\r\n * @example\r\n * // Using `@Inject` in a web component\r\n * class UserPanel extends HTMLElement {\r\n * @Inject(UserService)\r\n * private userService!: UserService;\r\n *\r\n * connectedCallback() {\r\n * // userService is already resolved and ready to use\r\n * const user = this.userService.getCurrentUser();\r\n * this.render(user);\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // Services must be registered before components are created.\r\n * // In your app entry point (e.g. main.ts):\r\n * serviceCollection.registerByType(UserService, { inject: [ApiClient] });\r\n * serviceCollection.registerByType(ApiClient, { inject: [] });\r\n *\r\n * // Now components can be created (by browser or code)\r\n * customElements.define('user-panel', UserPanel);\r\n */\r\nexport function Inject<T extends object>(typeOrKey: Constructor<T> | string) {\r\n return (_: undefined, context: ClassFieldDecoratorContext) => {\r\n return function(this: any) {\r\n return container.resolve(typeOrKey);\r\n };\r\n };\r\n}\r\n\r\n// Temporary collector of property injections - cleared after registration\r\n//const propertyCollector = new WeakMap<object, Record<string, string>>();\r\n\r\n/**\r\n * Class decorator that registers a service in the global DI container.\r\n * Registration happens at class definition time (when the module loads),\r\n * so import the module before creating instances that depend on this service.\r\n *\r\n * For web components: use `@ContainerService` on services, not on the\r\n * components themselves. Components use `@Inject` to consume services.\r\n *\r\n * @param options - Registration configuration including scope and dependencies\r\n *\r\n * @example\r\n * // Register a service that components can inject\r\n * @ContainerService({ inject: [ApiClient] })\r\n * class UserService {\r\n * constructor(private api: ApiClient) {}\r\n * getCurrentUser() { return this.api.get('/user'); }\r\n * }\r\n *\r\n * // Component consumes the service\r\n * class UserPanel extends HTMLElement {\r\n * @Inject(UserService)\r\n * private userService!: UserService;\r\n * }\r\n *\r\n * @example\r\n * // Service with custom key for named resolution\r\n * @ContainerService({ key: 'primaryCache', scope: 'global', inject: [] })\r\n * class CacheService {}\r\n *\r\n * // Later resolve by key\r\n * const cache = container.resolve('primaryCache');\r\n */\r\nexport function ContainerService<T extends object>(\r\n options?: RegistrationOptions\r\n) {\r\n return (target: Constructor<T>) => {\r\n const opts = options ?? {inject: []};\r\n\r\n if (opts.key) {\r\n serviceCollection.register(target, opts);\r\n } else {\r\n serviceCollection.registerByType(target, opts);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Internal class representing a registered service's metadata.\r\n * Holds all information needed to create and configure service instances.\r\n *\r\n * @internal This is an implementation detail and should not be used directly.\r\n */\r\nclass Registration {\r\n /**\r\n * Creates a new registration record.\r\n *\r\n * @param classConstructor - The class constructor function\r\n * @param scope - Instance sharing behavior\r\n * @param inject - Constructor parameter dependencies\r\n * @param properties - Property injection mappings\r\n * @param key - Optional string identifier\r\n * @param instance - Optional pre-created instance\r\n */\r\n constructor(\r\n public classConstructor: Constructor,\r\n public scope: ServiceScope,\r\n public inject: (string | Constructor)[],\r\n public properties: Record<string, string | Constructor> = {},\r\n public key?: string,\r\n public instance?: unknown\r\n ) {}\r\n}\r\n\r\n/**\r\n * Registry that stores service registration metadata.\r\n * Use this to register services before they can be resolved by a ServiceContainer.\r\n *\r\n * Typically you'll use the global `serviceCollection` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Register a service by type\r\n * serviceCollection.registerByType(LoggerService, { inject: [] });\r\n *\r\n * // Register with a string key\r\n * serviceCollection.register(CacheService, { key: 'cache', inject: [] });\r\n *\r\n * // Check if service is registered\r\n * const reg = serviceCollection.tryGet(LoggerService);\r\n * if (reg) {\r\n * console.log('Logger is registered');\r\n * }\r\n */\r\nexport class ServiceCollection {\r\n private servicesByKey = new Map<string, Registration>();\r\n private servicesByClassName = new Map<string, Registration>();\r\n\r\n /**\r\n * Registers a service with full configuration options.\r\n * The service will be resolvable by both its class name and optional key.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Registration configuration\r\n */\r\n register<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(\r\n constructor,\r\n options.scope ?? 'global',\r\n options.inject,\r\n options.properties ?? {},\r\n options.key,\r\n options.instance\r\n );\r\n\r\n if (options.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n /**\r\n * Registers a service by its class type.\r\n * The service will be resolvable by its class constructor.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Optional registration configuration\r\n */\r\n registerByType<T extends object>(\r\n constructor: Constructor<T>,\r\n options?: RegistrationOptions\r\n ): void {\r\n this.checkNameCollision(constructor);\r\n if (options) this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(constructor, options?.scope ?? 'global', options?.inject ?? [], options?.properties, options?.key, options?.instance);\r\n if (options?.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n private checkNameCollision<T extends object>(constructor: Constructor<T>): void {\r\n const existing = this.servicesByClassName.get(constructor.name);\r\n if (existing && existing.classConstructor !== constructor) {\r\n const error = reportError('Service name collision: different class registered with same name', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n private validateRegistration<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.checkNameCollision(constructor);\r\n\r\n if (options.key) {\r\n const existingByKey = this.servicesByKey.get(options.key);\r\n if (existingByKey && existingByKey.classConstructor !== constructor) {\r\n const error = reportError('Service key already registered to a different class', {\r\n key: options.key,\r\n existingClass: existingByKey.classConstructor.name,\r\n newClass: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n if (options.instance && options.inject.length > 0) {\r\n const error = reportError('Service has both instance and inject (inject will be ignored)', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Attempts to retrieve a service registration.\r\n * Returns undefined if the service is not registered.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration or undefined\r\n */\r\n tryGet<T extends object>(key: string | Constructor<T>): Registration | undefined {\r\n if (typeof key === 'string') {\r\n return this.servicesByKey.get(key);\r\n }\r\n return this.servicesByClassName.get(key.name);\r\n }\r\n\r\n /**\r\n * Retrieves a service registration or throws if not found.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration\r\n * @throws Error if the service is not registered\r\n */\r\n get<T extends object>(key: string | Constructor<T>): Registration {\r\n const reg = this.tryGet(key);\r\n if (!reg) {\r\n const service = typeof key === 'string' ? key : key.name;\r\n const error = reportError(`Failed to resolve service '${service}'`, {\r\n service,\r\n registeredTypes: Array.from(this.servicesByClassName.keys()),\r\n registeredKeys: Array.from(this.servicesByKey.keys()),\r\n });\r\n if (error) throw error;\r\n }\r\n return reg!;\r\n }\r\n}\r\n\r\n/**\r\n * Internal storage for tracking injected fields during service resolution.\r\n * @internal\r\n */\r\nconst injectedFields = new WeakMap<object, Map<string, string>>();\r\n\r\n/**\r\n * IoC container that resolves and manages service instances.\r\n * Creates instances based on registrations in a ServiceCollection,\r\n * handling constructor injection, property injection, and lifetime management.\r\n *\r\n * Typically you'll use the global `container` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Resolve a service by class\r\n * const logger = container.resolve(LoggerService);\r\n *\r\n * // Resolve by string key\r\n * const cache = container.resolve<CacheService>('primaryCache');\r\n *\r\n * @example\r\n * // Full setup workflow\r\n * serviceCollection.register(UserService, {\r\n * inject: [DatabaseConnection],\r\n * scope: 'global'\r\n * });\r\n *\r\n * const userService = container.resolve(UserService);\r\n */\r\nexport class ServiceContainer {\r\n private instances = new Map<string, any>();\r\n\r\n /**\r\n * Creates a new container backed by the given service collection.\r\n *\r\n * @param serviceCollection - The registry containing service registrations\r\n */\r\n constructor(private serviceCollection: ServiceCollection) {}\r\n\r\n /**\r\n * Resolves a service instance by class type or string key.\r\n * Creates the instance if not already cached (for global scope).\r\n * Handles constructor and property injection automatically.\r\n *\r\n * @param keyOrType - Either a string key or class constructor\r\n * @returns The resolved service instance\r\n * @throws Error if the service is not registered\r\n *\r\n * @example\r\n * const service = container.resolve(MyService);\r\n */\r\n resolve<T extends object>(keyOrType: string | Constructor<T>): T {\r\n const key = typeof keyOrType === 'string' ? keyOrType : keyOrType.name;\r\n\r\n if (this.instances.has(key)) {\r\n return this.instances.get(key);\r\n }\r\n\r\n const registration = this.serviceCollection.get(keyOrType);\r\n if (!registration) {\r\n const error = reportError(`Failed to resolve service '${key}'`, { service: key });\r\n if (error) throw error;\r\n return undefined as unknown as T;\r\n }\r\n\r\n if (registration.instance) {\r\n const inst = registration.instance as T;\r\n this.injectFields(inst, registration);\r\n this.instances.set(key, inst);\r\n return inst;\r\n }\r\n\r\n const instance = this.createInstance<T>(registration);\r\n if (registration.scope === 'global') {\r\n this.instances.set(key, instance);\r\n }\r\n this.injectFields(instance, registration);\r\n\r\n return instance;\r\n }\r\n\r\n /**\r\n * Creates a new instance of a service, resolving all constructor dependencies.\r\n */\r\n private createInstance<T extends object>(registration: Registration): T {\r\n const constructor = registration.classConstructor as Constructor<T>;\r\n\r\n const dependencies = registration.inject.map(dep => this.resolve(dep));\r\n return new constructor(...dependencies);\r\n }\r\n\r\n /**\r\n * Injects dependencies into instance properties based on registration config.\r\n */\r\n private injectFields<T extends object>(instance: T, registration: Registration): void {\r\n for (const [fieldName, keyOrType] of Object.entries(registration.properties)) {\r\n (instance as any)[fieldName] = this.resolve(keyOrType);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Global service collection instance for registering services.\r\n * Use this to register services that can later be resolved by the container.\r\n *\r\n * @example\r\n * import { serviceCollection } from 'relaxjs';\r\n *\r\n * serviceCollection.register(MyService, { inject: [Dependency] });\r\n */\r\nexport const serviceCollection = new ServiceCollection();\r\n\r\n/**\r\n * Global service container instance for resolving dependencies.\r\n * Use this to obtain service instances with all dependencies injected.\r\n *\r\n * @example\r\n * import { container } from 'relaxjs';\r\n *\r\n * const service = container.resolve(MyService);\r\n */\r\nexport const container = new ServiceContainer(serviceCollection);"],
5
+ "mappings": "AAiCO,IAAMA,EAAN,cAAyB,KAAM,CAClC,YACIC,EACOC,EACT,CACE,MAAMD,CAAO,EAFN,aAAAC,CAGX,CACJ,EAKIC,EAA+B,KAsC5B,SAASC,EAAYC,EAAiBC,EAAqD,CAC9F,IAAMC,EAAQ,IAAIC,EAAWH,EAASC,CAAO,EAC7C,GAAIG,EAAS,CACT,IAAIC,EAAa,GAKjB,GADAD,EAAQF,EAHkB,CACtB,UAAW,CAAEG,EAAa,EAAM,CACpC,CACkB,EACdA,EACA,OAAO,IAEf,CACA,OAAOH,CACX,CCOO,SAASI,EAAyBC,EAAoC,CACzE,MAAO,CAACC,EAAcC,IACX,UAAoB,CACvB,OAAOC,EAAU,QAAQH,CAAS,CACtC,CAER,CAqCO,SAASI,EACZC,EACF,CACE,OAAQC,GAA2B,CAC/B,IAAMC,EAAOF,GAAW,CAAC,OAAQ,CAAC,CAAC,EAE/BE,EAAK,IACLC,EAAkB,SAASF,EAAQC,CAAI,EAEvCC,EAAkB,eAAeF,EAAQC,CAAI,CAErD,CACJ,CAQA,IAAME,EAAN,KAAmB,CAWf,YACWC,EACAC,EACAC,EACAC,EAAmD,CAAC,EACpDC,EACAC,EACT,CANS,sBAAAL,EACA,WAAAC,EACA,YAAAC,EACA,gBAAAC,EACA,SAAAC,EACA,cAAAC,CACR,CACP,EAqBaC,EAAN,KAAwB,CAAxB,cACH,KAAQ,cAAgB,IAAI,IAC5B,KAAQ,oBAAsB,IAAI,IASlC,SAA2BC,EAA6BZ,EAAoC,CACxF,KAAK,qBAAqBY,EAAaZ,CAAO,EAE9C,IAAMa,EAAM,IAAIT,EACZQ,EACAZ,EAAQ,OAAS,SACjBA,EAAQ,OACRA,EAAQ,YAAc,CAAC,EACvBA,EAAQ,IACRA,EAAQ,QACZ,EAEIA,EAAQ,KACR,KAAK,cAAc,IAAIA,EAAQ,IAAKa,CAAG,EAE3C,KAAK,oBAAoB,IAAID,EAAY,KAAMC,CAAG,CACtD,CASA,eACID,EACAZ,EACI,CACJ,KAAK,mBAAmBY,CAAW,EAC/BZ,GAAS,KAAK,qBAAqBY,EAAaZ,CAAO,EAE3D,IAAMa,EAAM,IAAIT,EAAaQ,EAAaZ,GAAS,OAAS,SAAUA,GAAS,QAAU,CAAC,EAAGA,GAAS,WAAYA,GAAS,IAAKA,GAAS,QAAQ,EAC7IA,GAAS,KACT,KAAK,cAAc,IAAIA,EAAQ,IAAKa,CAAG,EAE3C,KAAK,oBAAoB,IAAID,EAAY,KAAMC,CAAG,CACtD,CAEQ,mBAAqCD,EAAmC,CAC5E,IAAME,EAAW,KAAK,oBAAoB,IAAIF,EAAY,IAAI,EAC9D,GAAIE,GAAYA,EAAS,mBAAqBF,EAAa,CACvD,IAAMG,EAAQC,EAAY,oEAAqE,CAC3F,QAASJ,EAAY,IACzB,CAAC,EACD,GAAIG,EAAO,MAAMA,CACrB,CACJ,CAEQ,qBAAuCH,EAA6BZ,EAAoC,CAG5G,GAFA,KAAK,mBAAmBY,CAAW,EAE/BZ,EAAQ,IAAK,CACb,IAAMiB,EAAgB,KAAK,cAAc,IAAIjB,EAAQ,GAAG,EACxD,GAAIiB,GAAiBA,EAAc,mBAAqBL,EAAa,CACjE,IAAMG,EAAQC,EAAY,sDAAuD,CAC7E,IAAKhB,EAAQ,IACb,cAAeiB,EAAc,iBAAiB,KAC9C,SAAUL,EAAY,IAC1B,CAAC,EACD,GAAIG,EAAO,MAAMA,CACrB,CACJ,CAEA,GAAIf,EAAQ,UAAYA,EAAQ,OAAO,OAAS,EAAG,CAC/C,IAAMe,EAAQC,EAAY,gEAAiE,CACvF,QAASJ,EAAY,IACzB,CAAC,EACD,GAAIG,EAAO,MAAMA,CACrB,CACJ,CASA,OAAyBN,EAAwD,CAC7E,OAAI,OAAOA,GAAQ,SACR,KAAK,cAAc,IAAIA,CAAG,EAE9B,KAAK,oBAAoB,IAAIA,EAAI,IAAI,CAChD,CASA,IAAsBA,EAA4C,CAC9D,IAAMI,EAAM,KAAK,OAAOJ,CAAG,EAC3B,GAAI,CAACI,EAAK,CACN,IAAMK,EAAU,OAAOT,GAAQ,SAAWA,EAAMA,EAAI,KAC9CM,EAAQC,EAAY,8BAA8BE,CAAO,IAAK,CAChE,QAAAA,EACA,gBAAiB,MAAM,KAAK,KAAK,oBAAoB,KAAK,CAAC,EAC3D,eAAgB,MAAM,KAAK,KAAK,cAAc,KAAK,CAAC,CACxD,CAAC,EACD,GAAIH,EAAO,MAAMA,CACrB,CACA,OAAOF,CACX,CACJ,EA+BO,IAAMM,EAAN,KAAuB,CAQ1B,YAAoBC,EAAsC,CAAtC,uBAAAA,EAPpB,KAAQ,UAAY,IAAI,GAOmC,CAc3D,QAA0BC,EAAuC,CAC7D,IAAMC,EAAM,OAAOD,GAAc,SAAWA,EAAYA,EAAU,KAElE,GAAI,KAAK,UAAU,IAAIC,CAAG,EACtB,OAAO,KAAK,UAAU,IAAIA,CAAG,EAGjC,IAAMC,EAAe,KAAK,kBAAkB,IAAIF,CAAS,EACzD,GAAI,CAACE,EAAc,CACf,IAAMC,EAAQC,EAAY,8BAA8BH,CAAG,IAAK,CAAE,QAASA,CAAI,CAAC,EAChF,GAAIE,EAAO,MAAMA,EACjB,MACJ,CAEA,GAAID,EAAa,SAAU,CACvB,IAAMG,EAAOH,EAAa,SAC1B,YAAK,aAAaG,EAAMH,CAAY,EACpC,KAAK,UAAU,IAAID,EAAKI,CAAI,EACrBA,CACX,CAEA,IAAMC,EAAW,KAAK,eAAkBJ,CAAY,EACpD,OAAIA,EAAa,QAAU,UACvB,KAAK,UAAU,IAAID,EAAKK,CAAQ,EAEpC,KAAK,aAAaA,EAAUJ,CAAY,EAEjCI,CACX,CAKQ,eAAiCJ,EAA+B,CACpE,IAAMK,EAAcL,EAAa,iBAE3BM,EAAeN,EAAa,OAAO,IAAIO,GAAO,KAAK,QAAQA,CAAG,CAAC,EACrE,OAAO,IAAIF,EAAY,GAAGC,CAAY,CAC1C,CAKQ,aAA+BF,EAAaJ,EAAkC,CAClF,OAAW,CAACQ,EAAWV,CAAS,IAAK,OAAO,QAAQE,EAAa,UAAU,EACtEI,EAAiBI,CAAS,EAAI,KAAK,QAAQV,CAAS,CAE7D,CACJ,EAWaD,EAAoB,IAAIY,EAWxBC,EAAY,IAAId,EAAiBC,CAAiB",
6
6
  "names": ["RelaxError", "message", "context", "handler", "reportError", "message", "context", "error", "RelaxError", "handler", "suppressed", "Inject", "typeOrKey", "_", "context", "container", "ContainerService", "options", "target", "opts", "serviceCollection", "Registration", "classConstructor", "scope", "inject", "properties", "key", "instance", "ServiceCollection", "constructor", "reg", "existing", "error", "reportError", "existingByKey", "service", "ServiceContainer", "serviceCollection", "keyOrType", "key", "registration", "error", "reportError", "inst", "instance", "constructor", "dependencies", "dep", "fieldName", "ServiceCollection", "container"]
7
7
  }
@@ -1,2 +1,2 @@
1
- var i=Object.defineProperty;var s=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var f=(t,n)=>{for(var r in n)i(t,r,{get:n[r],enumerable:!0})},E=(t,n,r,e)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of u(n))!c.call(t,o)&&o!==r&&i(t,o,{get:()=>n[o],enumerable:!(e=s(n,o))||e.enumerable});return t};var T=t=>E(i({},"__esModule",{value:!0}),t);var d={};f(d,{formError:()=>m,getParentComponent:()=>a,selectOne:()=>l});module.exports=T(d);function l(t,n){let r=n??document,e;if(t.startsWith("#")){let o=t.slice(1);e=r.querySelector(`#${CSS.escape(o)}`)??r.querySelector(`[name="${o}"]`)}else e=r.querySelector(t);if(!e)throw new Error(`No element found matching '${t}'`);return e}function m(t,n,r){let e=l(t,r);if(e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement||e instanceof HTMLButtonElement){e.setCustomValidity(n),e.reportValidity();return}if(e.constructor.formAssociated===!0&&"setCustomValidity"in e){e.setCustomValidity(n),e.reportValidity();return}throw new Error(`Element matching '${t}' is not a form field`)}function a(t,n){let r=t.parentElement;for(;r;){if(r instanceof n)return r;r=r.parentElement}return null}
1
+ "use strict";var i=Object.defineProperty;var s=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var f=(t,n)=>{for(var r in n)i(t,r,{get:n[r],enumerable:!0})},E=(t,n,r,e)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of u(n))!c.call(t,o)&&o!==r&&i(t,o,{get:()=>n[o],enumerable:!(e=s(n,o))||e.enumerable});return t};var T=t=>E(i({},"__esModule",{value:!0}),t);var d={};f(d,{formError:()=>m,getParentComponent:()=>a,selectOne:()=>l});module.exports=T(d);function l(t,n){let r=n??document,e;if(t.startsWith("#")){let o=t.slice(1);e=r.querySelector(`#${CSS.escape(o)}`)??r.querySelector(`[name="${o}"]`)}else e=r.querySelector(t);if(!e)throw new Error(`No element found matching '${t}'`);return e}function m(t,n,r){let e=l(t,r);if(e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement||e instanceof HTMLButtonElement){e.setCustomValidity(n),e.reportValidity();return}if(e.constructor.formAssociated===!0&&"setCustomValidity"in e){e.setCustomValidity(n),e.reportValidity();return}throw new Error(`Element matching '${t}' is not a form field`)}function a(t,n){let r=t.parentElement;for(;r;){if(r instanceof n)return r;r=r.parentElement}return null}
2
2
  //# sourceMappingURL=index.js.map
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/elements/index.ts", "../../src/elements/dom.ts", "../../src/getParentComponent.ts"],
4
4
  "sourcesContent": ["export { selectOne, formError } from './dom';\r\nexport { getParentComponent } from '../getParentComponent';\r\n", "/**\r\n * Finds exactly one element matching the selector. When the selector starts\r\n * with `#`, both `id` and `name` attributes are tried.\r\n *\r\n * @example\r\n * const input = selectOne<HTMLInputElement>('#email');\r\n * const btn = selectOne<HTMLButtonElement>('.submit', form);\r\n */\r\nexport function selectOne<T extends Element = HTMLElement>(\r\n selector: string,\r\n parent?: Element | Document,\r\n): T {\r\n const root = parent ?? document;\r\n\r\n let el: Element | null;\r\n if (selector.startsWith('#')) {\r\n const name = selector.slice(1);\r\n el = root.querySelector(`#${CSS.escape(name)}`)\r\n ?? root.querySelector(`[name=\"${name}\"]`);\r\n } else {\r\n el = root.querySelector(selector);\r\n }\r\n\r\n if (!el) {\r\n throw new Error(`No element found matching '${selector}'`);\r\n }\r\n\r\n return el as T;\r\n}\r\n\r\n/**\r\n * Sets a validation error on a form field found by selector. Supports native\r\n * form elements and form-associated custom elements using `ElementInternals`.\r\n *\r\n * @example\r\n * formError('#email', 'Please enter a valid email');\r\n * formError('#email', ''); // clears the error\r\n */\r\nexport function formError(\r\n selector: string,\r\n message: string,\r\n parent?: Element | Document,\r\n): void {\r\n const el = selectOne<HTMLElement>(selector, parent);\r\n\r\n if (\r\n el instanceof HTMLInputElement\r\n || el instanceof HTMLSelectElement\r\n || el instanceof HTMLTextAreaElement\r\n || el instanceof HTMLButtonElement\r\n ) {\r\n el.setCustomValidity(message);\r\n el.reportValidity();\r\n return;\r\n }\r\n\r\n if (\r\n (el.constructor as any).formAssociated === true\r\n && 'setCustomValidity' in el\r\n ) {\r\n (el as any).setCustomValidity(message);\r\n (el as any).reportValidity();\r\n return;\r\n }\r\n\r\n throw new Error(\r\n `Element matching '${selector}' is not a form field`,\r\n );\r\n}\r\n", "/**\r\n * Finds the closest parent element of a specific Web Component type.\r\n * Traverses up the DOM tree looking for an ancestor matching the constructor.\r\n *\r\n * Useful for child components that need to communicate with or access\r\n * their parent container component, common in composite component patterns.\r\n *\r\n * @template T - The type of HTMLElement to find\r\n * @param node - The starting node to search from\r\n * @param constructor - The class constructor of the desired element type\r\n * @returns The matching parent element or null if not found\r\n *\r\n * @example\r\n * // Inside a child component, find the parent container\r\n * class ListItem extends HTMLElement {\r\n * connectedCallback() {\r\n * const list = getParentComponent(this, ListContainer);\r\n * if (list) {\r\n * list.registerItem(this);\r\n * }\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // Access parent component's methods\r\n * class TabPanel extends HTMLElement {\r\n * activate() {\r\n * const tabs = getParentComponent(this, TabContainer);\r\n * tabs?.selectPanel(this);\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // Handle case where parent might not exist\r\n * const form = getParentComponent(input, FormContainer);\r\n * if (!form) {\r\n * console.warn('Input must be inside a FormContainer');\r\n * return;\r\n * }\r\n */\r\nexport function getParentComponent<T extends HTMLElement>(\r\n node: Node,\r\n constructor: { new (...args: any[]): T }\r\n): T | null {\r\n let current = node.parentElement;\r\n\r\n while (current) {\r\n if (current instanceof constructor) {\r\n return current;\r\n }\r\n current = current.parentElement;\r\n }\r\n\r\n return null;\r\n} "],
5
- "mappings": "4ZAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,EAAA,uBAAAC,EAAA,cAAAC,IAAA,eAAAC,EAAAL,GCQO,SAASM,EACZC,EACAC,EACC,CACD,IAAMC,EAAOD,GAAU,SAEnBE,EACJ,GAAIH,EAAS,WAAW,GAAG,EAAG,CAC1B,IAAMI,EAAOJ,EAAS,MAAM,CAAC,EAC7BG,EAAKD,EAAK,cAAc,IAAI,IAAI,OAAOE,CAAI,CAAC,EAAE,GACvCF,EAAK,cAAc,UAAUE,CAAI,IAAI,CAChD,MACID,EAAKD,EAAK,cAAcF,CAAQ,EAGpC,GAAI,CAACG,EACD,MAAM,IAAI,MAAM,8BAA8BH,CAAQ,GAAG,EAG7D,OAAOG,CACX,CAUO,SAASE,EACZL,EACAM,EACAL,EACI,CACJ,IAAME,EAAKJ,EAAuBC,EAAUC,CAAM,EAElD,GACIE,aAAc,kBACXA,aAAc,mBACdA,aAAc,qBACdA,aAAc,kBACnB,CACEA,EAAG,kBAAkBG,CAAO,EAC5BH,EAAG,eAAe,EAClB,MACJ,CAEA,GACKA,EAAG,YAAoB,iBAAmB,IACxC,sBAAuBA,EAC5B,CACGA,EAAW,kBAAkBG,CAAO,EACpCH,EAAW,eAAe,EAC3B,MACJ,CAEA,MAAM,IAAI,MACN,qBAAqBH,CAAQ,uBACjC,CACJ,CC5BO,SAASO,EACZC,EACAC,EACQ,CACR,IAAIC,EAAUF,EAAK,cAEnB,KAAOE,GAAS,CACZ,GAAIA,aAAmBD,EACnB,OAAOC,EAEXA,EAAUA,EAAQ,aACtB,CAEA,OAAO,IACX",
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,EAAA,uBAAAC,EAAA,cAAAC,IAAA,eAAAC,EAAAL,GCQO,SAASM,EACZC,EACAC,EACC,CACD,IAAMC,EAAOD,GAAU,SAEnBE,EACJ,GAAIH,EAAS,WAAW,GAAG,EAAG,CAC1B,IAAMI,EAAOJ,EAAS,MAAM,CAAC,EAC7BG,EAAKD,EAAK,cAAc,IAAI,IAAI,OAAOE,CAAI,CAAC,EAAE,GACvCF,EAAK,cAAc,UAAUE,CAAI,IAAI,CAChD,MACID,EAAKD,EAAK,cAAcF,CAAQ,EAGpC,GAAI,CAACG,EACD,MAAM,IAAI,MAAM,8BAA8BH,CAAQ,GAAG,EAG7D,OAAOG,CACX,CAUO,SAASE,EACZL,EACAM,EACAL,EACI,CACJ,IAAME,EAAKJ,EAAuBC,EAAUC,CAAM,EAElD,GACIE,aAAc,kBACXA,aAAc,mBACdA,aAAc,qBACdA,aAAc,kBACnB,CACEA,EAAG,kBAAkBG,CAAO,EAC5BH,EAAG,eAAe,EAClB,MACJ,CAEA,GACKA,EAAG,YAAoB,iBAAmB,IACxC,sBAAuBA,EAC5B,CACGA,EAAW,kBAAkBG,CAAO,EACpCH,EAAW,eAAe,EAC3B,MACJ,CAEA,MAAM,IAAI,MACN,qBAAqBH,CAAQ,uBACjC,CACJ,CC5BO,SAASO,EACZC,EACAC,EACQ,CACR,IAAIC,EAAUF,EAAK,cAEnB,KAAOE,GAAS,CACZ,GAAIA,aAAmBD,EACnB,OAAOC,EAEXA,EAAUA,EAAQ,aACtB,CAEA,OAAO,IACX",
6
6
  "names": ["index_exports", "__export", "formError", "getParentComponent", "selectOne", "__toCommonJS", "selectOne", "selector", "parent", "root", "el", "name", "formError", "message", "getParentComponent", "node", "constructor", "current"]
7
7
  }
@@ -47,8 +47,8 @@ export interface ValidatorOptions {
47
47
  export declare class FormValidator {
48
48
  private form;
49
49
  private options?;
50
- private errorSummary;
51
- constructor(form: HTMLFormElement, options?: ValidatorOptions);
50
+ private errorSummary?;
51
+ constructor(form: HTMLFormElement, options?: ValidatorOptions | undefined);
52
52
  /**
53
53
  * Validates all form fields.
54
54
  * Uses native HTML5 validation and optionally displays an error summary.
@@ -38,9 +38,7 @@ interface Validator {
38
38
  }
39
39
  /** @internal */
40
40
  interface ValidatorRegistryEntry {
41
- validator: {
42
- new (): Validator;
43
- };
41
+ validator: new (...args: any[]) => Validator;
44
42
  validInputTypes: string[];
45
43
  }
46
44
  /**
@@ -59,9 +57,7 @@ interface ValidatorRegistryEntry {
59
57
  * }
60
58
  * }
61
59
  */
62
- export declare function RegisterValidator(validationName: string, validInputTypes?: string[]): (target: {
63
- new (...args: unknown[]): Validator;
64
- }) => void;
60
+ export declare function RegisterValidator(validationName: string, validInputTypes?: string[]): (target: new (...args: any[]) => Validator) => void;
65
61
  /**
66
62
  * Looks up a registered validator by name.
67
63
  *