@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.
- package/LICENSE +21 -0
- package/README.md +188 -0
- package/dist/DataLoader.d.ts +51 -0
- package/dist/DependencyInjection.d.ts +271 -0
- package/dist/DependencyInjectionOld.d.ts +35 -0
- package/dist/Metadata.d.ts +8 -0
- package/dist/SequentialId.d.ts +47 -0
- package/dist/_alt/src/MustardEngine.d.ts +30 -0
- package/dist/_alt/src/MustardParser.d.ts +63 -0
- package/dist/_alt/src/MustardParser2.d.ts +35 -0
- package/dist/_alt/src/pipes.d.ts +93 -0
- package/dist/_alt/src/template.d.ts +166 -0
- package/dist/_alt/src/tools.d.ts +4 -0
- package/dist/_alt/tests/pipes.tests.d.ts +1 -0
- package/dist/_alt/tests/template.tests.d.ts +1 -0
- package/dist/_alt/vitest.config.d.ts +2 -0
- package/dist/collections/Index.d.ts +1 -0
- package/dist/collections/LinkedList.d.ts +75 -0
- package/dist/collections/Pager.d.ts +15 -0
- package/dist/collections/index.js +2 -0
- package/dist/collections/index.js.map +7 -0
- package/dist/collections/index.mjs +2 -0
- package/dist/collections/index.mjs.map +7 -0
- package/dist/components/Table.d.ts +13 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +128 -0
- package/dist/components/index.js.map +7 -0
- package/dist/components/index.mjs +128 -0
- package/dist/components/index.mjs.map +7 -0
- package/dist/components/lists/Table.d.ts +59 -0
- package/dist/components/lists/TreeView.d.ts +67 -0
- package/dist/components/lists/index.d.ts +2 -0
- package/dist/components/loader.d.ts +60 -0
- package/dist/components/menus/MenuItem.d.ts +30 -0
- package/dist/components/menus/TopMenu.d.ts +16 -0
- package/dist/components/menus/index.d.ts +2 -0
- package/dist/components/panels/tabs.d.ts +15 -0
- package/dist/di/index.d.ts +1 -0
- package/dist/di/index.js +2 -0
- package/dist/di/index.js.map +7 -0
- package/dist/di/index.mjs +2 -0
- package/dist/di/index.mjs.map +7 -0
- package/dist/elements/CopyAttributes.d.ts +2 -0
- package/dist/elements/dom.d.ts +18 -0
- package/dist/elements/index.d.ts +2 -0
- package/dist/elements/index.js +2 -0
- package/dist/elements/index.js.map +7 -0
- package/dist/elements/index.mjs +2 -0
- package/dist/elements/index.mjs.map +7 -0
- package/dist/errors.d.ts +71 -0
- package/dist/forms/FormReader.d.ts +182 -0
- package/dist/forms/FormValidator.d.ts +114 -0
- package/dist/forms/ValidationRules.d.ts +103 -0
- package/dist/forms/index.d.ts +4 -0
- package/dist/forms/index.js +2 -0
- package/dist/forms/index.js.map +7 -0
- package/dist/forms/index.mjs +2 -0
- package/dist/forms/index.mjs.map +7 -0
- package/dist/forms/setFormData.d.ts +49 -0
- package/dist/getParentComponent.d.ts +43 -0
- package/dist/html/TableRenderer.d.ts +44 -0
- package/dist/html/TreeBinder.d.ts +9 -0
- package/dist/html/html.d.ts +55 -0
- package/dist/html/index.d.ts +5 -0
- package/dist/html/index.js +2 -0
- package/dist/html/index.js.map +7 -0
- package/dist/html/index.mjs +2 -0
- package/dist/html/index.mjs.map +7 -0
- package/dist/html/template.d.ts +167 -0
- package/dist/http/ServerSentEvents.d.ts +116 -0
- package/dist/http/SimpleWebSocket.d.ts +153 -0
- package/dist/http/http.d.ts +177 -0
- package/dist/http/index.d.ts +3 -0
- package/dist/http/index.js +2 -0
- package/dist/http/index.js.map +7 -0
- package/dist/http/index.mjs +2 -0
- package/dist/http/index.mjs.map +7 -0
- package/dist/i18n/i18n.d.ts +105 -0
- package/dist/i18n/icu.d.ts +64 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/index.js.map +7 -0
- package/dist/i18n/index.mjs +2 -0
- package/dist/i18n/index.mjs.map +7 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +7 -0
- package/dist/index.mjs +5 -0
- package/dist/index.mjs.map +7 -0
- package/dist/lib/DataLoader.d.ts +51 -0
- package/dist/lib/DependencyInjection.d.ts +271 -0
- package/dist/lib/InvokeParent.d.ts +10 -0
- package/dist/lib/Pipes.d.ts +236 -0
- package/dist/lib/SequentialId.d.ts +47 -0
- package/dist/lib/collections/Index.d.ts +1 -0
- package/dist/lib/collections/LinkedList.d.ts +75 -0
- package/dist/lib/collections/Pager.d.ts +15 -0
- package/dist/lib/collections/TableRenderer.d.ts +44 -0
- package/dist/lib/di/index.d.ts +1 -0
- package/dist/lib/elements/CopyAttributes.d.ts +2 -0
- package/dist/lib/elements/dom.d.ts +18 -0
- package/dist/lib/elements/index.d.ts +2 -0
- package/dist/lib/errors.d.ts +71 -0
- package/dist/lib/forms/FormReader.d.ts +182 -0
- package/dist/lib/forms/FormValidator.d.ts +114 -0
- package/dist/lib/forms/ValidationRules.d.ts +103 -0
- package/dist/lib/forms/index.d.ts +4 -0
- package/dist/lib/forms/setFormData.d.ts +49 -0
- package/dist/lib/getParentComponent.d.ts +43 -0
- package/dist/lib/html/TableRenderer.d.ts +44 -0
- package/dist/lib/html/TreeBinder.d.ts +9 -0
- package/dist/lib/html/html.d.ts +55 -0
- package/dist/lib/html/html2.d.ts +55 -0
- package/dist/lib/html/index.d.ts +5 -0
- package/dist/lib/html/m.d.ts +167 -0
- package/dist/lib/html/m2.d.ts +8 -0
- package/dist/lib/html/m3.d.ts +0 -0
- package/dist/lib/html/template.d.ts +167 -0
- package/dist/lib/http/HttpClient.d.ts +153 -0
- package/dist/lib/http/ServerSentEvents.d.ts +116 -0
- package/dist/lib/http/SimpleWebSocket.d.ts +153 -0
- package/dist/lib/http/http.d.ts +177 -0
- package/dist/lib/http/index.d.ts +3 -0
- package/dist/lib/i18n/i18n.d.ts +105 -0
- package/dist/lib/i18n/icu.d.ts +64 -0
- package/dist/lib/i18n/index.d.ts +2 -0
- package/dist/lib/index.d.ts +16 -0
- package/dist/lib/routing/NavigateRouteEvent.d.ts +52 -0
- package/dist/lib/routing/RouteLink.d.ts +7 -0
- package/dist/lib/routing/Routing.d.ts +270 -0
- package/dist/lib/routing/RoutingTarget.d.ts +22 -0
- package/dist/lib/routing/index.d.ts +7 -0
- package/dist/lib/routing/navigation.d.ts +70 -0
- package/dist/lib/routing/routeMatching.d.ts +21 -0
- package/dist/lib/routing/routeTargetRegistry.d.ts +23 -0
- package/dist/lib/routing/types.d.ts +130 -0
- package/dist/lib/templates/NodeTemplate.d.ts +38 -0
- package/dist/lib/templates/accessorParser.d.ts +87 -0
- package/dist/lib/templates/parseTemplate.d.ts +6 -0
- package/dist/lib/templates/tokenizer.d.ts +76 -0
- package/dist/lib/tools.d.ts +30 -0
- package/dist/lib/utils/index.d.ts +4 -0
- package/dist/pipes.d.ts +236 -0
- package/dist/routing/NavigateRouteEvent.d.ts +52 -0
- package/dist/routing/RouteLink.d.ts +7 -0
- package/dist/routing/RoutingTarget.d.ts +22 -0
- package/dist/routing/index.d.ts +7 -0
- package/dist/routing/index.js +5 -0
- package/dist/routing/index.js.map +7 -0
- package/dist/routing/index.mjs +5 -0
- package/dist/routing/index.mjs.map +7 -0
- package/dist/routing/navigation.d.ts +70 -0
- package/dist/routing/routeMatching.d.ts +21 -0
- package/dist/routing/routeTargetRegistry.d.ts +23 -0
- package/dist/routing/types.d.ts +130 -0
- package/dist/templates/NodeTemplate.d.ts +38 -0
- package/dist/templates/accessorParser.d.ts +87 -0
- package/dist/templates/parseTemplate.d.ts +6 -0
- package/dist/templates/tokenizer.d.ts +76 -0
- package/dist/tools.d.ts +30 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +7 -0
- package/dist/utils/index.mjs +2 -0
- package/dist/utils/index.mjs.map +7 -0
- package/docs/Architecture.md +333 -0
- package/docs/DependencyInjection.md +237 -0
- package/docs/Errors.md +87 -0
- package/docs/GettingStarted.md +231 -0
- package/docs/Pipes.md +211 -0
- package/docs/Translations.md +312 -0
- package/docs/WhyRelaxjs.md +336 -0
- package/docs/elements/dom.md +102 -0
- package/docs/forms/creating-form-components.md +924 -0
- package/docs/forms/form-api.md +94 -0
- package/docs/forms/forms.md +99 -0
- package/docs/forms/patterns.md +311 -0
- package/docs/forms/reading-writing.md +365 -0
- package/docs/forms/validation.md +351 -0
- package/docs/html/TableRenderer.md +292 -0
- package/docs/html/html.md +175 -0
- package/docs/html/index.md +54 -0
- package/docs/html/template.md +422 -0
- package/docs/http/HttpClient.md +459 -0
- package/docs/http/ServerSentEvents.md +184 -0
- package/docs/http/index.md +109 -0
- package/docs/i18n/i18n.md +309 -0
- package/docs/i18n/intl-standard.md +178 -0
- package/docs/routing/RouteLink.md +98 -0
- package/docs/routing/Routing.md +332 -0
- package/docs/routing/RoutingTarget.md +136 -0
- package/docs/routing/layouts.md +207 -0
- package/docs/utilities.md +143 -0
- package/package.json +93 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 relax.js
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Relaxjs
|
|
2
|
+
|
|
3
|
+
**Ship faster with less code.**
|
|
4
|
+
|
|
5
|
+
Web Component library with routing, forms, DI, templating, and i18n. No virtual DOM, no build magic, no surprise re-renders.
|
|
6
|
+
|
|
7
|
+
## Why Relaxjs?
|
|
8
|
+
|
|
9
|
+
Modern frameworks solve problems you might not have. Relaxjs takes the opposite approach:
|
|
10
|
+
|
|
11
|
+
| Framework Approach | Relaxjs Approach |
|
|
12
|
+
|-------------------|------------------|
|
|
13
|
+
| Virtual DOM diffing | Direct DOM manipulation |
|
|
14
|
+
| Reactive state management | Explicit updates |
|
|
15
|
+
| Custom template syntax | Standard HTML |
|
|
16
|
+
| Framework-specific lifecycle | Native Web Component lifecycle |
|
|
17
|
+
| Magic re-renders | You control what updates |
|
|
18
|
+
| Custom rendering pipeline | Native async/await everywhere |
|
|
19
|
+
|
|
20
|
+
> [Read the detailed comparison](docs/WhyRelaxjs.md)
|
|
21
|
+
|
|
22
|
+
**The result:** You always know *when* something ran, *why* it ran, and *what* triggered it.
|
|
23
|
+
|
|
24
|
+
## What Relaxjs Adds
|
|
25
|
+
|
|
26
|
+
Web Components give you encapsulation and lifecycle hooks. Relaxjs fills the gaps:
|
|
27
|
+
|
|
28
|
+
| Vanilla Web Components | With Relaxjs |
|
|
29
|
+
|------------------------|--------------|
|
|
30
|
+
| Manual form serialization | `readData(form)` returns typed objects (send it directly to backend) |
|
|
31
|
+
| Query string parsing | Named routes with typed parameters |
|
|
32
|
+
| DIY validation logic | `FormValidator` with HTML5 integration |
|
|
33
|
+
| No component library | Table, Tabs, TreeView, Menu ready to use |
|
|
34
|
+
| Manual service wiring | Decorator-based dependency injection |
|
|
35
|
+
| Raw fetch boilerplate | Simple HTTP client for backend calls |
|
|
36
|
+
|
|
37
|
+
You write less boilerplate while keeping full control.
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install relaxjs
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Examples
|
|
46
|
+
|
|
47
|
+
### Form Handling
|
|
48
|
+
|
|
49
|
+
Read and write form data with automatic type conversion:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { setFormData, readData } from 'relaxjs';
|
|
53
|
+
|
|
54
|
+
// Populate a form from an object
|
|
55
|
+
const user = { name: 'John', email: 'john@example.com', age: 30 };
|
|
56
|
+
setFormData(form, user);
|
|
57
|
+
|
|
58
|
+
// Read form data back (with types!)
|
|
59
|
+
const data = readData(form);
|
|
60
|
+
// { name: 'John', email: 'john@example.com', age: 30 }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Supports nested objects (`user.address.city`), arrays (`tags[]`), and automatic type conversion for numbers, booleans, and dates.
|
|
64
|
+
|
|
65
|
+
> [Form utilities docs](docs/forms/forms.md)
|
|
66
|
+
|
|
67
|
+
### Client-Side Routing
|
|
68
|
+
|
|
69
|
+
Define routes and let the router handle navigation:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { defineRoutes, navigate, startRouting } from 'relaxjs';
|
|
73
|
+
|
|
74
|
+
defineRoutes([
|
|
75
|
+
{ name: 'home', path: '/', componentTagName: 'app-home' },
|
|
76
|
+
{ name: 'user', path: '/users/:id', componentTagName: 'app-user' },
|
|
77
|
+
{ name: 'settings', path: '/settings', componentTagName: 'app-settings' }
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
startRouting();
|
|
81
|
+
|
|
82
|
+
// Navigate programmatically
|
|
83
|
+
navigate('user', { params: { id: '123' } });
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<r-route-target></r-route-target>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
> [Routing docs](docs/routing/Routing.md)
|
|
91
|
+
|
|
92
|
+
### Form Validation
|
|
93
|
+
|
|
94
|
+
HTML5-style validation with custom rules and error summaries:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { FormValidator } from 'relaxjs';
|
|
98
|
+
|
|
99
|
+
const validator = new FormValidator(form, {
|
|
100
|
+
useSummary: true,
|
|
101
|
+
submitCallback: () => saveData()
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
> [Validation docs](docs/forms/validation.md)
|
|
106
|
+
|
|
107
|
+
## What's Included
|
|
108
|
+
|
|
109
|
+
| Feature | Description |
|
|
110
|
+
|---------|-------------|
|
|
111
|
+
| **Form Utilities** | Read/write forms, type conversion, validation |
|
|
112
|
+
| **Routing** | Named routes, typed parameters, guards, layouts, multiple targets |
|
|
113
|
+
| **HTML Templates** | `html` tagged templates with data binding and in-place updates |
|
|
114
|
+
| **HTTP Client** | Type-safe `get`/`post`/`put`/`del` with automatic JWT |
|
|
115
|
+
| **WebSocket** | Auto-reconnect, message queuing, typed messages |
|
|
116
|
+
| **SSE** | Server-Sent Events dispatched as DOM events |
|
|
117
|
+
| **Dependency Injection** | Decorator-based DI with constructor and property injection |
|
|
118
|
+
| **i18n** | ICU message format, pluralization, locale-aware formatting |
|
|
119
|
+
| **Pipes** | 15 built-in data transformations for templates |
|
|
120
|
+
|
|
121
|
+
## Where Relaxjs Fits
|
|
122
|
+
|
|
123
|
+
Relaxjs is a good choice when:
|
|
124
|
+
|
|
125
|
+
- You're building a **small-to-medium SPA** where you want direct control over the DOM
|
|
126
|
+
- Your team prefers **vanilla Web Components** over framework abstractions
|
|
127
|
+
- You want **gradual adoption** - use only the parts you need, no all-or-nothing buy-in
|
|
128
|
+
- **Bundle size and simplicity** matter more than ecosystem breadth
|
|
129
|
+
- You want to **understand what your code does** - no hidden re-renders, no magic proxies, no compiler transforms
|
|
130
|
+
|
|
131
|
+
## Where Relaxjs Doesn't Fit
|
|
132
|
+
|
|
133
|
+
Be honest with yourself - Relaxjs is not the right tool for everything:
|
|
134
|
+
|
|
135
|
+
- **Large-scale apps with complex state** - Relaxjs has no reactive state management, no global store, no computed properties. If your UI has dozens of interdependent data flows, you'll be writing a lot of manual update logic.
|
|
136
|
+
- **Server-side rendering / static site generation** - Relaxjs is client-only. If you need SEO, fast first-paint from the server, or pre-rendered pages, look at Next.js, Nuxt, or SvelteKit.
|
|
137
|
+
- **Big teams that need a large talent pool** - React and Angular developers are everywhere. Finding developers who know Relaxjs (or are willing to learn a small library) is harder.
|
|
138
|
+
- **Rich ecosystem needs** - There's no component marketplace, no DevTools extension, no community middleware. You build what you need or use vanilla JS libraries.
|
|
139
|
+
- **Mobile / native targets** - No React Native equivalent, no Ionic integration. Relaxjs is for the browser.
|
|
140
|
+
|
|
141
|
+
## How It Compares
|
|
142
|
+
|
|
143
|
+
| | Relaxjs | React | Angular | Vue | Svelte |
|
|
144
|
+
|---|---|---|---|---|---|
|
|
145
|
+
| **Approach** | Web Components | Virtual DOM | Full framework | Virtual DOM | Compiler |
|
|
146
|
+
| **Bundle size** | ~20KB gzipped | ~45KB | ~150KB+ | ~33KB | ~2KB runtime |
|
|
147
|
+
| **Learning curve** | Low (vanilla TS) | Medium | High | Medium | Low-Medium |
|
|
148
|
+
| **State management** | Explicit DOM updates | Hooks / Redux / Zustand | RxJS / Signals | Reactive refs | Stores / runes |
|
|
149
|
+
| **Routing** | Built-in (simple) | react-router (separate) | Built-in (full) | vue-router (separate) | SvelteKit |
|
|
150
|
+
| **Forms** | Built-in (HTML5 native) | Controlled / uncontrolled | Reactive forms | v-model | bind: |
|
|
151
|
+
| **SSR** | No | Yes | Yes | Yes | Yes |
|
|
152
|
+
| **Ecosystem** | Small | Massive | Large | Large | Growing |
|
|
153
|
+
| **DI** | Built-in | None (Context API) | Built-in | Provide / Inject | None |
|
|
154
|
+
| **i18n** | Built-in (ICU) | i18next etc. | Built-in | vue-i18n | i18next etc. |
|
|
155
|
+
| **DevTools** | Browser DevTools | React DevTools | Angular DevTools | Vue DevTools | Svelte DevTools |
|
|
156
|
+
| **Community size** | Small | Very large | Large | Large | Medium |
|
|
157
|
+
|
|
158
|
+
## Philosophy
|
|
159
|
+
|
|
160
|
+
This isn't a framework - it's a library. Use what you need:
|
|
161
|
+
|
|
162
|
+
- Need just form handling? Import `setFormData` and `readData`.
|
|
163
|
+
- Need routing? Add `defineRoutes` and `r-route-target`.
|
|
164
|
+
- Need everything? It's all there.
|
|
165
|
+
|
|
166
|
+
No buy-in required. No migration path to worry about. Just Web Components and TypeScript.
|
|
167
|
+
|
|
168
|
+
## Documentation
|
|
169
|
+
|
|
170
|
+
- [Why Relaxjs?](docs/WhyRelaxjs.md) - Detailed comparison with frameworks
|
|
171
|
+
- [Getting Started](docs/GettingStarted.md) - Progressive adoption guide (7 levels)
|
|
172
|
+
- [Architecture](docs/Architecture.md)
|
|
173
|
+
- [Form Utilities](docs/forms/forms.md) - Validation, reading/writing, custom form components
|
|
174
|
+
- [Routing](docs/routing/Routing.md) - Routes, guards, layouts, navigation
|
|
175
|
+
- [HTML Templates](docs/html/html.md) - Tagged templates with data binding
|
|
176
|
+
- [HTTP & WebSocket](docs/http/HttpClient.md) - REST calls, WebSocket, SSE
|
|
177
|
+
- [Dependency Injection](docs/DependencyInjection.md)
|
|
178
|
+
- [i18n](docs/i18n/i18n.md) - Translations, ICU format, locale switching
|
|
179
|
+
- [Pipes](docs/Pipes.md) - Data transformations for templates
|
|
180
|
+
- [Utilities](docs/utilities.md) - Sequential IDs, LinkedList, helpers
|
|
181
|
+
|
|
182
|
+
## Browser Support
|
|
183
|
+
|
|
184
|
+
Works in all browsers that support Web Components (Chrome, Firefox, Safari, Edge).
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
ISC
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for loading paginated data from a data source.
|
|
3
|
+
* Implement this interface to provide data to table or list components
|
|
4
|
+
* that support pagination and sorting.
|
|
5
|
+
*
|
|
6
|
+
* Used by components like `r-table` to fetch data on demand as users
|
|
7
|
+
* navigate through pages or change sort order.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // Implement for an API-backed data source
|
|
11
|
+
* class UserDataLoader implements DataLoader {
|
|
12
|
+
* async load(options) {
|
|
13
|
+
* const params = new URLSearchParams({
|
|
14
|
+
* page: options.page.toString(),
|
|
15
|
+
* pageSize: options.pageSize.toString(),
|
|
16
|
+
* sort: JSON.stringify(options.sort)
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* const response = await fetch(`/api/users?${params}`);
|
|
20
|
+
* return response.json();
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Use with a table component
|
|
26
|
+
* const loader: DataLoader = new UserDataLoader();
|
|
27
|
+
* const result = await loader.load({ page: 1, pageSize: 25, sort: [] });
|
|
28
|
+
* table.render(result.rows);
|
|
29
|
+
*/
|
|
30
|
+
export interface DataLoader {
|
|
31
|
+
/**
|
|
32
|
+
* Loads a page of data with optional sorting.
|
|
33
|
+
*
|
|
34
|
+
* @param options - The loading options
|
|
35
|
+
* @param options.page - The 1-based page number to load
|
|
36
|
+
* @param options.pageSize - Number of rows per page
|
|
37
|
+
* @param options.sort - Array of sort specifications
|
|
38
|
+
* @returns Promise resolving to rows and total count for pagination
|
|
39
|
+
*/
|
|
40
|
+
load(options: {
|
|
41
|
+
page: number;
|
|
42
|
+
pageSize: number;
|
|
43
|
+
sort: {
|
|
44
|
+
column: string;
|
|
45
|
+
direction: 'asc' | 'desc';
|
|
46
|
+
}[];
|
|
47
|
+
}): Promise<{
|
|
48
|
+
rows: Record<string, any>[];
|
|
49
|
+
totalCount: number;
|
|
50
|
+
}>;
|
|
51
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic constructor type used for dependency registration and injection.
|
|
3
|
+
* Represents any class constructor that can be used with the DI container.
|
|
4
|
+
*
|
|
5
|
+
* @template T - The type of object the constructor creates
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Use with service registration
|
|
9
|
+
* class UserService {}
|
|
10
|
+
* const ctor: Constructor<UserService> = UserService;
|
|
11
|
+
* serviceCollection.registerByType(ctor, { inject: [] });
|
|
12
|
+
*/
|
|
13
|
+
export type Constructor<T extends object = object> = new (...args: any[]) => T;
|
|
14
|
+
/**
|
|
15
|
+
* Controls how service instances are shared across the container hierarchy.
|
|
16
|
+
* Used when registering services to define their lifetime behavior.
|
|
17
|
+
*
|
|
18
|
+
* - `global`: Single instance shared everywhere (singleton pattern)
|
|
19
|
+
* - `closest`: New instance per container scope (scoped lifetime)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Singleton service - same instance everywhere
|
|
23
|
+
* serviceCollection.register(LoggerService, { scope: 'global', inject: [] });
|
|
24
|
+
*
|
|
25
|
+
* // Scoped service - new instance per scope
|
|
26
|
+
* serviceCollection.register(RequestContext, { scope: 'closest', inject: [] });
|
|
27
|
+
*/
|
|
28
|
+
export type ServiceScope = 'global' | 'closest';
|
|
29
|
+
/**
|
|
30
|
+
* Configuration options for registering a service in the DI container.
|
|
31
|
+
* Controls identification, lifetime, and dependency resolution.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Register with constructor injection
|
|
35
|
+
* const options: RegistrationOptions = {
|
|
36
|
+
* scope: 'global',
|
|
37
|
+
* inject: [DatabaseConnection, ConfigService]
|
|
38
|
+
* };
|
|
39
|
+
* serviceCollection.register(UserRepository, options);
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* // Register with property injection
|
|
43
|
+
* const options: RegistrationOptions = {
|
|
44
|
+
* inject: [],
|
|
45
|
+
* properties: { logger: Logger, config: 'appConfig' }
|
|
46
|
+
* };
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // Register with a pre-created instance
|
|
50
|
+
* const options: RegistrationOptions = {
|
|
51
|
+
* inject: [],
|
|
52
|
+
* instance: existingService
|
|
53
|
+
* };
|
|
54
|
+
*/
|
|
55
|
+
export interface RegistrationOptions {
|
|
56
|
+
/** Service lifetime - 'global' for singleton, 'closest' for scoped */
|
|
57
|
+
scope?: ServiceScope;
|
|
58
|
+
/** Optional string key for resolving by name instead of type */
|
|
59
|
+
key?: string;
|
|
60
|
+
/** Pre-existing instance to use instead of creating new one */
|
|
61
|
+
instance?: unknown;
|
|
62
|
+
/** Types or keys for constructor parameters, in order */
|
|
63
|
+
inject: (string | Constructor)[];
|
|
64
|
+
/** Map of property names to their injection types/keys */
|
|
65
|
+
properties?: Record<string, string | Constructor>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Field decorator that collects property injection configuration.
|
|
69
|
+
* Updates or creates the properties mapping in registration options.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* @ContainerService({
|
|
73
|
+
* inject: [Database],
|
|
74
|
+
* properties: {
|
|
75
|
+
* logger: Logger, // Inject by type
|
|
76
|
+
* audit: 'auditLogger' // Inject by key
|
|
77
|
+
* }
|
|
78
|
+
* })
|
|
79
|
+
* class UserService {
|
|
80
|
+
* @Inject(Logger)
|
|
81
|
+
* private logger!: Logger;
|
|
82
|
+
*
|
|
83
|
+
* @Inject('auditLogger')
|
|
84
|
+
* private audit!: Logger;
|
|
85
|
+
*
|
|
86
|
+
* constructor(db: Database) {}
|
|
87
|
+
* }
|
|
88
|
+
*/
|
|
89
|
+
export declare function Inject<T extends object>(typeOrKey: Constructor<T> | string): (_: undefined, context: ClassFieldDecoratorContext) => (this: any) => T;
|
|
90
|
+
/**
|
|
91
|
+
* Class decorator that automatically registers a service in the global DI container.
|
|
92
|
+
* Use this to declaratively register services without manual registration calls.
|
|
93
|
+
*
|
|
94
|
+
* Services are registered at module load time, so ensure this file is imported
|
|
95
|
+
* before attempting to resolve the decorated service.
|
|
96
|
+
*
|
|
97
|
+
* @param options - Registration configuration including scope and dependencies
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* // Simple service with constructor injection
|
|
101
|
+
* @ContainerService({ inject: [DatabaseConnection] })
|
|
102
|
+
* class UserRepository {
|
|
103
|
+
* constructor(private db: DatabaseConnection) {}
|
|
104
|
+
* }
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* // Service with custom key for named resolution
|
|
108
|
+
* @ContainerService({ key: 'primaryCache', scope: 'global', inject: [] })
|
|
109
|
+
* class CacheService {}
|
|
110
|
+
*
|
|
111
|
+
* // Later resolve by key
|
|
112
|
+
* const cache = container.resolve('primaryCache');
|
|
113
|
+
*/
|
|
114
|
+
export declare function ContainerService<T extends object>(options?: RegistrationOptions): (target: Constructor<T>) => void;
|
|
115
|
+
/**
|
|
116
|
+
* Internal class representing a registered service's metadata.
|
|
117
|
+
* Holds all information needed to create and configure service instances.
|
|
118
|
+
*
|
|
119
|
+
* @internal This is an implementation detail and should not be used directly.
|
|
120
|
+
*/
|
|
121
|
+
declare class Registration {
|
|
122
|
+
classConstructor: Constructor;
|
|
123
|
+
scope: ServiceScope;
|
|
124
|
+
inject: (string | Constructor)[];
|
|
125
|
+
properties: Record<string, string | Constructor>;
|
|
126
|
+
key?: string;
|
|
127
|
+
instance?: unknown;
|
|
128
|
+
/**
|
|
129
|
+
* Creates a new registration record.
|
|
130
|
+
*
|
|
131
|
+
* @param classConstructor - The class constructor function
|
|
132
|
+
* @param scope - Instance sharing behavior
|
|
133
|
+
* @param inject - Constructor parameter dependencies
|
|
134
|
+
* @param properties - Property injection mappings
|
|
135
|
+
* @param key - Optional string identifier
|
|
136
|
+
* @param instance - Optional pre-created instance
|
|
137
|
+
*/
|
|
138
|
+
constructor(classConstructor: Constructor, scope: ServiceScope, inject: (string | Constructor)[], properties?: Record<string, string | Constructor>, key?: string, instance?: unknown);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Registry that stores service registration metadata.
|
|
142
|
+
* Use this to register services before they can be resolved by a ServiceContainer.
|
|
143
|
+
*
|
|
144
|
+
* Typically you'll use the global `serviceCollection` instance rather than creating your own.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* // Register a service by type
|
|
148
|
+
* serviceCollection.registerByType(LoggerService, { inject: [] });
|
|
149
|
+
*
|
|
150
|
+
* // Register with a string key
|
|
151
|
+
* serviceCollection.register(CacheService, { key: 'cache', inject: [] });
|
|
152
|
+
*
|
|
153
|
+
* // Check if service is registered
|
|
154
|
+
* const reg = serviceCollection.tryGet(LoggerService);
|
|
155
|
+
* if (reg) {
|
|
156
|
+
* console.log('Logger is registered');
|
|
157
|
+
* }
|
|
158
|
+
*/
|
|
159
|
+
export declare class ServiceCollection {
|
|
160
|
+
private servicesByKey;
|
|
161
|
+
private servicesByClassName;
|
|
162
|
+
/**
|
|
163
|
+
* Registers a service with full configuration options.
|
|
164
|
+
* The service will be resolvable by both its class name and optional key.
|
|
165
|
+
*
|
|
166
|
+
* @param constructor - The service class constructor
|
|
167
|
+
* @param options - Registration configuration
|
|
168
|
+
*/
|
|
169
|
+
register<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void;
|
|
170
|
+
/**
|
|
171
|
+
* Registers a service by its class type.
|
|
172
|
+
* The service will be resolvable by its class constructor.
|
|
173
|
+
*
|
|
174
|
+
* @param constructor - The service class constructor
|
|
175
|
+
* @param options - Optional registration configuration
|
|
176
|
+
*/
|
|
177
|
+
registerByType<T extends object>(constructor: Constructor<T>, options?: RegistrationOptions): void;
|
|
178
|
+
private checkNameCollision;
|
|
179
|
+
private validateRegistration;
|
|
180
|
+
/**
|
|
181
|
+
* Attempts to retrieve a service registration.
|
|
182
|
+
* Returns undefined if the service is not registered.
|
|
183
|
+
*
|
|
184
|
+
* @param key - Either a string key or class constructor
|
|
185
|
+
* @returns The registration or undefined
|
|
186
|
+
*/
|
|
187
|
+
tryGet<T extends object>(key: string | Constructor<T>): Registration | undefined;
|
|
188
|
+
/**
|
|
189
|
+
* Retrieves a service registration or throws if not found.
|
|
190
|
+
*
|
|
191
|
+
* @param key - Either a string key or class constructor
|
|
192
|
+
* @returns The registration
|
|
193
|
+
* @throws Error if the service is not registered
|
|
194
|
+
*/
|
|
195
|
+
get<T extends object>(key: string | Constructor<T>): Registration;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* IoC container that resolves and manages service instances.
|
|
199
|
+
* Creates instances based on registrations in a ServiceCollection,
|
|
200
|
+
* handling constructor injection, property injection, and lifetime management.
|
|
201
|
+
*
|
|
202
|
+
* Typically you'll use the global `container` instance rather than creating your own.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* // Resolve a service by class
|
|
206
|
+
* const logger = container.resolve(LoggerService);
|
|
207
|
+
*
|
|
208
|
+
* // Resolve by string key
|
|
209
|
+
* const cache = container.resolve<CacheService>('primaryCache');
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* // Full setup workflow
|
|
213
|
+
* serviceCollection.register(UserService, {
|
|
214
|
+
* inject: [DatabaseConnection],
|
|
215
|
+
* scope: 'global'
|
|
216
|
+
* });
|
|
217
|
+
*
|
|
218
|
+
* const userService = container.resolve(UserService);
|
|
219
|
+
*/
|
|
220
|
+
export declare class ServiceContainer {
|
|
221
|
+
private serviceCollection;
|
|
222
|
+
private instances;
|
|
223
|
+
/**
|
|
224
|
+
* Creates a new container backed by the given service collection.
|
|
225
|
+
*
|
|
226
|
+
* @param serviceCollection - The registry containing service registrations
|
|
227
|
+
*/
|
|
228
|
+
constructor(serviceCollection: ServiceCollection);
|
|
229
|
+
/**
|
|
230
|
+
* Resolves a service instance by class type or string key.
|
|
231
|
+
* Creates the instance if not already cached (for global scope).
|
|
232
|
+
* Handles constructor and property injection automatically.
|
|
233
|
+
*
|
|
234
|
+
* @param keyOrType - Either a string key or class constructor
|
|
235
|
+
* @returns The resolved service instance
|
|
236
|
+
* @throws Error if the service is not registered
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* const service = container.resolve(MyService);
|
|
240
|
+
*/
|
|
241
|
+
resolve<T extends object>(keyOrType: string | Constructor<T>): T;
|
|
242
|
+
/**
|
|
243
|
+
* Creates a new instance of a service, resolving all constructor dependencies.
|
|
244
|
+
*/
|
|
245
|
+
private createInstance;
|
|
246
|
+
/**
|
|
247
|
+
* Injects dependencies into instance properties based on registration config.
|
|
248
|
+
*/
|
|
249
|
+
private injectFields;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Global service collection instance for registering services.
|
|
253
|
+
* Use this to register services that can later be resolved by the container.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* import { serviceCollection } from 'relaxjs';
|
|
257
|
+
*
|
|
258
|
+
* serviceCollection.register(MyService, { inject: [Dependency] });
|
|
259
|
+
*/
|
|
260
|
+
export declare const serviceCollection: ServiceCollection;
|
|
261
|
+
/**
|
|
262
|
+
* Global service container instance for resolving dependencies.
|
|
263
|
+
* Use this to obtain service instances with all dependencies injected.
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* import { container } from 'relaxjs';
|
|
267
|
+
*
|
|
268
|
+
* const service = container.resolve(MyService);
|
|
269
|
+
*/
|
|
270
|
+
export declare const container: ServiceContainer;
|
|
271
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type Constructor<T = object> = new (...args: any[]) => T;
|
|
2
|
+
export declare function Inject<T>(keyOrType?: string | Constructor<T>): PropertyDecorator & ParameterDecorator;
|
|
3
|
+
export interface RegistrationOptions {
|
|
4
|
+
scope?: ServiceScope;
|
|
5
|
+
key?: string;
|
|
6
|
+
instance?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export declare function setDebugFunc(func: (...msg: any[]) => {}): void;
|
|
9
|
+
export declare class ServiceCollection {
|
|
10
|
+
private servicesByKey;
|
|
11
|
+
private servicesByClassName;
|
|
12
|
+
register<T>(constructor: Constructor<T>, options: RegistrationOptions): void;
|
|
13
|
+
registerByType<T>(constructor: Constructor<T>, scope?: ServiceScope): void;
|
|
14
|
+
tryGet<T>(key: string | Constructor<T>): Registration | undefined;
|
|
15
|
+
get<T>(key: string | Constructor<T>): Registration;
|
|
16
|
+
}
|
|
17
|
+
export type ServiceScope = 'global' | 'closest';
|
|
18
|
+
export declare function ContainerService<T>(key?: string, scope?: ServiceScope): (target: Constructor<T>) => void;
|
|
19
|
+
export declare class ServiceContainer {
|
|
20
|
+
private instances;
|
|
21
|
+
private serviceCollection;
|
|
22
|
+
constructor(serviceCollection: ServiceCollection);
|
|
23
|
+
resolve<T>(keyOrType: string | Constructor<T>): T;
|
|
24
|
+
enrich<T>(instance: T): void;
|
|
25
|
+
}
|
|
26
|
+
export declare let serviceCollection: ServiceCollection;
|
|
27
|
+
export declare let container: ServiceContainer;
|
|
28
|
+
declare class Registration {
|
|
29
|
+
classConstructor: Constructor;
|
|
30
|
+
scope: ServiceScope;
|
|
31
|
+
key?: string;
|
|
32
|
+
instance?: unknown;
|
|
33
|
+
constructor(classConstructor: Constructor, scope: ServiceScope, key?: string, instance?: unknown);
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
interface MetadataHandler {
|
|
3
|
+
defineMetadata(metadataKey: string | symbol, value: any, target: object, propertyKey?: string | symbol): void;
|
|
4
|
+
getMetadata(metadataKey: string | symbol, target: object, propertyKey?: string | symbol): any;
|
|
5
|
+
hasMetadata(metadataKey: string | symbol, target: object, propertyKey?: string | symbol): boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const reflect: MetadataHandler;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module SequentialId
|
|
3
|
+
* Generates compact, time-ordered unique identifiers suitable for distributed systems.
|
|
4
|
+
*
|
|
5
|
+
* IDs are structured to be:
|
|
6
|
+
* - Unique across multiple clients (via baseId)
|
|
7
|
+
* - Time-sortable (timestamp is the most significant bits)
|
|
8
|
+
* - Compact (Base36 encoding produces short strings)
|
|
9
|
+
*
|
|
10
|
+
* Bit allocation (58 bits total):
|
|
11
|
+
* - 30 bits for timestamp (seconds since January 1, 2025)
|
|
12
|
+
* - 8 bits for per-second counter (supports 256 IDs/second)
|
|
13
|
+
* - 20 bits for client/endpoint identifier (supports ~1M unique sources)
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Generates a unique, time-ordered sequential ID.
|
|
17
|
+
*
|
|
18
|
+
* The ID combines a timestamp, per-second counter, and client identifier
|
|
19
|
+
* into a compact Base36 string. IDs generated later will sort after earlier IDs,
|
|
20
|
+
* making them suitable for ordered collections.
|
|
21
|
+
*
|
|
22
|
+
* @param baseId - Unique identifier for the client/endpoint (0 to 1,048,575).
|
|
23
|
+
* Use different baseIds for different servers or processes to
|
|
24
|
+
* avoid collisions.
|
|
25
|
+
* @returns Base36 encoded string representing the unique ID
|
|
26
|
+
* @throws Error if baseId is out of valid range
|
|
27
|
+
* @throws Error if more than 256 IDs are generated in a single second
|
|
28
|
+
* @throws Error if timestamp exceeds range (after year 2045)
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Generate ID for server instance 1
|
|
32
|
+
* const id1 = generateSequentialId(1);
|
|
33
|
+
* // Returns something like: 'k2j8m3n5p'
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // Different servers use different baseIds
|
|
37
|
+
* const SERVER_ID = parseInt(process.env.SERVER_ID || '0');
|
|
38
|
+
* const orderId = generateSequentialId(SERVER_ID);
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // IDs are time-sortable
|
|
42
|
+
* const id1 = generateSequentialId(0);
|
|
43
|
+
* await delay(1000);
|
|
44
|
+
* const id2 = generateSequentialId(0);
|
|
45
|
+
* console.log(id1 < id2); // true (lexicographic comparison works)
|
|
46
|
+
*/
|
|
47
|
+
export declare function generateSequentialId(baseId: number): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CompiledTemplate } from './MustardParser';
|
|
2
|
+
import { PipeRegistry } from './pipes';
|
|
3
|
+
/**
|
|
4
|
+
* Main template engine that brings together parsing, rendering and pipe functions
|
|
5
|
+
* Use this as the main entry point for template operations
|
|
6
|
+
*/
|
|
7
|
+
export declare class Mustard {
|
|
8
|
+
private parser;
|
|
9
|
+
private pipeRegistry;
|
|
10
|
+
private templateCache;
|
|
11
|
+
constructor(customPipeRegistry?: PipeRegistry);
|
|
12
|
+
/**
|
|
13
|
+
* Render a template with the given context
|
|
14
|
+
*/
|
|
15
|
+
render(template: string, context: Record<string, any>): string;
|
|
16
|
+
/**
|
|
17
|
+
* Get a compiled template function
|
|
18
|
+
*/
|
|
19
|
+
getTemplate(template: string): CompiledTemplate;
|
|
20
|
+
/**
|
|
21
|
+
* Register a custom pipe function
|
|
22
|
+
*/
|
|
23
|
+
registerPipe(name: string, fn: (value: any, ...args: any[]) => any): void;
|
|
24
|
+
/**
|
|
25
|
+
* Clear the template cache
|
|
26
|
+
*/
|
|
27
|
+
clearCache(): void;
|
|
28
|
+
}
|
|
29
|
+
export declare function bindFunctions(context: Record<string, any>, functions: Record<string, Function>): Record<string, any>;
|
|
30
|
+
export declare function createEngine(customPipes?: Record<string, (value: any, ...args: any[]) => any>): Mustard;
|