@relax.js/core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +188 -0
  3. package/dist/DataLoader.d.ts +51 -0
  4. package/dist/DependencyInjection.d.ts +271 -0
  5. package/dist/DependencyInjectionOld.d.ts +35 -0
  6. package/dist/Metadata.d.ts +8 -0
  7. package/dist/SequentialId.d.ts +47 -0
  8. package/dist/_alt/src/MustardEngine.d.ts +30 -0
  9. package/dist/_alt/src/MustardParser.d.ts +63 -0
  10. package/dist/_alt/src/MustardParser2.d.ts +35 -0
  11. package/dist/_alt/src/pipes.d.ts +93 -0
  12. package/dist/_alt/src/template.d.ts +166 -0
  13. package/dist/_alt/src/tools.d.ts +4 -0
  14. package/dist/_alt/tests/pipes.tests.d.ts +1 -0
  15. package/dist/_alt/tests/template.tests.d.ts +1 -0
  16. package/dist/_alt/vitest.config.d.ts +2 -0
  17. package/dist/collections/Index.d.ts +1 -0
  18. package/dist/collections/LinkedList.d.ts +75 -0
  19. package/dist/collections/Pager.d.ts +15 -0
  20. package/dist/collections/index.js +2 -0
  21. package/dist/collections/index.js.map +7 -0
  22. package/dist/collections/index.mjs +2 -0
  23. package/dist/collections/index.mjs.map +7 -0
  24. package/dist/components/Table.d.ts +13 -0
  25. package/dist/components/index.d.ts +4 -0
  26. package/dist/components/index.js +128 -0
  27. package/dist/components/index.js.map +7 -0
  28. package/dist/components/index.mjs +128 -0
  29. package/dist/components/index.mjs.map +7 -0
  30. package/dist/components/lists/Table.d.ts +59 -0
  31. package/dist/components/lists/TreeView.d.ts +67 -0
  32. package/dist/components/lists/index.d.ts +2 -0
  33. package/dist/components/loader.d.ts +60 -0
  34. package/dist/components/menus/MenuItem.d.ts +30 -0
  35. package/dist/components/menus/TopMenu.d.ts +16 -0
  36. package/dist/components/menus/index.d.ts +2 -0
  37. package/dist/components/panels/tabs.d.ts +15 -0
  38. package/dist/di/index.d.ts +1 -0
  39. package/dist/di/index.js +2 -0
  40. package/dist/di/index.js.map +7 -0
  41. package/dist/di/index.mjs +2 -0
  42. package/dist/di/index.mjs.map +7 -0
  43. package/dist/elements/CopyAttributes.d.ts +2 -0
  44. package/dist/elements/dom.d.ts +18 -0
  45. package/dist/elements/index.d.ts +2 -0
  46. package/dist/elements/index.js +2 -0
  47. package/dist/elements/index.js.map +7 -0
  48. package/dist/elements/index.mjs +2 -0
  49. package/dist/elements/index.mjs.map +7 -0
  50. package/dist/errors.d.ts +71 -0
  51. package/dist/forms/FormReader.d.ts +182 -0
  52. package/dist/forms/FormValidator.d.ts +114 -0
  53. package/dist/forms/ValidationRules.d.ts +103 -0
  54. package/dist/forms/index.d.ts +4 -0
  55. package/dist/forms/index.js +2 -0
  56. package/dist/forms/index.js.map +7 -0
  57. package/dist/forms/index.mjs +2 -0
  58. package/dist/forms/index.mjs.map +7 -0
  59. package/dist/forms/setFormData.d.ts +49 -0
  60. package/dist/getParentComponent.d.ts +43 -0
  61. package/dist/html/TableRenderer.d.ts +44 -0
  62. package/dist/html/TreeBinder.d.ts +9 -0
  63. package/dist/html/html.d.ts +55 -0
  64. package/dist/html/index.d.ts +5 -0
  65. package/dist/html/index.js +2 -0
  66. package/dist/html/index.js.map +7 -0
  67. package/dist/html/index.mjs +2 -0
  68. package/dist/html/index.mjs.map +7 -0
  69. package/dist/html/template.d.ts +167 -0
  70. package/dist/http/ServerSentEvents.d.ts +116 -0
  71. package/dist/http/SimpleWebSocket.d.ts +153 -0
  72. package/dist/http/http.d.ts +177 -0
  73. package/dist/http/index.d.ts +3 -0
  74. package/dist/http/index.js +2 -0
  75. package/dist/http/index.js.map +7 -0
  76. package/dist/http/index.mjs +2 -0
  77. package/dist/http/index.mjs.map +7 -0
  78. package/dist/i18n/i18n.d.ts +105 -0
  79. package/dist/i18n/icu.d.ts +64 -0
  80. package/dist/i18n/index.d.ts +2 -0
  81. package/dist/i18n/index.js +2 -0
  82. package/dist/i18n/index.js.map +7 -0
  83. package/dist/i18n/index.mjs +2 -0
  84. package/dist/i18n/index.mjs.map +7 -0
  85. package/dist/index.d.ts +16 -0
  86. package/dist/index.js +5 -0
  87. package/dist/index.js.map +7 -0
  88. package/dist/index.mjs +5 -0
  89. package/dist/index.mjs.map +7 -0
  90. package/dist/lib/DataLoader.d.ts +51 -0
  91. package/dist/lib/DependencyInjection.d.ts +271 -0
  92. package/dist/lib/InvokeParent.d.ts +10 -0
  93. package/dist/lib/Pipes.d.ts +236 -0
  94. package/dist/lib/SequentialId.d.ts +47 -0
  95. package/dist/lib/collections/Index.d.ts +1 -0
  96. package/dist/lib/collections/LinkedList.d.ts +75 -0
  97. package/dist/lib/collections/Pager.d.ts +15 -0
  98. package/dist/lib/collections/TableRenderer.d.ts +44 -0
  99. package/dist/lib/di/index.d.ts +1 -0
  100. package/dist/lib/elements/CopyAttributes.d.ts +2 -0
  101. package/dist/lib/elements/dom.d.ts +18 -0
  102. package/dist/lib/elements/index.d.ts +2 -0
  103. package/dist/lib/errors.d.ts +71 -0
  104. package/dist/lib/forms/FormReader.d.ts +182 -0
  105. package/dist/lib/forms/FormValidator.d.ts +114 -0
  106. package/dist/lib/forms/ValidationRules.d.ts +103 -0
  107. package/dist/lib/forms/index.d.ts +4 -0
  108. package/dist/lib/forms/setFormData.d.ts +49 -0
  109. package/dist/lib/getParentComponent.d.ts +43 -0
  110. package/dist/lib/html/TableRenderer.d.ts +44 -0
  111. package/dist/lib/html/TreeBinder.d.ts +9 -0
  112. package/dist/lib/html/html.d.ts +55 -0
  113. package/dist/lib/html/html2.d.ts +55 -0
  114. package/dist/lib/html/index.d.ts +5 -0
  115. package/dist/lib/html/m.d.ts +167 -0
  116. package/dist/lib/html/m2.d.ts +8 -0
  117. package/dist/lib/html/m3.d.ts +0 -0
  118. package/dist/lib/html/template.d.ts +167 -0
  119. package/dist/lib/http/HttpClient.d.ts +153 -0
  120. package/dist/lib/http/ServerSentEvents.d.ts +116 -0
  121. package/dist/lib/http/SimpleWebSocket.d.ts +153 -0
  122. package/dist/lib/http/http.d.ts +177 -0
  123. package/dist/lib/http/index.d.ts +3 -0
  124. package/dist/lib/i18n/i18n.d.ts +105 -0
  125. package/dist/lib/i18n/icu.d.ts +64 -0
  126. package/dist/lib/i18n/index.d.ts +2 -0
  127. package/dist/lib/index.d.ts +16 -0
  128. package/dist/lib/routing/NavigateRouteEvent.d.ts +52 -0
  129. package/dist/lib/routing/RouteLink.d.ts +7 -0
  130. package/dist/lib/routing/Routing.d.ts +270 -0
  131. package/dist/lib/routing/RoutingTarget.d.ts +22 -0
  132. package/dist/lib/routing/index.d.ts +7 -0
  133. package/dist/lib/routing/navigation.d.ts +70 -0
  134. package/dist/lib/routing/routeMatching.d.ts +21 -0
  135. package/dist/lib/routing/routeTargetRegistry.d.ts +23 -0
  136. package/dist/lib/routing/types.d.ts +130 -0
  137. package/dist/lib/templates/NodeTemplate.d.ts +38 -0
  138. package/dist/lib/templates/accessorParser.d.ts +87 -0
  139. package/dist/lib/templates/parseTemplate.d.ts +6 -0
  140. package/dist/lib/templates/tokenizer.d.ts +76 -0
  141. package/dist/lib/tools.d.ts +30 -0
  142. package/dist/lib/utils/index.d.ts +4 -0
  143. package/dist/pipes.d.ts +236 -0
  144. package/dist/routing/NavigateRouteEvent.d.ts +52 -0
  145. package/dist/routing/RouteLink.d.ts +7 -0
  146. package/dist/routing/RoutingTarget.d.ts +22 -0
  147. package/dist/routing/index.d.ts +7 -0
  148. package/dist/routing/index.js +5 -0
  149. package/dist/routing/index.js.map +7 -0
  150. package/dist/routing/index.mjs +5 -0
  151. package/dist/routing/index.mjs.map +7 -0
  152. package/dist/routing/navigation.d.ts +70 -0
  153. package/dist/routing/routeMatching.d.ts +21 -0
  154. package/dist/routing/routeTargetRegistry.d.ts +23 -0
  155. package/dist/routing/types.d.ts +130 -0
  156. package/dist/templates/NodeTemplate.d.ts +38 -0
  157. package/dist/templates/accessorParser.d.ts +87 -0
  158. package/dist/templates/parseTemplate.d.ts +6 -0
  159. package/dist/templates/tokenizer.d.ts +76 -0
  160. package/dist/tools.d.ts +30 -0
  161. package/dist/utils/index.d.ts +4 -0
  162. package/dist/utils/index.js +2 -0
  163. package/dist/utils/index.js.map +7 -0
  164. package/dist/utils/index.mjs +2 -0
  165. package/dist/utils/index.mjs.map +7 -0
  166. package/docs/Architecture.md +333 -0
  167. package/docs/DependencyInjection.md +237 -0
  168. package/docs/Errors.md +87 -0
  169. package/docs/GettingStarted.md +231 -0
  170. package/docs/Pipes.md +211 -0
  171. package/docs/Translations.md +312 -0
  172. package/docs/WhyRelaxjs.md +336 -0
  173. package/docs/elements/dom.md +102 -0
  174. package/docs/forms/creating-form-components.md +924 -0
  175. package/docs/forms/form-api.md +94 -0
  176. package/docs/forms/forms.md +99 -0
  177. package/docs/forms/patterns.md +311 -0
  178. package/docs/forms/reading-writing.md +365 -0
  179. package/docs/forms/validation.md +351 -0
  180. package/docs/html/TableRenderer.md +292 -0
  181. package/docs/html/html.md +175 -0
  182. package/docs/html/index.md +54 -0
  183. package/docs/html/template.md +422 -0
  184. package/docs/http/HttpClient.md +459 -0
  185. package/docs/http/ServerSentEvents.md +184 -0
  186. package/docs/http/index.md +109 -0
  187. package/docs/i18n/i18n.md +309 -0
  188. package/docs/i18n/intl-standard.md +178 -0
  189. package/docs/routing/RouteLink.md +98 -0
  190. package/docs/routing/Routing.md +332 -0
  191. package/docs/routing/RoutingTarget.md +136 -0
  192. package/docs/routing/layouts.md +207 -0
  193. package/docs/utilities.md +143 -0
  194. package/package.json +93 -0
@@ -0,0 +1,44 @@
1
+ export declare class TableRenderer {
2
+ private table;
3
+ private template;
4
+ private component;
5
+ private dataMap;
6
+ private rowMap;
7
+ IdColumn: string;
8
+ constructor(table: HTMLTableElement, template: HTMLTemplateElement, idColumn: string, component: HTMLElement);
9
+ render(data: Record<string, any>[]): void;
10
+ private clearRows;
11
+ private renderRow;
12
+ private populateRow;
13
+ private attachEventHandlers;
14
+ update(data: Record<string, any>): void;
15
+ }
16
+ export declare class SortChangeEvent extends CustomEvent<SortColumn[]> {
17
+ constructor(sortColumns: SortColumn[]);
18
+ }
19
+ type SortDirection = 'asc' | 'desc';
20
+ export type SortColumn = {
21
+ column: string;
22
+ direction: SortDirection;
23
+ };
24
+ export declare class TableSorter {
25
+ private table;
26
+ private sortColumns;
27
+ private component;
28
+ constructor(table: HTMLTableElement, component: HTMLElement);
29
+ private setupListeners;
30
+ private toggle;
31
+ private emit;
32
+ private updateSortIndicators;
33
+ getSortColumns(): SortColumn[];
34
+ clear(): void;
35
+ }
36
+ declare global {
37
+ interface HTMLTableElementEventMap extends HTMLElementEventMap {
38
+ 'sortchange': SortChangeEvent;
39
+ }
40
+ interface HTMLTableElement {
41
+ addEventListener<K extends keyof HTMLTableElementEventMap>(type: K, listener: (this: HTMLTableElement, ev: HTMLTableElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
42
+ }
43
+ }
44
+ export {};
@@ -0,0 +1,9 @@
1
+ export declare class Template {
2
+ private readonly template;
3
+ private readonly bindings;
4
+ constructor(html: string);
5
+ render(data: Record<string, any>): HTMLElement;
6
+ private collectBindings;
7
+ private getNodeAtPath;
8
+ private resolveVariable;
9
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @module html
3
+ * HTML template engine with update capabilities.
4
+ * Creates templates that can be re-rendered with new data without recreating DOM nodes.
5
+ */
6
+ /**
7
+ * Result of rendering a template.
8
+ * Provides the DOM fragment and an update function for re-rendering.
9
+ */
10
+ export interface RenderTemplate {
11
+ /** The rendered DOM fragment */
12
+ fragment: DocumentFragment;
13
+ /** Updates the DOM with new data without recreating elements */
14
+ update(context: any): void;
15
+ }
16
+ /**
17
+ * Creates an updateable HTML template using tagged template literals.
18
+ * Returns an object with the fragment and an update method for efficient re-rendering.
19
+ *
20
+ * Supports:
21
+ * - Template literal substitutions (`${}`)
22
+ * - Mustache-style bindings (`{{property}}`)
23
+ * - Pipe transformations (`{{value|uppercase}}`)
24
+ * - Event handler binding
25
+ *
26
+ * @param templateStrings - The static parts of the template literal
27
+ * @param substitutions - The dynamic values interpolated into the template
28
+ * @returns A function that takes context and returns a RenderTemplate
29
+ *
30
+ * @example
31
+ * // Create and render a template
32
+ * const template = html`
33
+ * <div class="user">
34
+ * <h2>{{name}}</h2>
35
+ * <p>{{email}}</p>
36
+ * <span>{{createdAt|daysAgo}}</span>
37
+ * </div>
38
+ * `;
39
+ *
40
+ * const result = template({ name: 'John', email: 'john@example.com', createdAt: new Date() });
41
+ * container.appendChild(result.fragment);
42
+ *
43
+ * // Later, update with new data
44
+ * result.update({ name: 'Jane', email: 'jane@example.com', createdAt: new Date() });
45
+ *
46
+ * @example
47
+ * // With event handlers
48
+ * const row = html`
49
+ * <tr>
50
+ * <td>{{name}}</td>
51
+ * <td><button onclick=${function() { this.edit(this.id) }}>Edit</button></td>
52
+ * </tr>
53
+ * `;
54
+ */
55
+ export declare function html(templateStrings: TemplateStringsArray, ...substitutions: any[]): (context: any) => RenderTemplate;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @module html2
3
+ * Enhanced HTML template engine with update capabilities.
4
+ * Creates templates that can be re-rendered with new data without recreating DOM nodes.
5
+ */
6
+ /**
7
+ * Result of rendering a template.
8
+ * Provides the DOM fragment and an update function for re-rendering.
9
+ */
10
+ export interface RenderTemplate {
11
+ /** The rendered DOM fragment */
12
+ fragment: DocumentFragment;
13
+ /** Updates the DOM with new data without recreating elements */
14
+ update(context: any): void;
15
+ }
16
+ /**
17
+ * Creates an updateable HTML template using tagged template literals.
18
+ * Unlike `html`, this returns an object with an update method for efficient re-rendering.
19
+ *
20
+ * Supports:
21
+ * - Template literal substitutions (`${}`)
22
+ * - Mustache-style bindings (`{{property}}`)
23
+ * - Pipe transformations (`{{value|uppercase}}`)
24
+ * - Event handler binding
25
+ *
26
+ * @param templateStrings - The static parts of the template literal
27
+ * @param substitutions - The dynamic values interpolated into the template
28
+ * @returns A function that takes context and returns a RenderTemplate
29
+ *
30
+ * @example
31
+ * // Create and render a template
32
+ * const template = html2`
33
+ * <div class="user">
34
+ * <h2>{{name}}</h2>
35
+ * <p>{{email}}</p>
36
+ * <span>{{createdAt|daysAgo}}</span>
37
+ * </div>
38
+ * `;
39
+ *
40
+ * const result = template({ name: 'John', email: 'john@example.com', createdAt: new Date() });
41
+ * container.appendChild(result.fragment);
42
+ *
43
+ * // Later, update with new data
44
+ * result.update({ name: 'Jane', email: 'jane@example.com', createdAt: new Date() });
45
+ *
46
+ * @example
47
+ * // With event handlers
48
+ * const row = html2`
49
+ * <tr>
50
+ * <td>{{name}}</td>
51
+ * <td><button onclick=${function() { this.edit(this.id) }}>Edit</button></td>
52
+ * </tr>
53
+ * `;
54
+ */
55
+ export declare function html2(templateStrings: TemplateStringsArray, ...substitutions: any[]): (context: any) => RenderTemplate;
@@ -0,0 +1,5 @@
1
+ export { html, RenderTemplate } from './html';
2
+ export { compileTemplate, EngineConfig, CompiledTemplate } from './template';
3
+ export * from '../templates/NodeTemplate';
4
+ export { TableRenderer, TableSorter, SortChangeEvent } from './TableRenderer';
5
+ export type { SortColumn } from './TableRenderer';
@@ -0,0 +1,167 @@
1
+ /**
2
+ * @module m
3
+ * DOM-based template engine with reactive rendering capabilities.
4
+ *
5
+ * Compiles HTML templates with mustache-style expressions into efficient
6
+ * render functions that update the DOM when data changes.
7
+ *
8
+ * **Features:**
9
+ * - Text interpolation: `{{name}}`, `{{user.profile.email}}`
10
+ * - Attribute binding: `<div class="{{className}}">`
11
+ * - Pipes: `{{price | currency}}`, `{{name | uppercase | truncate:20}}`
12
+ * - Function calls: `{{formatDate(createdAt)}}`, `{{add(5, 3)}}`
13
+ * - Array indexing: `{{items[0]}}`, `{{users[1].name}}`
14
+ * - Conditionals: `<div if="isVisible">`, `<div unless="isHidden">`
15
+ * - Loops: `<li loop="item in items">{{item.name}}</li>`
16
+ *
17
+ * @example
18
+ * // Basic usage
19
+ * import { compileTemplate } from './m';
20
+ *
21
+ * const { content, render } = compileTemplate(`
22
+ * <div class="card">
23
+ * <h2>{{title}}</h2>
24
+ * <p>{{description}}</p>
25
+ * </div>
26
+ * `);
27
+ *
28
+ * render({ title: 'Hello', description: 'World' });
29
+ * document.body.appendChild(content);
30
+ *
31
+ * @example
32
+ * // With pipes and functions
33
+ * import { createPipeRegistry } from '../pipes';
34
+ *
35
+ * const pipeRegistry = createPipeRegistry();
36
+ * const { content, render } = compileTemplate(`
37
+ * <span>{{user.name | uppercase}}</span>
38
+ * <span>{{formatDate(user.createdAt)}}</span>
39
+ * `, { strict: false, pipeRegistry });
40
+ *
41
+ * render(
42
+ * { user: { name: 'john', createdAt: new Date() } },
43
+ * { formatDate: (d) => d.toLocaleDateString() }
44
+ * );
45
+ *
46
+ * @example
47
+ * // With loops and conditionals
48
+ * const { content, render } = compileTemplate(`
49
+ * <ul>
50
+ * <li loop="item in items" if="item.visible">
51
+ * {{item.name}}: {{item.price | currency}}
52
+ * </li>
53
+ * </ul>
54
+ * `);
55
+ *
56
+ * render({ items: [
57
+ * { name: 'Apple', price: 1.5, visible: true },
58
+ * { name: 'Hidden', price: 0, visible: false }
59
+ * ]});
60
+ */
61
+ import { PipeRegistry } from '../pipes';
62
+ /**
63
+ * Configuration options for the template engine.
64
+ *
65
+ * @example
66
+ * const config: EngineConfig = {
67
+ * strict: true,
68
+ * onError: (msg) => console.error(msg),
69
+ * pipeRegistry: createPipeRegistry()
70
+ * };
71
+ */
72
+ export interface EngineConfig {
73
+ /** When true, throws errors for missing paths/functions. When false, returns empty string. */
74
+ strict: boolean;
75
+ /** Optional callback invoked when errors occur, receives formatted error message. */
76
+ onError?: (msg: string) => void;
77
+ /** Custom pipe registry for transformations. Defaults to built-in pipes. */
78
+ pipeRegistry?: PipeRegistry;
79
+ }
80
+ export type Path = string;
81
+ export type TemplateValue = string | number | boolean | null | undefined;
82
+ /**
83
+ * Data context object passed to render function.
84
+ * Contains the data values that expressions resolve against.
85
+ *
86
+ * @example
87
+ * const ctx: Context = {
88
+ * user: { name: 'John', age: 30 },
89
+ * items: ['a', 'b', 'c'],
90
+ * isActive: true
91
+ * };
92
+ */
93
+ export interface Context {
94
+ [key: string]: ContextValue;
95
+ }
96
+ /**
97
+ * Functions context object passed as second argument to render.
98
+ * Contains callable functions that can be invoked from templates.
99
+ *
100
+ * @example
101
+ * const fns: FunctionsContext = {
102
+ * formatDate: (d) => d.toLocaleDateString(),
103
+ * add: (a, b) => a + b,
104
+ * greet: (name) => `Hello, ${name}!`
105
+ * };
106
+ */
107
+ export interface FunctionsContext {
108
+ [key: string]: (...args: any[]) => any;
109
+ }
110
+ export type ContextValue = TemplateValue | any[] | Context | ((...args: any[]) => any);
111
+ export type Getter = (ctx: Context, path: Path, debugInfo?: string) => TemplateValue;
112
+ export type Setter = (ctx: Context, fns?: FunctionsContext) => void;
113
+ export type Patcher = (node: Node, get: Getter, config: EngineConfig) => Setter | void;
114
+ export type ExpressionFn = (ctx: Context, fns?: FunctionsContext) => TemplateValue;
115
+ /**
116
+ * Result of compiling a template.
117
+ * Contains the DOM content and a render function for updating it with data.
118
+ */
119
+ export interface CompiledTemplate {
120
+ /** The compiled DOM element containing the template structure. */
121
+ content: DocumentFragment | HTMLElement;
122
+ /**
123
+ * Updates the DOM with the provided data context.
124
+ * Memoized: only re-renders when context object reference changes.
125
+ * @param ctx - Data context with values for template expressions
126
+ * @param fns - Optional functions context for callable expressions
127
+ */
128
+ render: (ctx: Context, fns?: FunctionsContext) => void;
129
+ }
130
+ /**
131
+ * Compiles an HTML template string into a reusable render function.
132
+ *
133
+ * The template supports mustache-style expressions `{{expression}}` for:
134
+ * - Path resolution: `{{user.name}}`, `{{items[0].title}}`
135
+ * - Pipes: `{{value | uppercase}}`, `{{price | currency}}`
136
+ * - Function calls: `{{formatDate(createdAt)}}`, `{{add(a, b)}}`
137
+ *
138
+ * Directive attributes for control flow:
139
+ * - `if="condition"` - Renders element only when condition is truthy
140
+ * - `unless="condition"` - Renders element only when condition is falsy
141
+ * - `loop="item in items"` - Repeats element for each array item
142
+ *
143
+ * @param templateStr - HTML template string with mustache expressions
144
+ * @param config - Optional engine configuration
145
+ * @returns Compiled template with content and render function
146
+ *
147
+ * @example
148
+ * // Simple data binding
149
+ * const { content, render } = compileTemplate('<h1>{{title}}</h1>');
150
+ * render({ title: 'Hello World' });
151
+ * document.body.appendChild(content);
152
+ *
153
+ * @example
154
+ * // Re-rendering with new data
155
+ * const { content, render } = compileTemplate('<span>Count: {{count}}</span>');
156
+ * render({ count: 0 });
157
+ * render({ count: 1 }); // DOM updates automatically
158
+ *
159
+ * @example
160
+ * // With strict mode and error handling
161
+ * const { render } = compileTemplate('{{missing}}', {
162
+ * strict: true,
163
+ * onError: (msg) => console.error(msg)
164
+ * });
165
+ * render({}); // Throws error for missing path
166
+ */
167
+ export declare function compileTemplate(templateStr: string, config?: EngineConfig): CompiledTemplate;
@@ -0,0 +1,8 @@
1
+ export type PipeFunction = (value: any) => any;
2
+ export type StrictMode = boolean;
3
+ interface MustacheOptions {
4
+ strict?: StrictMode;
5
+ }
6
+ export declare function parseTemplate(template: string, options?: MustacheOptions): (data: any, component?: any) => string;
7
+ export declare function parse(template: string, data: any, component?: any, options?: MustacheOptions): string;
8
+ export {};
File without changes
@@ -0,0 +1,167 @@
1
+ /**
2
+ * @module template
3
+ * DOM-based template engine with reactive rendering capabilities.
4
+ *
5
+ * Compiles HTML templates with mustache-style expressions into efficient
6
+ * render functions that update the DOM when data changes.
7
+ *
8
+ * **Features:**
9
+ * - Text interpolation: `{{name}}`, `{{user.profile.email}}`
10
+ * - Attribute binding: `<div class="{{className}}">`
11
+ * - Pipes: `{{price | currency}}`, `{{name | uppercase | shorten:20}}`
12
+ * - Function calls: `{{formatDate(createdAt)}}`, `{{add(5, 3)}}`
13
+ * - Array indexing: `{{items[0]}}`, `{{users[1].name}}`
14
+ * - Conditionals: `<div if="isVisible">`, `<div unless="isHidden">`
15
+ * - Loops: `<li loop="item in items">{{item.name}}</li>`
16
+ *
17
+ * @example
18
+ * // Basic usage
19
+ * import { compileTemplate } from './m';
20
+ *
21
+ * const { content, render } = compileTemplate(`
22
+ * <div class="card">
23
+ * <h2>{{title}}</h2>
24
+ * <p>{{description}}</p>
25
+ * </div>
26
+ * `);
27
+ *
28
+ * render({ title: 'Hello', description: 'World' });
29
+ * document.body.appendChild(content);
30
+ *
31
+ * @example
32
+ * // With pipes and functions
33
+ * import { createPipeRegistry } from '../pipes';
34
+ *
35
+ * const pipeRegistry = createPipeRegistry();
36
+ * const { content, render } = compileTemplate(`
37
+ * <span>{{user.name | uppercase}}</span>
38
+ * <span>{{formatDate(user.createdAt)}}</span>
39
+ * `, { strict: false, pipeRegistry });
40
+ *
41
+ * render(
42
+ * { user: { name: 'john', createdAt: new Date() } },
43
+ * { formatDate: (d) => d.toLocaleDateString() }
44
+ * );
45
+ *
46
+ * @example
47
+ * // With loops and conditionals
48
+ * const { content, render } = compileTemplate(`
49
+ * <ul>
50
+ * <li loop="item in items" if="item.visible">
51
+ * {{item.name}}: {{item.price | currency}}
52
+ * </li>
53
+ * </ul>
54
+ * `);
55
+ *
56
+ * render({ items: [
57
+ * { name: 'Apple', price: 1.5, visible: true },
58
+ * { name: 'Hidden', price: 0, visible: false }
59
+ * ]});
60
+ */
61
+ import { PipeRegistry } from '../pipes';
62
+ /**
63
+ * Configuration options for the template engine.
64
+ *
65
+ * @example
66
+ * const config: EngineConfig = {
67
+ * strict: true,
68
+ * onError: (msg) => console.error(msg),
69
+ * pipeRegistry: createPipeRegistry()
70
+ * };
71
+ */
72
+ export interface EngineConfig {
73
+ /** When true, throws errors for missing paths/functions. When false, returns empty string. */
74
+ strict: boolean;
75
+ /** Optional callback invoked when errors occur, receives formatted error message. */
76
+ onError?: (msg: string) => void;
77
+ /** Custom pipe registry for transformations. Defaults to built-in pipes. */
78
+ pipeRegistry?: PipeRegistry;
79
+ }
80
+ export type Path = string;
81
+ export type TemplateValue = string | number | boolean | null | undefined;
82
+ /**
83
+ * Data context object passed to render function.
84
+ * Contains the data values that expressions resolve against.
85
+ *
86
+ * @example
87
+ * const ctx: Context = {
88
+ * user: { name: 'John', age: 30 },
89
+ * items: ['a', 'b', 'c'],
90
+ * isActive: true
91
+ * };
92
+ */
93
+ export interface Context {
94
+ [key: string]: ContextValue;
95
+ }
96
+ /**
97
+ * Functions context object passed as second argument to render.
98
+ * Contains callable functions that can be invoked from templates.
99
+ *
100
+ * @example
101
+ * const fns: FunctionsContext = {
102
+ * formatDate: (d) => d.toLocaleDateString(),
103
+ * add: (a, b) => a + b,
104
+ * greet: (name) => `Hello, ${name}!`
105
+ * };
106
+ */
107
+ export interface FunctionsContext {
108
+ [key: string]: (...args: any[]) => any;
109
+ }
110
+ export type ContextValue = TemplateValue | any[] | Context | ((...args: any[]) => any);
111
+ export type Getter = (ctx: Context, path: Path, debugInfo?: string) => TemplateValue;
112
+ export type Setter = (ctx: Context, fns?: FunctionsContext) => void;
113
+ export type Patcher = (node: Node, get: Getter, config: EngineConfig) => Setter | void;
114
+ export type ExpressionFn = (ctx: Context, fns?: FunctionsContext) => TemplateValue;
115
+ /**
116
+ * Result of compiling a template.
117
+ * Contains the DOM content and a render function for updating it with data.
118
+ */
119
+ export interface CompiledTemplate {
120
+ /** The compiled DOM element containing the template structure. */
121
+ content: DocumentFragment | HTMLElement;
122
+ /**
123
+ * Updates the DOM with the provided data context.
124
+ * Memoized: only re-renders when context object reference changes.
125
+ * @param ctx - Data context with values for template expressions
126
+ * @param fns - Optional functions context for callable expressions
127
+ */
128
+ render: (ctx: Context, fns?: FunctionsContext) => void;
129
+ }
130
+ /**
131
+ * Compiles an HTML template string into a reusable render function.
132
+ *
133
+ * The template supports mustache-style expressions `{{expression}}` for:
134
+ * - Path resolution: `{{user.name}}`, `{{items[0].title}}`
135
+ * - Pipes: `{{value | uppercase}}`, `{{price | currency}}`
136
+ * - Function calls: `{{formatDate(createdAt)}}`, `{{add(a, b)}}`
137
+ *
138
+ * Directive attributes for control flow:
139
+ * - `if="condition"` - Renders element only when condition is truthy
140
+ * - `unless="condition"` - Renders element only when condition is falsy
141
+ * - `loop="item in items"` - Repeats element for each array item
142
+ *
143
+ * @param templateStr - HTML template string with mustache expressions
144
+ * @param config - Optional engine configuration
145
+ * @returns Compiled template with content and render function
146
+ *
147
+ * @example
148
+ * // Simple data binding
149
+ * const { content, render } = compileTemplate('<h1>{{title}}</h1>');
150
+ * render({ title: 'Hello World' });
151
+ * document.body.appendChild(content);
152
+ *
153
+ * @example
154
+ * // Re-rendering with new data
155
+ * const { content, render } = compileTemplate('<span>Count: {{count}}</span>');
156
+ * render({ count: 0 });
157
+ * render({ count: 1 }); // DOM updates automatically
158
+ *
159
+ * @example
160
+ * // With strict mode and error handling
161
+ * const { render } = compileTemplate('{{missing}}', {
162
+ * strict: true,
163
+ * onError: (msg) => console.error(msg)
164
+ * });
165
+ * render({}); // Throws error for missing path
166
+ */
167
+ export declare function compileTemplate(templateStr: string, config?: EngineConfig): CompiledTemplate;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * @module HttpClient
3
+ * Type-safe HTTP client built on fetch() with automatic JWT handling.
4
+ *
5
+ * @example
6
+ * const api = new HttpClient({ baseUrl: '/api' });
7
+ * const response = await api.get('/users');
8
+ * const users = response.as<User[]>();
9
+ */
10
+ /**
11
+ * Configuration options for HttpClient.
12
+ */
13
+ export interface HttpClientOptions {
14
+ /**
15
+ * Root URL to remote endpoint. Used so that each method only have to specify path in requests.
16
+ */
17
+ baseUrl?: string;
18
+ /**
19
+ * Default content type to use if none is specified in the request method.
20
+ */
21
+ contentType?: string;
22
+ /***
23
+ * Checks for a JWT token in localStorage to automatically include it in requests.
24
+ *
25
+ * Undefined = use "jwt", null = disable.
26
+ */
27
+ bearerTokenName?: string;
28
+ }
29
+ /**
30
+ * HTTP client wrapper around fetch() with convenience features.
31
+ *
32
+ * Features:
33
+ * - Automatic base URL prefixing
34
+ * - JWT token handling from localStorage
35
+ * - Type-safe response casting
36
+ * - Consistent error handling
37
+ *
38
+ * @example
39
+ * // Create client with base URL
40
+ * const api = new HttpClient({ baseUrl: '/api/v1' });
41
+ *
42
+ * // GET request
43
+ * const users = await api.get('/users');
44
+ * const data = users.as<User[]>();
45
+ *
46
+ * // POST request
47
+ * const result = await api.post('/users', JSON.stringify({ name: 'John' }));
48
+ */
49
+ export declare class HttpClient {
50
+ private options?;
51
+ /**
52
+ *
53
+ * @param urlPrefix Can be used to specify the URL early (to allow only path to be used in all methods).
54
+ * @param defaultContentType Content type to use if not specified in the constructor
55
+ */
56
+ constructor(options?: HttpClientOptions);
57
+ /**
58
+ *
59
+ * @param url URL to make the request against.
60
+ * @param options Request options.
61
+ * @returns Response from server.
62
+ */
63
+ request(url: string, options?: RequestInit): Promise<HttpResponse>;
64
+ /**
65
+ * GET a resource.
66
+ * @param url URL to get resource from.
67
+ * @param queryString Optional query string.
68
+ * @param options Request options.
69
+ * @returns HTTP response.
70
+ */
71
+ get(url: string, queryString?: Record<string, string>, options?: RequestInit): Promise<HttpResponse>;
72
+ /**
73
+ * POST a resource.
74
+ * @param url URL to post to.
75
+ * @param data Data to post.
76
+ * @param options Request options.
77
+ * @returns HTTP response.
78
+ */
79
+ post(url: string, data: BodyInit, options?: RequestInit): Promise<HttpResponse>;
80
+ /**
81
+ * DELETE a resource.
82
+ * @param url url to resource.
83
+ * @param options request options.
84
+ * @returns response.
85
+ */
86
+ put(url: string, data: BodyInit, options?: RequestInit): Promise<HttpResponse>;
87
+ /**
88
+ * DELETE a resource.
89
+ * @param url url to resource.
90
+ * @param options request options.
91
+ * @returns response.
92
+ */
93
+ delete(url: string, options?: RequestInit): Promise<HttpResponse>;
94
+ }
95
+ /**
96
+ * Response for request methods in @see HttpClient
97
+ */
98
+ export interface HttpResponse {
99
+ /**
100
+ * Http status code.
101
+ */
102
+ statusCode: number;
103
+ /**
104
+ * Reason to why the status code was used.
105
+ */
106
+ statusReason: string;
107
+ /**
108
+ * this is a 2x response.
109
+ */
110
+ success: boolean;
111
+ /**
112
+ * Content type of response body.
113
+ */
114
+ contentType: string | null;
115
+ /**
116
+ * Body returned.
117
+ *
118
+ * Body has been read and deserialized from json (if the request content type was 'application/json' which is per default is).
119
+ */
120
+ body: unknown;
121
+ /**
122
+ * Charset used in body.
123
+ */
124
+ charset: string | null;
125
+ /**
126
+ * Cast body to a type.
127
+ */
128
+ as<T>(): T;
129
+ }
130
+ /**
131
+ * Error thrown when a request fails.
132
+ */
133
+ export declare class HttpError extends Error {
134
+ message: string;
135
+ response: HttpResponse;
136
+ constructor(response: HttpResponse);
137
+ }
138
+ /**
139
+ * HTTP request options.
140
+ */
141
+ export interface RequestOptions {
142
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
143
+ mode?: 'cors' | 'no-cors' | '*cors' | 'same-origin';
144
+ cache: 'default' | 'no-store' | 'reload' | 'no-cache' | 'force-cache' | 'only-if-cached';
145
+ credentials: 'omit' | 'same-origin' | 'include';
146
+ headers: Map<string, string>;
147
+ redirect: 'follow' | 'manual' | '*follow' | 'error';
148
+ referrerPolicy: 'no-referrer' | '*no-referrer-when-downgrade' | 'origin' | 'origin-when-cross-origin' | 'same-origin' | 'strict-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url';
149
+ /**
150
+ * Will be serialized if the content type is json (and the body is an object).
151
+ */
152
+ body: unknown;
153
+ }