@v-ibe/core 0.1.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 +40 -0
- package/dist/DI/__tests__/scoped-container-dependencies.test.d.ts +1 -0
- package/dist/DI/bootstrap.d.ts +18 -0
- package/dist/DI/decorators/inject.d.ts +37 -0
- package/dist/DI/decorators/inject.js +45 -0
- package/dist/DI/decorators/service.d.ts +24 -0
- package/dist/DI/decorators/service.js +13 -0
- package/dist/DI/di-container.d.ts +53 -0
- package/dist/DI/di-container.js +158 -0
- package/dist/DI/lifecycle.d.ts +37 -0
- package/dist/DI/lifecycle.js +6 -0
- package/dist/DI/scoped-container.d.ts +68 -0
- package/dist/DI/scoped-container.js +193 -0
- package/dist/DI/service-metadata.d.ts +32 -0
- package/dist/DI/service-metadata.js +31 -0
- package/dist/DI/types.d.ts +4 -0
- package/dist/behaviors/__tests__/behavior-system.test.d.ts +1 -0
- package/dist/behaviors/behavior-manager.d.ts +60 -0
- package/dist/behaviors/behavior-manager.js +131 -0
- package/dist/behaviors/behavior-registry.d.ts +68 -0
- package/dist/behaviors/behavior-registry.js +105 -0
- package/dist/behaviors/constants.d.ts +16 -0
- package/dist/behaviors/constants.js +8 -0
- package/dist/behaviors/decorators.d.ts +87 -0
- package/dist/behaviors/decorators.js +46 -0
- package/dist/behaviors/index.d.ts +4 -0
- package/dist/components/__tests__/host.test.d.ts +1 -0
- package/dist/components/app-tree.d.ts +49 -0
- package/dist/components/app-tree.js +122 -0
- package/dist/components/base-component.d.ts +85 -0
- package/dist/components/base-component.js +438 -0
- package/dist/components/decorators/component.d.ts +27 -0
- package/dist/components/decorators/component.js +47 -0
- package/dist/components/decorators/prop.d.ts +14 -0
- package/dist/components/decorators/prop.js +37 -0
- package/dist/components/types.d.ts +26 -0
- package/dist/core.d.ts +23 -0
- package/dist/core.js +8 -0
- package/dist/custom-components/__tests__/for.test.d.ts +1 -0
- package/dist/custom-components/__tests__/show.test.d.ts +1 -0
- package/dist/custom-components/for.d.ts +58 -0
- package/dist/custom-components/for.js +313 -0
- package/dist/custom-components/index.d.ts +2 -0
- package/dist/custom-components/show.d.ts +78 -0
- package/dist/custom-components/show.js +88 -0
- package/dist/data-management/cache/cache-invalidate.decorator.d.ts +35 -0
- package/dist/data-management/cache/cache-invalidate.decorator.js +21 -0
- package/dist/data-management/cache/cache-metadata.d.ts +15 -0
- package/dist/data-management/cache/cache-provider.interface.d.ts +67 -0
- package/dist/data-management/cache/cache-tags.decorator.d.ts +52 -0
- package/dist/data-management/cache/cache-tags.decorator.js +13 -0
- package/dist/data-management/cache/cache-update.decorator.d.ts +28 -0
- package/dist/data-management/cache/cache-update.decorator.js +21 -0
- package/dist/data-management/cache/cache.decorator.d.ts +28 -0
- package/dist/data-management/cache/cache.decorator.js +13 -0
- package/dist/data-management/cache/index.d.ts +11 -0
- package/dist/data-management/cache/local-storage-cache.d.ts +40 -0
- package/dist/data-management/cache/local-storage-cache.js +268 -0
- package/dist/data-management/cache/memory-cache.d.ts +37 -0
- package/dist/data-management/cache/memory-cache.js +149 -0
- package/dist/data-management/cache/session-storage-cache.d.ts +35 -0
- package/dist/data-management/cache/session-storage-cache.js +242 -0
- package/dist/data-management/cache/ttl.decorator.d.ts +31 -0
- package/dist/data-management/cache/ttl.decorator.js +34 -0
- package/dist/data-management/decorators/consume.d.ts +29 -0
- package/dist/data-management/decorators/consume.js +28 -0
- package/dist/data-management/decorators/id.d.ts +28 -0
- package/dist/data-management/decorators/id.js +19 -0
- package/dist/data-management/decorators/model.d.ts +48 -0
- package/dist/data-management/decorators/model.js +24 -0
- package/dist/data-management/decorators/prop.d.ts +43 -0
- package/dist/data-management/decorators/prop.js +32 -0
- package/dist/data-management/index.d.ts +13 -0
- package/dist/data-management/store/json-to-model.d.ts +45 -0
- package/dist/data-management/store/json-to-model.js +36 -0
- package/dist/data-management/store/store.d.ts +108 -0
- package/dist/data-management/store/store.js +207 -0
- package/dist/data-management/store/types.d.ts +53 -0
- package/dist/events-handler/decorators/emit.d.ts +29 -0
- package/dist/events-handler/decorators/emit.js +51 -0
- package/dist/events-handler/event-decorators.d.ts +1 -0
- package/dist/events-handler/event-emitter.service.d.ts +21 -0
- package/dist/events-handler/event-emitter.service.js +85 -0
- package/dist/events-handler/event-types.d.ts +12 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +121 -0
- package/dist/jsx/dynamic/__tests__/granular-array-renderer.test.d.ts +1 -0
- package/dist/jsx/dynamic/__tests__/jsx-array-rendering.test.d.ts +1 -0
- package/dist/jsx/dynamic/array-renderer.d.ts +2 -0
- package/dist/jsx/dynamic/array-renderer.js +133 -0
- package/dist/jsx/dynamic/child-renderer.d.ts +1 -0
- package/dist/jsx/dynamic/child-renderer.js +180 -0
- package/dist/jsx/dynamic/dom-utils.d.ts +5 -0
- package/dist/jsx/dynamic/dom-utils.js +22 -0
- package/dist/jsx/dynamic/granular-array-renderer.d.ts +16 -0
- package/dist/jsx/dynamic/granular-array-renderer.js +153 -0
- package/dist/jsx/dynamic/node-renderer.d.ts +2 -0
- package/dist/jsx/dynamic/props-handler.d.ts +3 -0
- package/dist/jsx/dynamic/props-handler.js +281 -0
- package/dist/jsx/dynamic/text-renderer.d.ts +2 -0
- package/dist/jsx/jsx-dev-runtime.d.ts +2 -0
- package/dist/jsx/jsx-runtime.d.ts +3 -0
- package/dist/jsx/types.d.ts +35 -0
- package/dist/jsx/types.js +4 -0
- package/dist/jsx-dev-runtime.d.ts +2 -0
- package/dist/jsx-dev-runtime.js +8 -0
- package/dist/jsx-runtime.d.ts +2 -0
- package/dist/jsx-runtime.js +11 -0
- package/dist/reactivity/__tests__/context-stack.test.d.ts +1 -0
- package/dist/reactivity/__tests__/nested-effects-untrack.test.d.ts +22 -0
- package/dist/reactivity/context-scope.d.ts +57 -0
- package/dist/reactivity/context-scope.js +35 -0
- package/dist/reactivity/decorators/__tests__/ctx-integration.test.d.ts +5 -0
- package/dist/reactivity/decorators/__tests__/ctx-loop.test.d.ts +10 -0
- package/dist/reactivity/decorators/__tests__/state-intelligent.test.d.ts +1 -0
- package/dist/reactivity/decorators/computed.d.ts +6 -0
- package/dist/reactivity/decorators/computed.js +17 -0
- package/dist/reactivity/decorators/create-event-decorator.d.ts +5 -0
- package/dist/reactivity/decorators/create-event-decorator.js +28 -0
- package/dist/reactivity/decorators/ctx.d.ts +9 -0
- package/dist/reactivity/decorators/ctx.js +91 -0
- package/dist/reactivity/decorators/effect.d.ts +9 -0
- package/dist/reactivity/decorators/effect.js +24 -0
- package/dist/reactivity/decorators/resource.d.ts +48 -0
- package/dist/reactivity/decorators/resource.js +20 -0
- package/dist/reactivity/decorators/state.d.ts +8 -0
- package/dist/reactivity/decorators/state.js +68 -0
- package/dist/reactivity/decorators/store.d.ts +6 -0
- package/dist/reactivity/decorators/store.js +25 -0
- package/dist/reactivity/phase-scheduler.d.ts +81 -0
- package/dist/reactivity/phase-scheduler.js +88 -0
- package/dist/reactivity/phase-scheduler.test.d.ts +1 -0
- package/dist/reactivity/reactive-cache.d.ts +21 -0
- package/dist/reactivity/reactive-cache.js +31 -0
- package/dist/reactivity/reactive-cache.test.d.ts +1 -0
- package/dist/reactivity/reactive-context.d.ts +152 -0
- package/dist/reactivity/reactive-context.js +184 -0
- package/dist/reactivity/signals/__tests__/composicion-automatica.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/composite/nivel-1-estructura-basica.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/composite/nivel-2-registro-subscribers.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/composite/nivel-3-notificaciones-basicas.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/composite/nivel-4-comparacion-valores.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/composite/nivel-5-tracking-automatico.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/composite/nivel-6-anti-glitch.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/composite/nivel-7-objetos-anidados.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/composite/nivel-8-observable-array-support.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/composite-shallow-tracking.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/effect.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/reactive-array/nivel-1-estructura-basica.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/reactive-array/nivel-2-metodos-mutadores.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/reactive-array/nivel-3-tracking-por-indice.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/reactive-array/nivel-4-tracking-length.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/reactive-array/nivel-5-tracking-mutation.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/reactive-array/nivel-6-metodos-no-mutadores.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/reactive-array/nivel-7-composicion-bidireccional.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/reactive-array/nivel-8-proxies.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/reactive-array/nivel-9-derived-cache-optimization.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/resource.test.d.ts +1 -0
- package/dist/reactivity/signals/__tests__/signal.test.d.ts +1 -0
- package/dist/reactivity/signals/array-strategies.d.ts +120 -0
- package/dist/reactivity/signals/array-strategies.js +261 -0
- package/dist/reactivity/signals/composite.d.ts +89 -0
- package/dist/reactivity/signals/composite.js +145 -0
- package/dist/reactivity/signals/computed.d.ts +61 -0
- package/dist/reactivity/signals/computed.js +107 -0
- package/dist/reactivity/signals/computed.test.d.ts +1 -0
- package/dist/reactivity/signals/derived.d.ts +10 -0
- package/dist/reactivity/signals/derived.js +24 -0
- package/dist/reactivity/signals/effect.d.ts +27 -0
- package/dist/reactivity/signals/effect.js +46 -0
- package/dist/reactivity/signals/event.d.ts +9 -0
- package/dist/reactivity/signals/event.js +15 -0
- package/dist/reactivity/signals/reactive-array.d.ts +133 -0
- package/dist/reactivity/signals/reactive-array.js +490 -0
- package/dist/reactivity/signals/reactive-proxy.d.ts +54 -0
- package/dist/reactivity/signals/reactive-proxy.js +299 -0
- package/dist/reactivity/signals/reactive-tracking.test.d.ts +1 -0
- package/dist/reactivity/signals/resource.d.ts +9 -0
- package/dist/reactivity/signals/resource.js +58 -0
- package/dist/reactivity/signals/signal.d.ts +39 -0
- package/dist/reactivity/signals/signal.js +56 -0
- package/dist/reactivity/signals/subscription-management.test.d.ts +1 -0
- package/dist/reactivity/types.d.ts +12 -0
- package/dist/router/__tests__/link-behavior-active-class.test.d.ts +1 -0
- package/dist/router/__tests__/loop-detector.test.d.ts +1 -0
- package/dist/router/__tests__/params-container-resolution.test.d.ts +1 -0
- package/dist/router/__tests__/router-generated-routes.test.d.ts +1 -0
- package/dist/router/__tests__/router-params-granular.test.d.ts +1 -0
- package/dist/router/__tests__/router-params-simple.test.d.ts +1 -0
- package/dist/router/__tests__/router-query-params.test.d.ts +1 -0
- package/dist/router/__tests__/router-route-candidates.test.d.ts +1 -0
- package/dist/router/__tests__/routeview-app-articles.test.d.ts +1 -0
- package/dist/router/__tests__/routeview-debug.test.d.ts +1 -0
- package/dist/router/__tests__/routeview-integration.test.d.ts +1 -0
- package/dist/router/__tests__/routeview-this.test.d.ts +1 -0
- package/dist/router/decorators/base-policy.d.ts +141 -0
- package/dist/router/decorators/base-policy.js +63 -0
- package/dist/router/decorators/index.d.ts +6 -0
- package/dist/router/decorators/params.d.ts +31 -0
- package/dist/router/decorators/params.js +97 -0
- package/dist/router/decorators/route-metadata.d.ts +11 -0
- package/dist/router/decorators/route-metadata.js +23 -0
- package/dist/router/decorators/route.d.ts +39 -0
- package/dist/router/decorators/route.js +7 -0
- package/dist/router/link.behavior.d.ts +87 -0
- package/dist/router/link.behavior.js +227 -0
- package/dist/router/policy-evaluator.d.ts +81 -0
- package/dist/router/policy-evaluator.js +209 -0
- package/dist/router/route-view.d.ts +56 -0
- package/dist/router/route-view.js +156 -0
- package/dist/router/router.d.ts +67 -0
- package/dist/router/router.js +308 -0
- package/dist/router/static-analysis/index.d.ts +37 -0
- package/dist/router/static-analysis/parser.d.ts +14 -0
- package/dist/router/static-analysis/parser.js +147 -0
- package/dist/router/static-analysis/scanner.d.ts +27 -0
- package/dist/router/static-analysis/scanner.js +91 -0
- package/dist/router/trie.d.ts +14 -0
- package/dist/router/trie.js +126 -0
- package/dist/router/trie.types.d.ts +36 -0
- package/dist/styles/base-style-sheet.d.ts +96 -0
- package/dist/styles/base-style-sheet.js +149 -0
- package/dist/styles/decorators/factories.d.ts +76 -0
- package/dist/styles/decorators/factories.js +11 -0
- package/dist/styles/decorators/keyframes.d.ts +238 -0
- package/dist/styles/decorators/keyframes.js +79 -0
- package/dist/styles/decorators/rule.d.ts +177 -0
- package/dist/styles/decorators/rule.js +72 -0
- package/dist/styles/decorators/scope.d.ts +66 -0
- package/dist/styles/decorators/scope.js +17 -0
- package/dist/styles/decorators/style.d.ts +1 -0
- package/dist/styles/decorators/style.js +20 -0
- package/dist/styles/decorators/useStyles.d.ts +5 -0
- package/dist/styles/decorators/useStyles.js +29 -0
- package/dist/styles/global-styles-registry.d.ts +72 -0
- package/dist/styles/global-styles-registry.js +155 -0
- package/dist/types.d.ts +1 -0
- package/dist/vite-plugins/__tests__/jsx-control-flow-transform.test.d.ts +1 -0
- package/dist/vite-plugins/index.d.ts +4 -0
- package/dist/vite-plugins/index.js +10 -0
- package/dist/vite-plugins/jsx-contextual.d.ts +7 -0
- package/dist/vite-plugins/jsx-contextual.js +53 -0
- package/dist/vite-plugins/jsx-control-flow-transform.d.ts +60 -0
- package/dist/vite-plugins/jsx-control-flow-transform.js +180 -0
- package/dist/vite-plugins/jsx-signals.d.ts +2 -0
- package/dist/vite-plugins/jsx-signals.js +124 -0
- package/dist/vite-plugins/router/route-generator-plugin.d.ts +63 -0
- package/dist/vite-plugins/router/route-generator-plugin.js +310 -0
- package/package.json +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Julian Vargas
|
|
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,40 @@
|
|
|
1
|
+
# v-ibe
|
|
2
|
+
|
|
3
|
+
Modern framework for single page applications.
|
|
4
|
+
|
|
5
|
+
> **Alpha** — Core is stable but the API may change before 1.0. Not recommended for production yet.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**v-ibe** is an opinionated front-end framework for building SPAs using persistent class-based components, signals, and direct DOM updates. No virtual DOM, no hooks, no re-renders.
|
|
10
|
+
|
|
11
|
+
## Hello World
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
@Component()
|
|
15
|
+
export class HelloWorld extends BaseComponent {
|
|
16
|
+
@State name = 'World';
|
|
17
|
+
|
|
18
|
+
view() {
|
|
19
|
+
return (
|
|
20
|
+
<h1 onClick={() => this.name = 'Signals'}>
|
|
21
|
+
Hello {this.name}
|
|
22
|
+
</h1>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @v-ibe/core
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Documentation
|
|
35
|
+
|
|
36
|
+
[https://v-ibe.com](https://v-ibe.com)
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootstrap function to register all services marked with @Service decorator
|
|
3
|
+
* and initialize them in topological order.
|
|
4
|
+
*
|
|
5
|
+
* This should be called once at application startup, before rendering components.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { bootstrap } from './framework';
|
|
10
|
+
*
|
|
11
|
+
* // Register all services and bootstrap
|
|
12
|
+
* await bootstrap();
|
|
13
|
+
*
|
|
14
|
+
* // Now render your app
|
|
15
|
+
* document.getElementById('root')!.innerHTML = '<my-app></my-app>';
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function bootstrap(): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Constructor } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Decorator to inject a service dependency from the global DI container
|
|
4
|
+
*
|
|
5
|
+
* Works by creating a lazy getter that retrieves the service from the container
|
|
6
|
+
* associated with the instance. The value is cached after first access.
|
|
7
|
+
*
|
|
8
|
+
* @param ctor - Constructor of the service to inject
|
|
9
|
+
*
|
|
10
|
+
* @example In a service
|
|
11
|
+
* ```typescript
|
|
12
|
+
* @Service
|
|
13
|
+
* class AuthService {
|
|
14
|
+
* @Inject(HttpClient) http!: HttpClient;
|
|
15
|
+
* @Inject(ConfigService) config!: ConfigService;
|
|
16
|
+
*
|
|
17
|
+
* async login(credentials: Credentials) {
|
|
18
|
+
* const url = this.config.getApiUrl();
|
|
19
|
+
* return this.http.post(url, credentials);
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example In a component
|
|
25
|
+
* ```typescript
|
|
26
|
+
* @Component
|
|
27
|
+
* class MyComponent extends BaseComponent {
|
|
28
|
+
* @Inject(Router) router!: Router;
|
|
29
|
+
* @Inject(AuthService) auth!: AuthService;
|
|
30
|
+
*
|
|
31
|
+
* view() {
|
|
32
|
+
* return <div>Usuario: {this.auth.currentUser}</div>;
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function Inject(ctor: Constructor): (_: undefined, ctx: ClassFieldDecoratorContext) => void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { DEPENDENCIES_KEY } from "./service.js";
|
|
2
|
+
function Inject(ctor) {
|
|
3
|
+
return function(_, ctx) {
|
|
4
|
+
if (ctx.kind !== "field") {
|
|
5
|
+
throw new Error("@Inject solo puede usarse en fields");
|
|
6
|
+
}
|
|
7
|
+
if (!ctx.metadata[DEPENDENCIES_KEY]) {
|
|
8
|
+
ctx.metadata[DEPENDENCIES_KEY] = /* @__PURE__ */ new Set();
|
|
9
|
+
}
|
|
10
|
+
ctx.metadata[DEPENDENCIES_KEY].add(ctor);
|
|
11
|
+
ctx.addInitializer(function() {
|
|
12
|
+
const privateKey = Symbol(`__injected_${String(ctx.name)}`);
|
|
13
|
+
Object.defineProperty(this, ctx.name, {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
configurable: true,
|
|
16
|
+
get() {
|
|
17
|
+
if (this[privateKey]) {
|
|
18
|
+
return this[privateKey];
|
|
19
|
+
}
|
|
20
|
+
const container = this.__container;
|
|
21
|
+
if (!container) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`@Inject(${ctor.name}): No container found on ${this.constructor?.name || "unknown"}. Ensure this instance is within a component tree that provides ${ctor.name}.`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
const inst = container.get(ctor);
|
|
27
|
+
Object.defineProperty(this, ctx.name, {
|
|
28
|
+
value: inst,
|
|
29
|
+
writable: true,
|
|
30
|
+
// ← Permitir override en tests
|
|
31
|
+
configurable: true
|
|
32
|
+
// ← Permitir redefinir en tests
|
|
33
|
+
});
|
|
34
|
+
return inst;
|
|
35
|
+
},
|
|
36
|
+
set(value) {
|
|
37
|
+
this[privateKey] = value;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
Inject
|
|
45
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Constructor } from '../types';
|
|
2
|
+
declare const DEPENDENCIES_KEY: unique symbol;
|
|
3
|
+
/**
|
|
4
|
+
* Decorator to mark a class as a Service
|
|
5
|
+
* Only stores metadata - actual registration happens when container is created
|
|
6
|
+
* All services are bootstrapped eagerly during container bootstrap
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* @Service
|
|
11
|
+
* class AuthService {
|
|
12
|
+
* @Inject(HttpClient) http!: HttpClient;
|
|
13
|
+
*
|
|
14
|
+
* async login(credentials: Credentials) {
|
|
15
|
+
* return this.http.post('/auth/login', credentials);
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function Service<T extends Constructor>(ctor: T, ctx: ClassDecoratorContext): T;
|
|
21
|
+
/**
|
|
22
|
+
* Export the dependencies key for use by @Inject decorator
|
|
23
|
+
*/
|
|
24
|
+
export { DEPENDENCIES_KEY };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { registerServiceMetadata } from "../service-metadata.js";
|
|
2
|
+
const DEPENDENCIES_KEY = Symbol("dependencies");
|
|
3
|
+
function Service(ctor, ctx) {
|
|
4
|
+
const dependencies = ctx.metadata[DEPENDENCIES_KEY];
|
|
5
|
+
registerServiceMetadata(ctor, {
|
|
6
|
+
dependencies: dependencies || /* @__PURE__ */ new Set()
|
|
7
|
+
});
|
|
8
|
+
return ctor;
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
DEPENDENCIES_KEY,
|
|
12
|
+
Service
|
|
13
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Constructor } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Singleton global dependency injection container
|
|
4
|
+
*
|
|
5
|
+
* Uses topological sort (Kahn's algorithm) to bootstrap services in correct dependency order.
|
|
6
|
+
* All services are eagerly initialized during bootstrap.
|
|
7
|
+
*/
|
|
8
|
+
export declare class DIContainer {
|
|
9
|
+
#private;
|
|
10
|
+
/**
|
|
11
|
+
* Register a service constructor
|
|
12
|
+
*/
|
|
13
|
+
register(token: Constructor): void;
|
|
14
|
+
/**
|
|
15
|
+
* Register a dependency relationship between services
|
|
16
|
+
* @param parent - The service that depends on another
|
|
17
|
+
* @param dependency - The service that parent depends on
|
|
18
|
+
*/
|
|
19
|
+
registerDependency(parent: Constructor, dependency: Constructor): void;
|
|
20
|
+
/**
|
|
21
|
+
* Bootstrap all services in dependency order
|
|
22
|
+
* All services are eagerly initialized during bootstrap
|
|
23
|
+
* Each instance is associated with this container for property injection
|
|
24
|
+
*/
|
|
25
|
+
bootstrap(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Get the container associated with an instance
|
|
28
|
+
* Useful for property injection (fallback for @Inject)
|
|
29
|
+
*/
|
|
30
|
+
static getContainerForInstance(instance: any): DIContainer | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Get a service instance
|
|
33
|
+
* All services must be bootstrapped before calling get()
|
|
34
|
+
*/
|
|
35
|
+
get<T>(ctor: Constructor<T>): T;
|
|
36
|
+
/**
|
|
37
|
+
* Get all service instances
|
|
38
|
+
* Useful for collecting metadata from all services after bootstrap
|
|
39
|
+
*/
|
|
40
|
+
getAllInstances(): any[];
|
|
41
|
+
/**
|
|
42
|
+
* Check if bootstrap has been called
|
|
43
|
+
*/
|
|
44
|
+
get isReady(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Dispose all services and reset container
|
|
47
|
+
*/
|
|
48
|
+
dispose(): void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Global singleton container instance
|
|
52
|
+
*/
|
|
53
|
+
export declare const services: DIContainer;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { hasLifecycle } from "./lifecycle.js";
|
|
2
|
+
class DIContainer {
|
|
3
|
+
#singletons = /* @__PURE__ */ new Map();
|
|
4
|
+
#registered = /* @__PURE__ */ new Set();
|
|
5
|
+
// Dependency graph for topological sort
|
|
6
|
+
#dependencies = /* @__PURE__ */ new Map();
|
|
7
|
+
// What each service depends on
|
|
8
|
+
#dependents = /* @__PURE__ */ new Map();
|
|
9
|
+
// What depends on each service
|
|
10
|
+
#ready = false;
|
|
11
|
+
/**
|
|
12
|
+
* Register a service constructor
|
|
13
|
+
*/
|
|
14
|
+
register(token) {
|
|
15
|
+
this.#registered.add(token);
|
|
16
|
+
if (!this.#dependencies.has(token)) {
|
|
17
|
+
this.#dependencies.set(token, /* @__PURE__ */ new Set());
|
|
18
|
+
}
|
|
19
|
+
if (!this.#dependents.has(token)) {
|
|
20
|
+
this.#dependents.set(token, /* @__PURE__ */ new Set());
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Register a dependency relationship between services
|
|
25
|
+
* @param parent - The service that depends on another
|
|
26
|
+
* @param dependency - The service that parent depends on
|
|
27
|
+
*/
|
|
28
|
+
registerDependency(parent, dependency) {
|
|
29
|
+
if (!this.#registered.has(parent)) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`Cannot register dependency: ${parent.name} is not registered. Use @Service decorator first.`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if (!this.#registered.has(dependency)) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Cannot register dependency: ${dependency.name} is not registered. Use @Service decorator first.`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
if (!this.#dependencies.has(parent)) {
|
|
40
|
+
this.#dependencies.set(parent, /* @__PURE__ */ new Set());
|
|
41
|
+
}
|
|
42
|
+
this.#dependencies.get(parent).add(dependency);
|
|
43
|
+
if (!this.#dependents.has(dependency)) {
|
|
44
|
+
this.#dependents.set(dependency, /* @__PURE__ */ new Set());
|
|
45
|
+
}
|
|
46
|
+
this.#dependents.get(dependency).add(parent);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get bootstrap order using topological sort (Kahn's algorithm)
|
|
50
|
+
* This ensures dependencies are initialized before dependents
|
|
51
|
+
*/
|
|
52
|
+
async *#getBootstrapOrder() {
|
|
53
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
54
|
+
const queue = [];
|
|
55
|
+
for (const service of this.#registered) {
|
|
56
|
+
const deps = this.#dependencies.get(service) || /* @__PURE__ */ new Set();
|
|
57
|
+
inDegree.set(service, deps.size);
|
|
58
|
+
if (deps.size === 0) {
|
|
59
|
+
queue.push(service);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
while (queue.length > 0) {
|
|
63
|
+
const service = queue.shift();
|
|
64
|
+
yield service;
|
|
65
|
+
const dependents = this.#dependents.get(service) || /* @__PURE__ */ new Set();
|
|
66
|
+
for (const dependent of dependents) {
|
|
67
|
+
const newInDegree = inDegree.get(dependent) - 1;
|
|
68
|
+
inDegree.set(dependent, newInDegree);
|
|
69
|
+
if (newInDegree === 0) {
|
|
70
|
+
queue.push(dependent);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const remaining = Array.from(inDegree.entries()).filter(
|
|
75
|
+
([_, degree]) => degree > 0
|
|
76
|
+
);
|
|
77
|
+
if (remaining.length > 0) {
|
|
78
|
+
const cycleServices = remaining.map(([service]) => service.name).join(", ");
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Circular dependency detected. Services with unresolved dependencies: ${cycleServices}`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Bootstrap all services in dependency order
|
|
86
|
+
* All services are eagerly initialized during bootstrap
|
|
87
|
+
* Each instance is associated with this container for property injection
|
|
88
|
+
*/
|
|
89
|
+
async bootstrap() {
|
|
90
|
+
if (this.#ready) return;
|
|
91
|
+
for await (const ctor of this.#getBootstrapOrder()) {
|
|
92
|
+
const inst = new ctor();
|
|
93
|
+
inst.__container = this;
|
|
94
|
+
this.#singletons.set(ctor, inst);
|
|
95
|
+
if (hasLifecycle(inst)) {
|
|
96
|
+
await inst.onBootstrap();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
this.#ready = true;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get the container associated with an instance
|
|
103
|
+
* Useful for property injection (fallback for @Inject)
|
|
104
|
+
*/
|
|
105
|
+
static getContainerForInstance(instance) {
|
|
106
|
+
return instance.__container;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get a service instance
|
|
110
|
+
* All services must be bootstrapped before calling get()
|
|
111
|
+
*/
|
|
112
|
+
get(ctor) {
|
|
113
|
+
if (!this.#registered.has(ctor)) {
|
|
114
|
+
throw new Error(`Service not registered: ${ctor.name}`);
|
|
115
|
+
}
|
|
116
|
+
if (!this.#singletons.has(ctor)) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Service ${ctor.name} not found in singletons. Make sure bootstrap() has been called.`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return this.#singletons.get(ctor);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get all service instances
|
|
125
|
+
* Useful for collecting metadata from all services after bootstrap
|
|
126
|
+
*/
|
|
127
|
+
getAllInstances() {
|
|
128
|
+
return Array.from(this.#singletons.values());
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Check if bootstrap has been called
|
|
132
|
+
*/
|
|
133
|
+
get isReady() {
|
|
134
|
+
return this.#ready;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Dispose all services and reset container
|
|
138
|
+
*/
|
|
139
|
+
dispose() {
|
|
140
|
+
for (const instance of this.#singletons.values()) {
|
|
141
|
+
if (typeof instance.onDestroy === "function") {
|
|
142
|
+
try {
|
|
143
|
+
instance.onDestroy();
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error("[DIContainer] Error en onDestroy:", error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
this.#singletons.clear();
|
|
150
|
+
this.#registered.clear();
|
|
151
|
+
this.#dependencies.clear();
|
|
152
|
+
this.#dependents.clear();
|
|
153
|
+
this.#ready = false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
export {
|
|
157
|
+
DIContainer
|
|
158
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interfaz para servicios que requieren inicialización asíncrona
|
|
3
|
+
*
|
|
4
|
+
* Los servicios que implementan esta interfaz tendrán su método onBootstrap
|
|
5
|
+
* llamado automáticamente cuando el componente que los provee se monte.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* class Router implements LifeCycle {
|
|
10
|
+
* async onBootstrap() {
|
|
11
|
+
* await this.loadRoutes();
|
|
12
|
+
* console.log('Router initialized');
|
|
13
|
+
* }
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export interface LifeCycle {
|
|
18
|
+
/**
|
|
19
|
+
* Método llamado automáticamente durante el bootstrap del componente
|
|
20
|
+
* Permite inicialización asíncrona como cargar configuración, conectar a APIs, etc.
|
|
21
|
+
*/
|
|
22
|
+
onBootstrap(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Type guard para verificar si un objeto implementa la interfaz LifeCycle
|
|
26
|
+
*
|
|
27
|
+
* @param obj - Objeto a verificar
|
|
28
|
+
* @returns true si el objeto tiene un método onBootstrap que es una función
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* if (hasLifecycle(service)) {
|
|
33
|
+
* await service.onBootstrap();
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function hasLifecycle(obj: any): obj is LifeCycle;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Constructor } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Hierarchical DI container that supports parent-chain resolution.
|
|
4
|
+
*
|
|
5
|
+
* Each component with `services: [...]` in its @Component config
|
|
6
|
+
* gets a ScopedContainer. Services not found locally are resolved
|
|
7
|
+
* by walking up the parent chain.
|
|
8
|
+
*
|
|
9
|
+
* Uses topological sort (Kahn's algorithm) to bootstrap services
|
|
10
|
+
* in correct dependency order — same algorithm as DIContainer.
|
|
11
|
+
*/
|
|
12
|
+
export declare class ScopedContainer {
|
|
13
|
+
#private;
|
|
14
|
+
constructor(parent?: ScopedContainer);
|
|
15
|
+
/**
|
|
16
|
+
* Register a service constructor in this scope
|
|
17
|
+
*/
|
|
18
|
+
register(token: Constructor): void;
|
|
19
|
+
/**
|
|
20
|
+
* Register a dependency relationship between services in this scope.
|
|
21
|
+
* Only for dependencies that are BOTH registered locally.
|
|
22
|
+
* Cross-scope dependencies are resolved via parent chain at get() time.
|
|
23
|
+
*/
|
|
24
|
+
registerDependency(parent: Constructor, dependency: Constructor): void;
|
|
25
|
+
/**
|
|
26
|
+
* Bootstrap all locally registered services in dependency order.
|
|
27
|
+
* Each instance is associated with this container via __container.
|
|
28
|
+
*
|
|
29
|
+
* Services with async onBootstrap() are launched as fire-and-forget.
|
|
30
|
+
* Use the reactive pattern (@Store with isLoading) to handle async state.
|
|
31
|
+
*/
|
|
32
|
+
bootstrapSync(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Bootstrap all locally registered services, awaiting async onBootstrap hooks.
|
|
35
|
+
* Use this in the DOM init() path where async is available.
|
|
36
|
+
*/
|
|
37
|
+
bootstrap(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a service by walking up the parent chain.
|
|
40
|
+
* Checks local scope first, then parent, then grandparent, etc.
|
|
41
|
+
*/
|
|
42
|
+
get<T>(ctor: Constructor<T>): T;
|
|
43
|
+
/**
|
|
44
|
+
* Check if a service exists in this scope or any parent scope.
|
|
45
|
+
*/
|
|
46
|
+
has(ctor: Constructor): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Check if a service is registered locally (not including parents).
|
|
49
|
+
*/
|
|
50
|
+
hasLocal(ctor: Constructor): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Check if bootstrap has been called.
|
|
53
|
+
*/
|
|
54
|
+
get isReady(): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Get the parent container.
|
|
57
|
+
*/
|
|
58
|
+
get parent(): ScopedContainer | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Get all locally instantiated service instances.
|
|
61
|
+
*/
|
|
62
|
+
getAllInstances(): any[];
|
|
63
|
+
/**
|
|
64
|
+
* Dispose all local services and reset container.
|
|
65
|
+
* Calls onDestroy() on services that implement it.
|
|
66
|
+
*/
|
|
67
|
+
dispose(): void;
|
|
68
|
+
}
|