@kaokei/use-vue-service 3.0.1 → 4.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/README.md CHANGED
@@ -13,12 +13,19 @@
13
13
 
14
14
  灵感来自 angular 中的服务的概念。在 angular 中不需要全局唯一的数据源 store。而是通过声明服务,以及向组件中注入服务来达到数据管理以及数据共享的。
15
15
 
16
- 本库也是实现了类似的效果,可以通过依赖注入实现面向服务编程、实现领域驱动开发。从而可以代替 vuex。
16
+ 本库也是实现了类似的效果,可以通过依赖注入实现面向服务编程、实现领域驱动开发。从而可以代替 vuex/pinia
17
17
 
18
18
  本库通过类来声明服务,对 typescript 支持非常棒。
19
19
 
20
- - [入门指南](./docs/guide/README.md)
21
- - [API 文档](./docs/api/README.md)
20
+ - [入门指南](./docs/guide/index.md)
21
+ - [API 文档](./docs/api/index.md)
22
22
  - [博客文章](./docs/note/01.父组件与子组件的理解.md)
23
23
  - [codesandbox example](https://codesandbox.io/s/di-playground-zjnyv)
24
24
  - [online demo](https://use-vue-service.vercel.app/)
25
+
26
+ ## Todo List
27
+ 1. 优化@Computed
28
+ 5. 增加@Raw装饰器
29
+ 4. 更新hasOwn
30
+ 3. 发布@kaokei/di@5.0.3
31
+ 2. 评估是否需要@Watch/@Effect
@@ -1 +1,2 @@
1
- export declare function Computed(_: any, key: string, descriptor: PropertyDescriptor): PropertyDescriptor;
1
+ export declare function Computed(): (value: (this: any) => any, context: ClassGetterDecoratorContext) => (this: any) => any;
2
+ export declare function Computed(value: (this: any) => any, context: ClassGetterDecoratorContext): (this: any) => any;
@@ -1 +1,2 @@
1
- export declare function Computed(_: any, key: string, descriptor: PropertyDescriptor): PropertyDescriptor;
1
+ export declare function Computed(): (value: (this: any) => any, context: ClassGetterDecoratorContext) => (this: any) => any;
2
+ export declare function Computed(value: (this: any) => any, context: ClassGetterDecoratorContext): (this: any) => any;
@@ -1,9 +1,7 @@
1
- import { Token } from '@kaokei/di';
2
- import { ComponentInternalInstance } from 'vue';
1
+ import { Token, Container } from '@kaokei/di';
2
+ import { InjectionKey } from 'vue';
3
3
  import { FindChildService, FindChildrenServices } from './interface.ts';
4
- export declare const CURRENT_COMPONENT: Token<ComponentInternalInstance>;
5
4
  export declare const FIND_CHILD_SERVICE: Token<FindChildService>;
6
5
  export declare const FIND_CHILDREN_SERVICES: Token<FindChildrenServices>;
7
6
  export declare const SCOPE_KEY: unique symbol;
8
- export declare const CONTAINER_TOKEN = "USE_VUE_SERVICE_CONTAINER_TOKEN";
9
- export declare const DEFAULT_CONTAINER: import('@kaokei/di').Container;
7
+ export declare const CONTAINER_TOKEN: InjectionKey<Container>;
@@ -1,9 +1,7 @@
1
- import { Token } from '@kaokei/di';
2
- import { ComponentInternalInstance } from 'vue';
1
+ import { Token, Container } from '@kaokei/di';
2
+ import { InjectionKey } from 'vue';
3
3
  import { FindChildService, FindChildrenServices } from './interface.ts';
4
- export declare const CURRENT_COMPONENT: Token<ComponentInternalInstance>;
5
4
  export declare const FIND_CHILD_SERVICE: Token<FindChildService>;
6
5
  export declare const FIND_CHILDREN_SERVICES: Token<FindChildrenServices>;
7
6
  export declare const SCOPE_KEY: unique symbol;
8
- export declare const CONTAINER_TOKEN = "USE_VUE_SERVICE_CONTAINER_TOKEN";
9
- export declare const DEFAULT_CONTAINER: import('@kaokei/di').Container;
7
+ export declare const CONTAINER_TOKEN: InjectionKey<Container>;
package/dist/core.d.cts CHANGED
@@ -1,14 +1,89 @@
1
1
  import { App } from 'vue';
2
2
  import { CommonToken } from '@kaokei/di';
3
3
  import { NewableProvider, FunctionProvider, Provider } from './interface.ts';
4
+ /**
5
+ * 从当前组件或最近的祖先组件的 DI 容器中获取服务实例。
6
+ *
7
+ * 查找顺序:
8
+ * 1. 先检查当前组件自身是否声明了容器(getCurrentContainer)
9
+ * 2. 如果没有,则沿组件树向上查找(getProvideContainer)
10
+ *
11
+ * @param token - 服务的标识符,可以是类本身(Newable)或 Token 实例
12
+ * @returns 对应 token 的服务实例
13
+ */
4
14
  export declare function useService<T>(token: CommonToken<T>): T;
5
- export declare function useRootService<T>(token: CommonToken<T>): T;
6
- export declare function useAppService<T>(token: CommonToken<T>, app: App): T;
15
+ /**
16
+ * 在当前组件中声明服务提供者。
17
+ *
18
+ * 行为逻辑:
19
+ * - 如果当前组件已经声明过容器(重复调用 declareProviders),则直接在已有容器上追加绑定。
20
+ * - 如果当前组件尚未声明容器,则:
21
+ * 1. 获取父级容器作为 parent
22
+ * 2. 创建一个子容器(继承父级容器的所有绑定)
23
+ * 3. 在子容器上绑定新的服务
24
+ * 4. 通过 Vue 的 provide 将子容器注入组件树
25
+ * 5. 在组件卸载时(onUnmounted)自动销毁子容器,清理资源
26
+ *
27
+ * @param providers - 服务提供者,支持类数组或函数两种形式
28
+ */
7
29
  export declare function declareProviders(providers: FunctionProvider): void;
8
30
  export declare function declareProviders(providers: NewableProvider): void;
31
+ export declare function declareProviders(providers: Provider): void;
32
+ /**
33
+ * 从全局根容器(ROOT_CONTAINER)中获取服务实例。
34
+ * 不依赖 Vue 组件树,可以在任何地方调用。
35
+ *
36
+ * @param token - 服务的标识符
37
+ * @returns 对应 token 的服务实例
38
+ */
39
+ export declare function useRootService<T>(token: CommonToken<T>): T;
40
+ /**
41
+ * 在全局根容器上声明服务提供者。
42
+ * 绑定的服务在整个应用中全局共享。
43
+ *
44
+ * @param providers - 服务提供者,支持类数组或函数两种形式
45
+ */
9
46
  export declare function declareRootProviders(providers: FunctionProvider): void;
10
47
  export declare function declareRootProviders(providers: NewableProvider): void;
48
+ export declare function declareRootProviders(providers: Provider): void;
49
+ /**
50
+ * 在指定 Vue App 实例的上下文中获取服务实例。
51
+ * 通过 app.runWithContext 确保 inject 能正确找到该 App 提供的容器。
52
+ * 适用于多 App 实例场景。
53
+ *
54
+ * @param token - 服务的标识符
55
+ * @param app - 目标 Vue App 实例
56
+ * @returns 对应 token 的服务实例
57
+ */
58
+ export declare function useAppService<T>(token: CommonToken<T>, app: App): T;
59
+ /**
60
+ * 在指定 Vue App 实例的上下文中声明服务提供者。
61
+ *
62
+ * 行为逻辑:
63
+ * - 如果该 App 已经有容器(之前调用过 declareAppProviders),则直接追加绑定。
64
+ * - 如果该 App 尚未有容器,则:
65
+ * 1. 以 ROOT_CONTAINER 为 parent 创建子容器
66
+ * 2. 绑定服务
67
+ * 3. 通过 app.provide 将容器注入该 App 的组件树
68
+ * 4. 在 App 卸载时自动销毁容器
69
+ *
70
+ * @param providers - 服务提供者,支持类数组或函数两种形式
71
+ * @param app - 目标 Vue App 实例
72
+ */
11
73
  export declare function declareAppProviders(providers: FunctionProvider, app: App): void;
12
74
  export declare function declareAppProviders(providers: NewableProvider, app: App): void;
13
75
  export declare function declareAppProviders(providers: Provider, app: App): void;
76
+ /**
77
+ * declareAppProviders 的 Vue 插件形式。
78
+ * 返回一个符合 Vue 插件接口的函数,可直接用于 app.use()。
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * const app = createApp(App);
83
+ * app.use(declareAppProvidersPlugin([ServiceA, ServiceB]));
84
+ * ```
85
+ *
86
+ * @param providers - 服务提供者
87
+ * @returns Vue 插件函数
88
+ */
14
89
  export declare function declareAppProvidersPlugin(providers: Provider): (app: App) => void;
package/dist/core.d.ts CHANGED
@@ -1,14 +1,89 @@
1
1
  import { App } from 'vue';
2
2
  import { CommonToken } from '@kaokei/di';
3
3
  import { NewableProvider, FunctionProvider, Provider } from './interface.ts';
4
+ /**
5
+ * 从当前组件或最近的祖先组件的 DI 容器中获取服务实例。
6
+ *
7
+ * 查找顺序:
8
+ * 1. 先检查当前组件自身是否声明了容器(getCurrentContainer)
9
+ * 2. 如果没有,则沿组件树向上查找(getProvideContainer)
10
+ *
11
+ * @param token - 服务的标识符,可以是类本身(Newable)或 Token 实例
12
+ * @returns 对应 token 的服务实例
13
+ */
4
14
  export declare function useService<T>(token: CommonToken<T>): T;
5
- export declare function useRootService<T>(token: CommonToken<T>): T;
6
- export declare function useAppService<T>(token: CommonToken<T>, app: App): T;
15
+ /**
16
+ * 在当前组件中声明服务提供者。
17
+ *
18
+ * 行为逻辑:
19
+ * - 如果当前组件已经声明过容器(重复调用 declareProviders),则直接在已有容器上追加绑定。
20
+ * - 如果当前组件尚未声明容器,则:
21
+ * 1. 获取父级容器作为 parent
22
+ * 2. 创建一个子容器(继承父级容器的所有绑定)
23
+ * 3. 在子容器上绑定新的服务
24
+ * 4. 通过 Vue 的 provide 将子容器注入组件树
25
+ * 5. 在组件卸载时(onUnmounted)自动销毁子容器,清理资源
26
+ *
27
+ * @param providers - 服务提供者,支持类数组或函数两种形式
28
+ */
7
29
  export declare function declareProviders(providers: FunctionProvider): void;
8
30
  export declare function declareProviders(providers: NewableProvider): void;
31
+ export declare function declareProviders(providers: Provider): void;
32
+ /**
33
+ * 从全局根容器(ROOT_CONTAINER)中获取服务实例。
34
+ * 不依赖 Vue 组件树,可以在任何地方调用。
35
+ *
36
+ * @param token - 服务的标识符
37
+ * @returns 对应 token 的服务实例
38
+ */
39
+ export declare function useRootService<T>(token: CommonToken<T>): T;
40
+ /**
41
+ * 在全局根容器上声明服务提供者。
42
+ * 绑定的服务在整个应用中全局共享。
43
+ *
44
+ * @param providers - 服务提供者,支持类数组或函数两种形式
45
+ */
9
46
  export declare function declareRootProviders(providers: FunctionProvider): void;
10
47
  export declare function declareRootProviders(providers: NewableProvider): void;
48
+ export declare function declareRootProviders(providers: Provider): void;
49
+ /**
50
+ * 在指定 Vue App 实例的上下文中获取服务实例。
51
+ * 通过 app.runWithContext 确保 inject 能正确找到该 App 提供的容器。
52
+ * 适用于多 App 实例场景。
53
+ *
54
+ * @param token - 服务的标识符
55
+ * @param app - 目标 Vue App 实例
56
+ * @returns 对应 token 的服务实例
57
+ */
58
+ export declare function useAppService<T>(token: CommonToken<T>, app: App): T;
59
+ /**
60
+ * 在指定 Vue App 实例的上下文中声明服务提供者。
61
+ *
62
+ * 行为逻辑:
63
+ * - 如果该 App 已经有容器(之前调用过 declareAppProviders),则直接追加绑定。
64
+ * - 如果该 App 尚未有容器,则:
65
+ * 1. 以 ROOT_CONTAINER 为 parent 创建子容器
66
+ * 2. 绑定服务
67
+ * 3. 通过 app.provide 将容器注入该 App 的组件树
68
+ * 4. 在 App 卸载时自动销毁容器
69
+ *
70
+ * @param providers - 服务提供者,支持类数组或函数两种形式
71
+ * @param app - 目标 Vue App 实例
72
+ */
11
73
  export declare function declareAppProviders(providers: FunctionProvider, app: App): void;
12
74
  export declare function declareAppProviders(providers: NewableProvider, app: App): void;
13
75
  export declare function declareAppProviders(providers: Provider, app: App): void;
76
+ /**
77
+ * declareAppProviders 的 Vue 插件形式。
78
+ * 返回一个符合 Vue 插件接口的函数,可直接用于 app.use()。
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * const app = createApp(App);
83
+ * app.use(declareAppProvidersPlugin([ServiceA, ServiceB]));
84
+ * ```
85
+ *
86
+ * @param providers - 服务提供者
87
+ * @returns Vue 插件函数
88
+ */
14
89
  export declare function declareAppProvidersPlugin(providers: Provider): (app: App) => void;
@@ -0,0 +1,2 @@
1
+ import { Container } from '@kaokei/di';
2
+ export declare function createContainer(parent?: Container): Container;
@@ -0,0 +1,2 @@
1
+ import { Container } from '@kaokei/di';
2
+ export declare function createContainer(parent?: Container): Container;
@@ -0,0 +1,41 @@
1
+ import { EffectScope } from 'vue';
2
+ /**
3
+ * 被装饰方法的类型约束:
4
+ * - 方法体内应返回 void(装饰器会接管返回值)
5
+ * - 但方法签名可以声明返回 EffectScope,以便调用侧获得正确的类型推断
6
+ *
7
+ * 已知限制:
8
+ * TypeScript 装饰器目前无法自动修改被装饰方法的返回类型。
9
+ * 原始方法返回 void,但装饰器在运行时将返回值替换为 EffectScope。
10
+ * 因此调用侧默认推断为 void,无法直接访问 EffectScope 的属性(如 stop())。
11
+ *
12
+ * 方案 1(推荐):在调用侧强制类型转换
13
+ * 实际业务中通常只需要调用 stop() 方法来清理副作用,直接在调用侧做类型断言即可:
14
+ * ```ts
15
+ * const scope = reactiveDemo.setup() as any;
16
+ * scope.stop();
17
+ * // 或者更精确的类型转换:
18
+ * const scope = reactiveDemo.setup() as unknown as EffectScope;
19
+ * scope.stop();
20
+ * ```
21
+ *
22
+ * 方案 2:显式声明方法返回类型 + return 占位
23
+ * 在被装饰方法上声明返回 EffectScope,并在方法体末尾添加占位 return,
24
+ * 这样调用侧可以直接获得正确的类型推断:
25
+ * ```ts
26
+ * import type { EffectScope } from 'vue';
27
+ *
28
+ * class DemoService {
29
+ * @RunInScope
30
+ * public setup(): EffectScope {
31
+ * watchEffect(() => { ... });
32
+ * return null as any;
33
+ * // 或者:return null as unknown as EffectScope;
34
+ * }
35
+ * }
36
+ * ```
37
+ */
38
+ type DecorableMethod = (this: any, ...args: any[]) => void | EffectScope;
39
+ export declare function RunInScope(): (value: DecorableMethod, context: ClassMethodDecoratorContext) => (this: any, ...args: any[]) => EffectScope;
40
+ export declare function RunInScope(value: DecorableMethod, context: ClassMethodDecoratorContext): (this: any, ...args: any[]) => EffectScope;
41
+ export {};
@@ -0,0 +1,41 @@
1
+ import { EffectScope } from 'vue';
2
+ /**
3
+ * 被装饰方法的类型约束:
4
+ * - 方法体内应返回 void(装饰器会接管返回值)
5
+ * - 但方法签名可以声明返回 EffectScope,以便调用侧获得正确的类型推断
6
+ *
7
+ * 已知限制:
8
+ * TypeScript 装饰器目前无法自动修改被装饰方法的返回类型。
9
+ * 原始方法返回 void,但装饰器在运行时将返回值替换为 EffectScope。
10
+ * 因此调用侧默认推断为 void,无法直接访问 EffectScope 的属性(如 stop())。
11
+ *
12
+ * 方案 1(推荐):在调用侧强制类型转换
13
+ * 实际业务中通常只需要调用 stop() 方法来清理副作用,直接在调用侧做类型断言即可:
14
+ * ```ts
15
+ * const scope = reactiveDemo.setup() as any;
16
+ * scope.stop();
17
+ * // 或者更精确的类型转换:
18
+ * const scope = reactiveDemo.setup() as unknown as EffectScope;
19
+ * scope.stop();
20
+ * ```
21
+ *
22
+ * 方案 2:显式声明方法返回类型 + return 占位
23
+ * 在被装饰方法上声明返回 EffectScope,并在方法体末尾添加占位 return,
24
+ * 这样调用侧可以直接获得正确的类型推断:
25
+ * ```ts
26
+ * import type { EffectScope } from 'vue';
27
+ *
28
+ * class DemoService {
29
+ * @RunInScope
30
+ * public setup(): EffectScope {
31
+ * watchEffect(() => { ... });
32
+ * return null as any;
33
+ * // 或者:return null as unknown as EffectScope;
34
+ * }
35
+ * }
36
+ * ```
37
+ */
38
+ type DecorableMethod = (this: any, ...args: any[]) => void | EffectScope;
39
+ export declare function RunInScope(): (value: DecorableMethod, context: ClassMethodDecoratorContext) => (this: any, ...args: any[]) => EffectScope;
40
+ export declare function RunInScope(value: DecorableMethod, context: ClassMethodDecoratorContext): (this: any, ...args: any[]) => EffectScope;
41
+ export {};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("@kaokei/di"),r=require("vue");function E(e,t,n){return e&&e.forEach(o=>{o&&o.isCurrentBound(t)&&n.push(o.get(t)),o.children&&E(o.children,t,n)}),n}function y(e,t){const n=[];return E(t.children,e,n),n[0]}function b(e,t){const n=[];return E(t.children,e,n),n}function T(e){const t=e,n=r.effectScope(!0);return t[S]=n,n}function R(e){return e[S]}function _(e){const t=R(e);return t||T(e)}function D(e){const t=e;if(t){const n=R(t);n&&(n.stop(),delete t[S])}}function V(e){return e!==null&&typeof e=="object"}function A(e,t){return V(t)?r.reactive(t):t}function U(e){return D(e)}function w({container:e}){return t=>y(t,e)}function j({container:e}){return t=>b(t,e)}function p(e,t){let n;return e?n=e.createChild():n=new s.Container,t&&n.bind(I).toConstantValue(r.markRaw(t)),n.bind(h).toDynamicValue(w),n.bind(N).toDynamicValue(j),n.onActivation(A),n.onDeactivation(U),n}const I=new s.Token("USE_VUE_SERVICE_CURRENT_COMPONENT"),h=new s.Token("USE_REACT_SERVICE_FIND_CHILD_SERVICE"),N=new s.Token("USE_REACT_SERVICE_FIND_CHILDREN_SERVICES"),S=Symbol(),a="USE_VUE_SERVICE_CONTAINER_TOKEN",d=p();function l(e,t){if(typeof t=="function")t(e);else for(let n=0;n<t.length;n++)e.bind(t[n]).toSelf()}function g(){const e=r.getCurrentInstance();if(e){const t=a,n=e.provides,o=e.parent&&e.parent.provides;if(n&&n!==o&&Object.prototype.hasOwnProperty.call(n,t))return n[t]}}function v(){if(r.hasInjectionContext())return r.inject(a,d);throw new Error("getProvideContainer 只能在 setup 中使用")}function F(e){return(g()||v()).get(e)}function H(e){return d.get(e)}function L(e,t){return t.runWithContext(()=>v().get(e))}function M(e){const t=g();if(t)l(t,e);else{const n=v(),o=r.getCurrentInstance();let c=p(n,o);l(c,e),r.provide(a,c),r.onUnmounted(()=>{c.destroy(),c=null})}}function x(e){l(d,e)}function m(e,t){t.runWithContext(()=>{const n=r.inject(a,null);if(n)l(n,e);else{let o=p(d);l(o,e),t.provide(a,o),t.onUnmount(()=>{o.destroy(),o=null})}})}function K(e){return t=>m(e,t)}function k(e,t,n){const o=n.get,c=n.set;return{configurable:!0,enumerable:!0,get(){const i=r.reactive(this),f=Symbol.for(t);let u=i[f];if(!u){const O=_(i).run(()=>c?r.computed({get:()=>o.call(i),set:P=>c.call(i,P)}):r.computed(()=>o.call(i)));u=r.markRaw({value:O}),i[f]=u}return u.value.value},set(i){const f=r.reactive(this),u=Symbol.for(t),C=f[u];C&&c&&(C.value.value=i)}}}exports.CURRENT_COMPONENT=I;exports.Computed=k;exports.FIND_CHILDREN_SERVICES=N;exports.FIND_CHILD_SERVICE=h;exports.declareAppProviders=m;exports.declareAppProvidersPlugin=K;exports.declareProviders=M;exports.declareRootProviders=x;exports.getEffectScope=_;exports.useAppService=L;exports.useRootService=H;exports.useService=F;Object.keys(s).forEach(e=>{e!=="default"&&!Object.prototype.hasOwnProperty.call(exports,e)&&Object.defineProperty(exports,e,{enumerable:!0,get:()=>s[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("@kaokei/di"),o=require("vue"),P=new c.Token("FIND_CHILD_SERVICE"),m=new c.Token("FIND_CHILDREN_SERVICES"),C=Symbol("SCOPE_KEY"),s=Symbol("CONTAINER_TOKEN");function w(t){const e=t,n=o.effectScope(!0);return e[C]=n,n}function b(t){return t[C]}function j(t){const e=t;if(e){const n=b(e);n&&(n.stop(),delete e[C])}}function D(t){const e=b(t);return e||w(t)}function h(t,e,n,r){if(t){for(const i of t)if(i.isCurrentBound(e)&&(n.push(i.get(e)),r)||i.children&&h(i.children,e,n,r))return!0}return!1}function A(t,e){const n=[];return h(e.children,t,n,!0),n[0]}function T(t,e){const n=[];return h(e.children,t,n,!1),n}function V(t,e){return c.isObject(e)?o.reactive(e):e}function H(t){return j(t)}function k({container:t}){return e=>A(e,t)}function F({container:t}){return e=>T(e,t)}function g(t){let e;return t?e=t.createChild():e=new c.Container,e.bind(P).toDynamicValue(k),e.bind(m).toDynamicValue(F),e.onActivation(V),e.onDeactivation(H),e}const d=g();function a(t,e){if(typeof e=="function")e(t);else for(let n=0;n<e.length;n++)t.bind(e[n]).toSelf()}function N(){const t=o.getCurrentInstance();if(t){const e=s,n=t.provides,r=t.parent&&t.parent.provides;if(n&&n!==r&&c.hasOwn(n,e))return n[e]}}function v(){if(o.hasInjectionContext())return o.inject(s,d);throw new Error("getProvideContainer 只能在 setup 中使用")}function L(t){return(N()||v()).get(t)}function K(t){const e=N();if(e)a(e,t);else{const n=v();let r=g(n);a(r,t),o.provide(s,r),o.onUnmounted(()=>{r.destroy(),r=null})}}function q(t){return d.get(t)}function U(t){a(d,t)}function W(t,e){return e.runWithContext(()=>v().get(t))}function _(t,e){e.runWithContext(()=>{const n=o.inject(s,null);if(n)a(n,t);else{let r=g(d);a(r,t),e.provide(s,r),e.onUnmount(()=>{r.destroy(),r=null})}})}function Y(t){return e=>_(t,e)}function O(t,e){const n=e.name;return function(){const r=D(this),i=t,E=o.toRaw(this);let p,f=Object.getPrototypeOf(E);for(;f;){const u=Object.getOwnPropertyDescriptor(f,n);if(u&&u.set){p=u.set;break}f=Object.getPrototypeOf(f)}const S=this,I=p?r.run(()=>o.computed({get:()=>i.call(S),set:u=>p.call(S,u)})):r.run(()=>o.computed(()=>i.call(S)));return Object.defineProperty(E,n,{value:I,writable:!0,configurable:!0,enumerable:!0}),I.value}}function z(t,e){return typeof t=="function"&&(e==null?void 0:e.kind)==="getter"?O(t,e):O}function l(t){return c.isObject(t)?o.markRaw(t):t}function R(t,e){if(e.kind==="accessor")return{get(){return t.get.call(this)},set(r){t.set.call(this,l(r))},init:l};const n=e.name;return e.addInitializer(function(){let r;Object.defineProperty(this,n,{configurable:!0,enumerable:!0,get(){return r},set(i){r=l(i)}})}),l}function B(t,e){return(e==null?void 0:e.kind)==="field"||(e==null?void 0:e.kind)==="accessor"?R(t,e):R}function y(t,e){return function(...n){const i=D(this).run(()=>o.effectScope());return i.run(()=>t.call(this,...n)),i}}function G(t,e){return typeof t=="function"&&(e==null?void 0:e.kind)==="method"?y(t):y}exports.Computed=z;exports.FIND_CHILDREN_SERVICES=m;exports.FIND_CHILD_SERVICE=P;exports.Raw=B;exports.RunInScope=G;exports.declareAppProviders=_;exports.declareAppProvidersPlugin=Y;exports.declareProviders=K;exports.declareRootProviders=U;exports.useAppService=W;exports.useRootService=q;exports.useService=L;Object.keys(c).forEach(t=>{t!=="default"&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:()=>c[t]})});
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from '@kaokei/di';
2
- export { CURRENT_COMPONENT, FIND_CHILD_SERVICE, FIND_CHILDREN_SERVICES, } from './constants.ts';
3
2
  export { useService, declareProviders, useRootService, declareRootProviders, useAppService, declareAppProviders, declareAppProvidersPlugin, } from './core.ts';
3
+ export { FIND_CHILD_SERVICE, FIND_CHILDREN_SERVICES } from './constants.ts';
4
4
  export { Computed } from './computed.ts';
5
- export { getEffectScope } from './scope.ts';
5
+ export { Raw } from './raw.ts';
6
+ export { RunInScope } from './effect-scope.ts';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from '@kaokei/di';
2
- export { CURRENT_COMPONENT, FIND_CHILD_SERVICE, FIND_CHILDREN_SERVICES, } from './constants.ts';
3
2
  export { useService, declareProviders, useRootService, declareRootProviders, useAppService, declareAppProviders, declareAppProvidersPlugin, } from './core.ts';
3
+ export { FIND_CHILD_SERVICE, FIND_CHILDREN_SERVICES } from './constants.ts';
4
4
  export { Computed } from './computed.ts';
5
- export { getEffectScope } from './scope.ts';
5
+ export { Raw } from './raw.ts';
6
+ export { RunInScope } from './effect-scope.ts';
package/dist/index.js CHANGED
@@ -1,167 +1,206 @@
1
- import { Container as y, Token as d } from "@kaokei/di";
1
+ import { Token as y, Container as _, isObject as R, hasOwn as k } from "@kaokei/di";
2
2
  export * from "@kaokei/di";
3
- import { effectScope as P, markRaw as R, reactive as C, getCurrentInstance as h, provide as T, onUnmounted as V, inject as m, hasInjectionContext as b, computed as v } from "vue";
4
- function E(t, e, n) {
5
- return t && t.forEach((o) => {
6
- o && o.isCurrentBound(e) && n.push(o.get(e)), o.children && E(o.children, e, n);
7
- }), n;
8
- }
9
- function D(t, e) {
10
- const n = [];
11
- return E(e.children, t, n), n[0];
3
+ import { effectScope as w, reactive as A, inject as N, provide as T, onUnmounted as V, getCurrentInstance as H, hasInjectionContext as j, toRaw as F, computed as E, markRaw as K } from "vue";
4
+ const L = new y(
5
+ "FIND_CHILD_SERVICE"
6
+ ), U = new y(
7
+ "FIND_CHILDREN_SERVICES"
8
+ ), p = Symbol("SCOPE_KEY"), c = Symbol("CONTAINER_TOKEN");
9
+ function W(n) {
10
+ const e = n, t = w(!0);
11
+ return e[p] = t, t;
12
+ }
13
+ function P(n) {
14
+ return n[p];
15
+ }
16
+ function Y(n) {
17
+ const e = n;
18
+ if (e) {
19
+ const t = P(e);
20
+ t && (t.stop(), delete e[p]);
21
+ }
12
22
  }
13
- function U(t, e) {
14
- const n = [];
15
- return E(e.children, t, n), n;
23
+ function b(n) {
24
+ const e = P(n);
25
+ return e || W(n);
16
26
  }
17
- function A(t) {
18
- const e = t, n = P(!0);
19
- return e[S] = n, n;
27
+ function h(n, e, t, r) {
28
+ if (n) {
29
+ for (const o of n)
30
+ if (o.isCurrentBound(e) && (t.push(o.get(e)), r) || o.children && h(o.children, e, t, r))
31
+ return !0;
32
+ }
33
+ return !1;
20
34
  }
21
- function I(t) {
22
- return t[S];
35
+ function z(n, e) {
36
+ const t = [];
37
+ return h(e.children, n, t, !0), t[0];
23
38
  }
24
- function w(t) {
25
- const e = I(t);
26
- return e || A(t);
39
+ function B(n, e) {
40
+ const t = [];
41
+ return h(e.children, n, t, !1), t;
27
42
  }
28
- function F(t) {
29
- const e = t;
30
- if (e) {
31
- const n = I(e);
32
- n && (n.stop(), delete e[S]);
33
- }
43
+ function G(n, e) {
44
+ return R(e) ? A(e) : e;
34
45
  }
35
- function H(t) {
36
- return t !== null && typeof t == "object";
46
+ function q(n) {
47
+ return Y(n);
37
48
  }
38
- function x(t, e) {
39
- return H(e) ? C(e) : e;
49
+ function J({ container: n }) {
50
+ return (e) => z(e, n);
40
51
  }
41
- function L(t) {
42
- return F(t);
52
+ function M({
53
+ container: n
54
+ }) {
55
+ return (e) => B(e, n);
43
56
  }
44
- function j({ container: t }) {
45
- return (e) => D(e, t);
57
+ function C(n) {
58
+ let e;
59
+ return n ? e = n.createChild() : e = new _(), e.bind(L).toDynamicValue(J), e.bind(U).toDynamicValue(M), e.onActivation(G), e.onDeactivation(q), e;
46
60
  }
47
- function K({
48
- container: t
49
- }) {
50
- return (e) => U(e, t);
51
- }
52
- function p(t, e) {
53
- let n;
54
- return t ? n = t.createChild() : n = new y(), e && n.bind(M).toConstantValue(R(e)), n.bind(W).toDynamicValue(j), n.bind(k).toDynamicValue(K), n.onActivation(x), n.onDeactivation(L), n;
55
- }
56
- const M = new d(
57
- "USE_VUE_SERVICE_CURRENT_COMPONENT"
58
- ), W = new d(
59
- "USE_REACT_SERVICE_FIND_CHILD_SERVICE"
60
- ), k = new d(
61
- "USE_REACT_SERVICE_FIND_CHILDREN_SERVICES"
62
- ), S = Symbol(), u = "USE_VUE_SERVICE_CONTAINER_TOKEN", a = p();
63
- function s(t, e) {
61
+ const a = C();
62
+ function u(n, e) {
64
63
  if (typeof e == "function")
65
- e(t);
64
+ e(n);
66
65
  else
67
- for (let n = 0; n < e.length; n++)
68
- t.bind(e[n]).toSelf();
69
- }
70
- function N() {
71
- const t = h();
72
- if (t) {
73
- const e = u, n = t.provides, o = t.parent && t.parent.provides;
74
- if (
75
- // 当前实例的provides存在
76
- n && // 当前实例的provides已经和parentProvides不是一个对象,说明已经Object.create(parentProvides)
77
- n !== o && // provides自身已经具有CONTAINER_TOKEN属性
78
- Object.prototype.hasOwnProperty.call(n, e)
79
- )
80
- return n[e];
66
+ for (let t = 0; t < e.length; t++)
67
+ n.bind(e[t]).toSelf();
68
+ }
69
+ function D() {
70
+ const n = H();
71
+ if (n) {
72
+ const e = c, t = n.provides, r = n.parent && n.parent.provides;
73
+ if (t && t !== r && k(t, e))
74
+ return t[e];
81
75
  }
82
76
  }
83
- function _() {
84
- if (b())
85
- return m(u, a);
77
+ function S() {
78
+ if (j())
79
+ return N(c, a);
86
80
  throw new Error("getProvideContainer 只能在 setup 中使用");
87
81
  }
88
- function q(t) {
89
- return (N() || _()).get(t);
90
- }
91
- function z(t) {
92
- return a.get(t);
93
- }
94
- function J(t, e) {
95
- return e.runWithContext(() => _().get(t));
82
+ function $(n) {
83
+ return (D() || S()).get(n);
96
84
  }
97
- function Q(t) {
98
- const e = N();
85
+ function x(n) {
86
+ const e = D();
99
87
  if (e)
100
- s(e, t);
88
+ u(e, n);
101
89
  else {
102
- const n = _(), o = h();
103
- let r = p(n, o);
104
- s(r, t), T(u, r), V(() => {
90
+ const t = S();
91
+ let r = C(t);
92
+ u(r, n), T(c, r), V(() => {
105
93
  r.destroy(), r = null;
106
94
  });
107
95
  }
108
96
  }
109
- function X(t) {
110
- s(a, t);
97
+ function ee(n) {
98
+ return a.get(n);
111
99
  }
112
- function B(t, e) {
100
+ function ne(n) {
101
+ u(a, n);
102
+ }
103
+ function te(n, e) {
104
+ return e.runWithContext(() => S().get(n));
105
+ }
106
+ function Q(n, e) {
113
107
  e.runWithContext(() => {
114
- const n = m(
115
- u,
116
- null
117
- );
118
- if (n)
119
- s(n, t);
108
+ const t = N(c, null);
109
+ if (t)
110
+ u(t, n);
120
111
  else {
121
- let o = p(a);
122
- s(o, t), e.provide(u, o), e.onUnmount(() => {
123
- o.destroy(), o = null;
112
+ let r = C(a);
113
+ u(r, n), e.provide(c, r), e.onUnmount(() => {
114
+ r.destroy(), r = null;
124
115
  });
125
116
  }
126
117
  });
127
118
  }
128
- function Z(t) {
129
- return (e) => B(t, e);
130
- }
131
- function $(t, e, n) {
132
- const o = n.get, r = n.set;
133
- return {
134
- configurable: !0,
135
- enumerable: !0,
136
- get() {
137
- const c = C(this), f = Symbol.for(e);
138
- let i = c[f];
139
- if (!i) {
140
- const g = w(c).run(() => r ? v({
141
- get: () => o.call(c),
142
- set: (O) => r.call(c, O)
143
- }) : v(() => o.call(c)));
144
- i = R({ value: g }), c[f] = i;
119
+ function re(n) {
120
+ return (e) => Q(n, e);
121
+ }
122
+ function I(n, e) {
123
+ const t = e.name;
124
+ return function() {
125
+ const r = b(this), o = n, g = F(this);
126
+ let l, s = Object.getPrototypeOf(g);
127
+ for (; s; ) {
128
+ const i = Object.getOwnPropertyDescriptor(s, t);
129
+ if (i && i.set) {
130
+ l = i.set;
131
+ break;
145
132
  }
146
- return i.value.value;
147
- },
148
- set(c) {
149
- const f = C(this), i = Symbol.for(e), l = f[i];
150
- l && r && (l.value.value = c);
133
+ s = Object.getPrototypeOf(s);
151
134
  }
135
+ const d = this, m = l ? r.run(
136
+ () => E({
137
+ get: () => o.call(d),
138
+ set: (i) => l.call(d, i)
139
+ })
140
+ ) : r.run(() => E(() => o.call(d)));
141
+ return Object.defineProperty(g, t, {
142
+ value: m,
143
+ writable: !0,
144
+ configurable: !0,
145
+ enumerable: !0
146
+ }), m.value;
152
147
  };
153
148
  }
149
+ function oe(n, e) {
150
+ return typeof n == "function" && (e == null ? void 0 : e.kind) === "getter" ? I(n, e) : I;
151
+ }
152
+ function f(n) {
153
+ return R(n) ? K(n) : n;
154
+ }
155
+ function O(n, e) {
156
+ if (e.kind === "accessor")
157
+ return {
158
+ get() {
159
+ return n.get.call(this);
160
+ },
161
+ set(r) {
162
+ n.set.call(this, f(r));
163
+ },
164
+ init: f
165
+ };
166
+ const t = e.name;
167
+ return e.addInitializer(function() {
168
+ let r;
169
+ Object.defineProperty(this, t, {
170
+ configurable: !0,
171
+ enumerable: !0,
172
+ get() {
173
+ return r;
174
+ },
175
+ set(o) {
176
+ r = f(o);
177
+ }
178
+ });
179
+ }), f;
180
+ }
181
+ function ie(n, e) {
182
+ return (e == null ? void 0 : e.kind) === "field" || (e == null ? void 0 : e.kind) === "accessor" ? O(n, e) : O;
183
+ }
184
+ function v(n, e) {
185
+ return function(...t) {
186
+ const o = b(this).run(() => w());
187
+ return o.run(() => n.call(this, ...t)), o;
188
+ };
189
+ }
190
+ function ce(n, e) {
191
+ return typeof n == "function" && (e == null ? void 0 : e.kind) === "method" ? v(n) : v;
192
+ }
154
193
  export {
155
- M as CURRENT_COMPONENT,
156
- $ as Computed,
157
- k as FIND_CHILDREN_SERVICES,
158
- W as FIND_CHILD_SERVICE,
159
- B as declareAppProviders,
160
- Z as declareAppProvidersPlugin,
161
- Q as declareProviders,
162
- X as declareRootProviders,
163
- w as getEffectScope,
164
- J as useAppService,
165
- z as useRootService,
166
- q as useService
194
+ oe as Computed,
195
+ U as FIND_CHILDREN_SERVICES,
196
+ L as FIND_CHILD_SERVICE,
197
+ ie as Raw,
198
+ ce as RunInScope,
199
+ Q as declareAppProviders,
200
+ re as declareAppProvidersPlugin,
201
+ x as declareProviders,
202
+ ne as declareRootProviders,
203
+ te as useAppService,
204
+ ee as useRootService,
205
+ $ as useService
167
206
  };
package/dist/raw.d.cts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 将值标记为 raw(如果是对象则调用 markRaw,否则原样返回)
3
+ */
4
+ export declare function ensureRaw(val: unknown): unknown;
5
+ export declare function Raw(): (value: any, context: ClassFieldDecoratorContext | ClassAccessorDecoratorContext) => any;
6
+ export declare function Raw(value: any, context: ClassFieldDecoratorContext | ClassAccessorDecoratorContext): any;
package/dist/raw.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 将值标记为 raw(如果是对象则调用 markRaw,否则原样返回)
3
+ */
4
+ export declare function ensureRaw(val: unknown): unknown;
5
+ export declare function Raw(): (value: any, context: ClassFieldDecoratorContext | ClassAccessorDecoratorContext) => any;
6
+ export declare function Raw(value: any, context: ClassFieldDecoratorContext | ClassAccessorDecoratorContext): any;
package/dist/scope.d.cts CHANGED
@@ -1,5 +1,33 @@
1
1
  import { EffectScope } from 'vue';
2
+ /**
3
+ * 本模块用于为类的实例对象管理 Vue 的 EffectScope。
4
+ *
5
+ * 核心思路:通过一个 Symbol key(SCOPE_KEY)在实例对象上挂载唯一的 EffectScope,
6
+ * 从而将该实例相关的 computed、watch 等响应式副作用统一收集到这个 scope 中。
7
+ * 当实例销毁时,只需 stop 这个 scope,即可自动清理所有关联的响应式副作用,
8
+ * 避免内存泄漏。
9
+ *
10
+ * 设计保证:每个实例对象上最多只存在一个 EffectScope(通过 getEffectScope 懒创建)。
11
+ */
12
+ /**
13
+ * 为实例对象创建一个新的 EffectScope,并挂载到对象的 SCOPE_KEY 属性上。
14
+ * 使用 effectScope(true) 创建独立的(detached)scope,
15
+ * 使其不受外层 scope 的 stop 影响,生命周期完全由自身控制。
16
+ */
2
17
  export declare function createScope(obj: object): EffectScope;
18
+ /**
19
+ * 获取实例对象上已有的 EffectScope。
20
+ * 如果对象上尚未挂载 scope,则返回 undefined。
21
+ */
3
22
  export declare function getScope(obj: object): EffectScope | undefined;
4
- export declare function getEffectScope(obj: object): EffectScope;
23
+ /**
24
+ * 移除并停止实例对象上的 EffectScope。
25
+ * 调用 scope.stop() 会自动清理该 scope 内所有的 computed、watch 等响应式副作用,
26
+ * 随后从对象上删除 SCOPE_KEY 属性,彻底解除关联。
27
+ */
5
28
  export declare function removeScope(obj: object): void;
29
+ /**
30
+ * 获取实例对象的 EffectScope,如果不存在则自动创建。
31
+ * 这是外部最常用的入口函数,保证每个实例对象上有且仅有一个 EffectScope。
32
+ */
33
+ export declare function getEffectScope(obj: object): EffectScope;
package/dist/scope.d.ts CHANGED
@@ -1,5 +1,33 @@
1
1
  import { EffectScope } from 'vue';
2
+ /**
3
+ * 本模块用于为类的实例对象管理 Vue 的 EffectScope。
4
+ *
5
+ * 核心思路:通过一个 Symbol key(SCOPE_KEY)在实例对象上挂载唯一的 EffectScope,
6
+ * 从而将该实例相关的 computed、watch 等响应式副作用统一收集到这个 scope 中。
7
+ * 当实例销毁时,只需 stop 这个 scope,即可自动清理所有关联的响应式副作用,
8
+ * 避免内存泄漏。
9
+ *
10
+ * 设计保证:每个实例对象上最多只存在一个 EffectScope(通过 getEffectScope 懒创建)。
11
+ */
12
+ /**
13
+ * 为实例对象创建一个新的 EffectScope,并挂载到对象的 SCOPE_KEY 属性上。
14
+ * 使用 effectScope(true) 创建独立的(detached)scope,
15
+ * 使其不受外层 scope 的 stop 影响,生命周期完全由自身控制。
16
+ */
2
17
  export declare function createScope(obj: object): EffectScope;
18
+ /**
19
+ * 获取实例对象上已有的 EffectScope。
20
+ * 如果对象上尚未挂载 scope,则返回 undefined。
21
+ */
3
22
  export declare function getScope(obj: object): EffectScope | undefined;
4
- export declare function getEffectScope(obj: object): EffectScope;
23
+ /**
24
+ * 移除并停止实例对象上的 EffectScope。
25
+ * 调用 scope.stop() 会自动清理该 scope 内所有的 computed、watch 等响应式副作用,
26
+ * 随后从对象上删除 SCOPE_KEY 属性,彻底解除关联。
27
+ */
5
28
  export declare function removeScope(obj: object): void;
29
+ /**
30
+ * 获取实例对象的 EffectScope,如果不存在则自动创建。
31
+ * 这是外部最常用的入口函数,保证每个实例对象上有且仅有一个 EffectScope。
32
+ */
33
+ export declare function getEffectScope(obj: object): EffectScope;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaokei/use-vue-service",
3
- "version": "3.0.1",
3
+ "version": "4.0.0",
4
4
  "type": "module",
5
5
  "description": "Lightweight Vue 3 state management with dependency injection, inspired by Angular services.",
6
6
  "main": "./dist/index.cjs",
@@ -41,31 +41,43 @@
41
41
  "scripts": {
42
42
  "test": "vitest",
43
43
  "coverage": "vitest run --coverage",
44
- "dev": "vite",
45
- "build": "vue-tsc -b && vite build",
46
- "preview": "vite preview",
44
+ "build": "vue-tsc -b tsconfig.app.json && vite build",
47
45
  "clean": "rm -rf dist/*",
48
46
  "public": "npm publish --access public",
49
47
  "postpublish": "git push origin --follow-tags",
50
48
  "prepublishOnly": "npm run clean && npm run build",
51
49
  "release": "standard-version -r",
52
- "release:first": "standard-version --first-release"
50
+ "release:first": "standard-version --first-release",
51
+ "docs:dev": "vitepress dev docs",
52
+ "docs:build": "vitepress build docs",
53
+ "docs:preview": "vitepress preview docs"
54
+ },
55
+ "peerDependencies": {
56
+ "@kaokei/di": "^5.0.4"
53
57
  },
54
58
  "devDependencies": {
55
- "@kaokei/di": "^3.0.9",
59
+ "@kaokei/di": "^5.0.4",
56
60
  "@types/node": "^22.15.17",
57
- "@vitejs/plugin-vue": "^5.2.4",
58
- "@vitest/coverage-v8": "^2.1.9",
61
+ "@vitejs/plugin-vue": "^6.0.0",
62
+ "@vitest/coverage-v8": "^3.1.1",
59
63
  "@vue/test-utils": "^2.4.6",
60
64
  "jsdom": "^25.0.1",
61
65
  "standard-version": "^9.5.0",
62
66
  "typescript": "~5.6.3",
63
- "vite": "^5.4.19",
67
+ "vite": "^6.0.0",
64
68
  "vite-plugin-dts": "^4.5.3",
65
- "vitest": "^2.1.9",
69
+ "vitepress": "^1.6.3",
70
+ "vitest": "^3.1.1",
66
71
  "vue": "^3.5.13",
67
72
  "vue-router": "^4.5.1",
68
- "vue-tsc": "^2.2.10"
73
+ "vue-tsc": "^2.2.10",
74
+ "@swc/core": "^1.15.21",
75
+ "@types/fs-extra": "^11.0.4",
76
+ "fast-check": "^4.6.0",
77
+ "fs-extra": "^11.3.0",
78
+ "inversify": "^6.2.2",
79
+ "reflect-metadata": "^0.2.2",
80
+ "unplugin-swc": "^1.5.9"
69
81
  },
70
82
  "packageManager": "pnpm@9.9.0+sha512.60c18acd138bff695d339be6ad13f7e936eea6745660d4cc4a776d5247c540d0edee1a563695c183a66eb917ef88f2b4feb1fc25f32a7adcadc7aaf3438e99c1"
71
83
  }
package/dist/utils.d.cts DELETED
@@ -1,3 +0,0 @@
1
- import { Container } from '@kaokei/di';
2
- import { ComponentInternalInstance } from 'vue';
3
- export declare function createContainer(parent?: Container, instance?: ComponentInternalInstance | null): Container;
package/dist/utils.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import { Container } from '@kaokei/di';
2
- import { ComponentInternalInstance } from 'vue';
3
- export declare function createContainer(parent?: Container, instance?: ComponentInternalInstance | null): Container;