@cmtlyt/lingshu-toolkit 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +2 -0
  2. package/dist/{607.js → 707.js} +11 -11
  3. package/dist/{react.js → react/index.js} +8 -6
  4. package/dist/react/use-boolean/index.d.ts +6 -0
  5. package/dist/react/use-boolean/index.js +16 -0
  6. package/dist/react/use-boolean/index.test.d.ts +1 -0
  7. package/dist/react/use-controllable-value/index.d.ts +4 -3
  8. package/dist/react/use-controllable-value/index.js +1 -2
  9. package/dist/react/use-counter/index.js +2 -2
  10. package/dist/react/use-mount/index.d.ts +1 -0
  11. package/dist/react/use-mount/index.js +16 -0
  12. package/dist/react/use-mount/index.test.d.ts +1 -0
  13. package/dist/react/use-title/index.d.ts +6 -0
  14. package/dist/react/use-title/index.js +24 -0
  15. package/dist/react/use-title/index.test.d.ts +1 -0
  16. package/dist/react/use-toggle/index.d.ts +10 -0
  17. package/dist/react/use-toggle/index.js +26 -0
  18. package/dist/react/use-toggle/index.test.d.ts +1 -0
  19. package/dist/react/use-valid-data/index.d.ts +4 -2
  20. package/dist/react/use-valid-data/index.js +5 -2
  21. package/dist/shared/condition-merge/index.d.ts +35 -0
  22. package/dist/shared/condition-merge/index.js +30 -0
  23. package/dist/shared/condition-merge/index.test-d.d.ts +1 -0
  24. package/dist/shared/condition-merge/index.test-d.js +108 -0
  25. package/dist/shared/condition-merge/index.test.d.ts +1 -0
  26. package/dist/shared/data-handler/index.d.ts +1 -1
  27. package/dist/shared/data-handler/index.js +4 -4
  28. package/dist/shared/data-handler/tools.js +44 -0
  29. package/dist/shared/data-handler/types.d.ts +1 -0
  30. package/dist/shared/data-handler/types.js +0 -0
  31. package/dist/{shared.js → shared/index.js} +1 -1
  32. package/dist/shared/logger/index.d.ts +5 -1
  33. package/dist/shared/logger/index.js +2 -2
  34. package/dist/shared/throw-error/index.d.ts +2 -2
  35. package/dist/shared/throw-error/index.js +4 -4
  36. package/dist/shared/types/base.d.ts +5 -0
  37. package/dist/shared/types/base.js +0 -0
  38. package/dist/shared/types/index.d.ts +2 -2
  39. package/dist/shared/types/index.js +2 -0
  40. package/dist/shared/types/pack.d.ts +9 -0
  41. package/dist/shared/types/pack.js +1 -0
  42. package/dist/vue/index.d.ts +1 -0
  43. package/dist/vue/index.js +29 -0
  44. package/dist/vue/use-title/index.d.ts +6 -0
  45. package/dist/vue/use-title/index.js +29 -0
  46. package/dist/vue/use-title/index.test.d.ts +1 -0
  47. package/package.json +16 -4
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  一个支持 shadcn 的工具库
4
4
 
5
+ [![codecov](https://codecov.io/gh/cmtlyt/lingshu-toolkit/graph/badge.svg?token=WCAIRJNBFN)](https://codecov.io/gh/cmtlyt/lingshu-toolkit)
6
+
5
7
  ## 为什么要支持 shadcn?
6
8
 
7
9
  如果是纯 shadcn 的话, 就会失去长期维护能力, 作者对包的后续修改也很难进行更新, 所以对于这个痛点, 我希望这个包能同时支持 shadcn 和 npm package
@@ -1,14 +1,14 @@
1
- function throwError(message, ErrorClass = Error) {
2
- throw new ErrorClass(`[@cmtlyt/lingshu-toolkit]: ${message}`);
1
+ function throwError(fnName, message, ErrorClass = Error) {
2
+ throw new ErrorClass(`[@cmtlyt/lingshu-toolkit#${fnName}]: ${message}`);
3
3
  }
4
- function throwType(message) {
5
- throwError(message, TypeError);
4
+ function throwType(fnName, message) {
5
+ throwError(fnName, message, TypeError);
6
6
  }
7
7
  const logger = new Proxy(console, {
8
8
  get (target, prop, receiver) {
9
9
  const oldLog = Reflect.get(target, prop, receiver).bind(console);
10
- return (...args)=>{
11
- oldLog('[@cmtlyt/lingshu-toolkit]:', ...args);
10
+ return (fnName, ...args)=>{
11
+ oldLog(`[@cmtlyt/lingshu-toolkit#${fnName}]:`, ...args);
12
12
  };
13
13
  }
14
14
  });
@@ -46,7 +46,7 @@ function defineTransform(dataInfo) {
46
46
  }
47
47
  const handler = $t[item];
48
48
  if (!handler) {
49
- logger.warn(`${item} is not a valid type`);
49
+ logger.warn('defineTransform', `${item} is not a valid type`);
50
50
  continue;
51
51
  }
52
52
  verifyInfo[key] = handler();
@@ -101,7 +101,7 @@ function handleProcess(data, keys, handleFn, getActions, actionHandlers) {
101
101
  function errorProcess(errors, errorHandler, strict) {
102
102
  if (!errors.length) return;
103
103
  if (errorHandler) errorHandler(errors);
104
- else if (strict) throwType(errors.join('\n'));
104
+ else if (strict) throwType('dataHandler', errors.join('\n'));
105
105
  }
106
106
  function filterData(data, ctx, defaultValue = {}) {
107
107
  ctx.handledErrorKeys.forEach((key)=>{
@@ -109,8 +109,8 @@ function filterData(data, ctx, defaultValue = {}) {
109
109
  });
110
110
  }
111
111
  function dataHandler(data, handler, options) {
112
- if (!handler) throwType('handler is required');
113
- const { strict = false, errorHandler, defaultValue } = options || {};
112
+ if (!handler) throwType('dataHandler', 'handler is required');
113
+ const { strict = false, errorHandler, defaultValue, unwrap = false } = options || {};
114
114
  const handlerIsFunction = 'function' == typeof handler;
115
115
  const handleFn = handlerIsFunction ? handler : (value, key, ...args)=>handler[key](value, ...args);
116
116
  const tempData = {
@@ -123,7 +123,7 @@ function dataHandler(data, handler, options) {
123
123
  errorProcess(ctx.errors, errorHandler, strict);
124
124
  transformApply(tempData, ctx.transforms);
125
125
  filterData(tempData, ctx, defaultValue);
126
- return {
126
+ return unwrap ? tempData : {
127
127
  result: tempData,
128
128
  errors: ctx.errors
129
129
  };
@@ -1,9 +1,12 @@
1
1
  import { useEffect, useEffectEvent, useMemo, useRef, useState } from "react";
2
- import { dataHandler, logger, $dt, $t } from "./607.js";
2
+ import { dataHandler, logger, $dt, $t } from "../707.js";
3
3
  function useValidData(data, verifyInfo, options) {
4
4
  const verifyInfoRef = useRef(verifyInfo);
5
5
  const optionsRef = useRef(options);
6
- return useMemo(()=>dataHandler(data, verifyInfoRef.current, optionsRef.current), [
6
+ return useMemo(()=>dataHandler(data, verifyInfoRef.current, {
7
+ unwrap: true,
8
+ ...optionsRef.current
9
+ }), [
7
10
  data
8
11
  ]);
9
12
  }
@@ -13,8 +16,7 @@ const validInfo = $dt({
13
16
  trigger: $t.validString('onChange')
14
17
  });
15
18
  function useControllableValue(props = {}, options = {}) {
16
- const { result: validOptions } = useValidData(options, validInfo);
17
- const { defaultValue: _defaultValue, trigger, valuePropName, defaultValuePropName } = validOptions;
19
+ const { defaultValue: _defaultValue, trigger, valuePropName, defaultValuePropName } = useValidData(options, validInfo);
18
20
  const { [valuePropName]: propValue, [defaultValuePropName]: defaultValue = _defaultValue, [trigger]: emitChange } = props;
19
21
  const hasValueRef = useRef(Boolean(Reflect.getOwnPropertyDescriptor(props, valuePropName)));
20
22
  const isFirstRenderRef = useRef(true);
@@ -56,7 +58,7 @@ const use_counter_validInfo = $dt({
56
58
  step: $t.validNumber(nanTransform(1))
57
59
  });
58
60
  function useCounter(initialValue = 0, options = {}) {
59
- const { result: validOptions } = useValidData(options, use_counter_validInfo);
61
+ const validOptions = useValidData(options, use_counter_validInfo);
60
62
  const { step } = validOptions;
61
63
  const initialValueRef = useRef(getRealValue(Number(initialValue), validOptions));
62
64
  const [current, setCurrent] = useState(getRealValue(Number(initialValue), validOptions));
@@ -82,5 +84,5 @@ function useCounter(initialValue = 0, options = {}) {
82
84
  actions
83
85
  ];
84
86
  }
85
- export { $dt, $t, defineTransform } from "./607.js";
87
+ export { $dt, $t, defineTransform } from "../707.js";
86
88
  export { useControllableValue, useCounter, useValidData };
@@ -0,0 +1,6 @@
1
+ export declare function useBoolean(defaultValue?: boolean): readonly [boolean, {
2
+ toggle: () => void;
3
+ setTrue: () => void;
4
+ setFalse: () => void;
5
+ set: (value: boolean) => void;
6
+ }];
@@ -0,0 +1,16 @@
1
+ import { useMemo } from "react";
2
+ import { useToggle } from "../use-toggle/index.js";
3
+ function useBoolean(defaultValue = false) {
4
+ const [state, { toggle, set }] = useToggle(!!defaultValue);
5
+ const actions = useMemo(()=>({
6
+ toggle,
7
+ setTrue: ()=>set(true),
8
+ setFalse: ()=>set(false),
9
+ set: (value)=>set(!!value)
10
+ }), []);
11
+ return [
12
+ state,
13
+ actions
14
+ ];
15
+ }
16
+ export { useBoolean };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,3 @@
1
- import type { NotUnion } from '../../shared/types';
2
1
  interface UseControllableValueOptions<Ks extends PropertyKey = PropertyKey, P extends Ks | (string & {}) = 'value'> {
3
2
  defaultValue: any;
4
3
  defaultValuePropName: Ks;
@@ -6,9 +5,11 @@ interface UseControllableValueOptions<Ks extends PropertyKey = PropertyKey, P ex
6
5
  trigger: Ks;
7
6
  }
8
7
  export type PublicUseControllableValueOptions<Ks extends PropertyKey = PropertyKey, P extends Ks | (string & {}) = 'value'> = Partial<UseControllableValueOptions<Ks, P>>;
9
- type ValueType<T extends Record<PropertyKey, any>, P> = NotUnion<P> extends true ? P extends keyof T ? T[P] : T['value'] : T['value'];
8
+ type ParseDefaultValue<OT extends Record<PropertyKey, any>, O extends PublicUseControllableValueOptions> = O['defaultValuePropName'] extends keyof OT ? OT[O['defaultValuePropName']] : O['defaultValue'];
9
+ type Defaultize<OT extends Record<PropertyKey, any>, P extends keyof OT | (string & {}), O extends PublicUseControllableValueOptions> = P extends keyof OT ? undefined extends OT[P] ? OT[P] & ParseDefaultValue<OT, O> : OT[P] : ParseDefaultValue<OT, O>;
10
+ type ValueType<T extends Record<PropertyKey, any>, O extends PublicUseControllableValueOptions<PropertyKey, any>> = O['valuePropName'] extends keyof T ? Defaultize<T, O['valuePropName'], O> : Defaultize<T, 'value', O>;
10
11
  /**
11
12
  * 受控组件 value 逻辑切换, 如果传递了 value 则走受控逻辑, 否则走非受控逻辑
12
13
  */
13
- export declare function useControllableValue<T extends Record<PropertyKey, any>, P extends keyof T | (string & {}) = PropertyKey>(props?: T, options?: PublicUseControllableValueOptions<keyof T, P>): [ValueType<T, P>, (value: ValueType<T, P>, ...args: any[]) => void];
14
+ export declare function useControllableValue<T extends Record<PropertyKey, any>, P extends keyof T | (string & {}) = PropertyKey, O extends PublicUseControllableValueOptions<keyof T, P> = PublicUseControllableValueOptions<keyof T, P>>(props?: T, options?: O): [ValueType<T, O>, (value: ValueType<T, O>, ...args: any[]) => void];
14
15
  export {};
@@ -6,8 +6,7 @@ const validInfo = $dt({
6
6
  trigger: $t.validString('onChange')
7
7
  });
8
8
  function useControllableValue(props = {}, options = {}) {
9
- const { result: validOptions } = useValidData(options, validInfo);
10
- const { defaultValue: _defaultValue, trigger, valuePropName, defaultValuePropName } = validOptions;
9
+ const { defaultValue: _defaultValue, trigger, valuePropName, defaultValuePropName } = useValidData(options, validInfo);
11
10
  const { [valuePropName]: propValue, [defaultValuePropName]: defaultValue = _defaultValue, [trigger]: emitChange } = props;
12
11
  const hasValueRef = useRef(Boolean(Reflect.getOwnPropertyDescriptor(props, valuePropName)));
13
12
  const isFirstRenderRef = useRef(true);
@@ -1,6 +1,6 @@
1
- import { logger } from "../../shared/logger/index.js";
2
1
  import { useEffectEvent, useMemo, useRef, useState } from "react";
3
2
  import { $dt, $t, useValidData } from "../use-valid-data/index.js";
3
+ import { logger } from "../../shared/logger/index.js";
4
4
  function getRealValue(value, options) {
5
5
  const { min, max } = options;
6
6
  return Math.min(Math.max(value, min), max);
@@ -20,7 +20,7 @@ const validInfo = $dt({
20
20
  step: $t.validNumber(nanTransform(1))
21
21
  });
22
22
  function useCounter(initialValue = 0, options = {}) {
23
- const { result: validOptions } = useValidData(options, validInfo);
23
+ const validOptions = useValidData(options, validInfo);
24
24
  const { step } = validOptions;
25
25
  const initialValueRef = useRef(getRealValue(Number(initialValue), validOptions));
26
26
  const [current, setCurrent] = useState(getRealValue(Number(initialValue), validOptions));
@@ -0,0 +1 @@
1
+ export declare function useMount(callback: () => any): void;
@@ -0,0 +1,16 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { $t, dataHandler } from "../../shared/index.js";
3
+ function useMount(callback) {
4
+ const callbackRef = useRef(callback);
5
+ useEffect(()=>{
6
+ dataHandler({
7
+ fn: callbackRef.current
8
+ }, {
9
+ fn: $t["function"]()
10
+ }, {
11
+ strict: true
12
+ });
13
+ callbackRef.current();
14
+ }, []);
15
+ }
16
+ export { useMount };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ interface UseTitleOptions {
2
+ restoreOnUnmount: boolean;
3
+ }
4
+ declare function setTitle(title?: string): void;
5
+ export declare function useTitle(title?: string, options?: Partial<UseTitleOptions>): typeof setTitle;
6
+ export {};
@@ -0,0 +1,24 @@
1
+ import { useEffect } from "react";
2
+ import { $dt, $t, useValidData } from "../use-valid-data/index.js";
3
+ function setTitle(title) {
4
+ if (!title) return;
5
+ document.title = title;
6
+ }
7
+ const validInfo = $dt({
8
+ restoreOnUnmount: $t.boolean(true)
9
+ });
10
+ function useTitle(title, options = {}) {
11
+ const { restoreOnUnmount } = useValidData(options, validInfo);
12
+ useEffect(()=>{
13
+ const originalTitle = document.title;
14
+ setTitle(title);
15
+ return ()=>{
16
+ if (restoreOnUnmount) setTitle(originalTitle);
17
+ };
18
+ }, [
19
+ title,
20
+ restoreOnUnmount
21
+ ]);
22
+ return setTitle;
23
+ }
24
+ export { useTitle };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ interface Actions<T> {
2
+ set: (value: T) => void;
3
+ setLeft: () => void;
4
+ setRight: () => void;
5
+ toggle: () => void;
6
+ }
7
+ export declare function useToggle(): [boolean, Actions<boolean>];
8
+ export declare function useToggle<L>(defaultValue: L): [L, Actions<L>];
9
+ export declare function useToggle<L, R>(defaultValue: L, reverseValue: R): [L | R, Actions<L | R>];
10
+ export {};
@@ -0,0 +1,26 @@
1
+ import { useMemo, useRef, useState } from "react";
2
+ import { throwType } from "../../shared/throw-error/index.js";
3
+ function useToggle(defualtValue = false, reverseValue) {
4
+ const [state, setState] = useState(defualtValue);
5
+ const toggleRef = useRef([
6
+ defualtValue,
7
+ void 0 === reverseValue ? !defualtValue : reverseValue
8
+ ]);
9
+ const actions = useMemo(()=>{
10
+ const [left, right] = toggleRef.current;
11
+ return {
12
+ set: (value)=>{
13
+ if (value !== left && value !== right) throwType('useToggle', 'value is not left or right');
14
+ setState(value);
15
+ },
16
+ setLeft: ()=>setState(left),
17
+ setRight: ()=>setState(right),
18
+ toggle: ()=>setState((prev)=>prev === left ? right : left)
19
+ };
20
+ }, []);
21
+ return [
22
+ state,
23
+ actions
24
+ ];
25
+ }
26
+ export { useToggle };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,8 @@
1
1
  import type { DataHandlerOptions, Handler } from '../../shared/data-handler/types';
2
2
  export * from '../../shared/data-handler/tools';
3
- export declare function useValidData<T extends Record<PropertyKey, any>>(data: T, verifyInfo: Handler<T>, options?: DataHandlerOptions<T>): {
4
- result: T | (T & undefined);
3
+ export declare function useValidData<T extends Record<PropertyKey, any>, O extends DataHandlerOptions<T> = DataHandlerOptions<T> & {
4
+ unwrap: true;
5
+ }>(data: T, verifyInfo: Handler<T>, options?: O): O["unwrap"] extends true ? T & O["defaultValue"] : {
6
+ result: T & O["defaultValue"];
5
7
  errors: string[];
6
8
  };
@@ -1,10 +1,13 @@
1
- import { dataHandler } from "../../shared/index.js";
2
1
  import { useMemo, useRef } from "react";
2
+ import { dataHandler } from "../../shared/data-handler/index.js";
3
3
  export * from "../../shared/data-handler/tools.js";
4
4
  function useValidData(data, verifyInfo, options) {
5
5
  const verifyInfoRef = useRef(verifyInfo);
6
6
  const optionsRef = useRef(options);
7
- return useMemo(()=>dataHandler(data, verifyInfoRef.current, optionsRef.current), [
7
+ return useMemo(()=>dataHandler(data, verifyInfoRef.current, {
8
+ unwrap: true,
9
+ ...optionsRef.current
10
+ }), [
8
11
  data
9
12
  ]);
10
13
  }
@@ -0,0 +1,35 @@
1
+ import type { IsPrimitive, UnionToIntersection } from '../types';
2
+ type AssertValue = Record<PropertyKey, any> | any[];
3
+ type ConditionArrayItem = [boolean, AssertValue, AssertValue?];
4
+ type ConditionObjItem = {
5
+ condition: boolean;
6
+ value: AssertValue;
7
+ fullback?: AssertValue;
8
+ };
9
+ type ConditionItem = ConditionObjItem | ConditionArrayItem;
10
+ type GetDefaultValue<V> = IsPrimitive<V> extends true ? never : Record<never, any>;
11
+ type ParseDefaultValue<V, D> = FormatValue<unknown extends D ? (V extends any[] ? [] : GetDefaultValue<V>) : D extends undefined | null ? GetDefaultValue<V> : D>;
12
+ type ParseArrayCondition<T extends [any, any, any?]> = T extends [infer Flag, infer Value, (infer DefaultValue)?] ? boolean extends Flag ? FormatValue<Value> | ParseDefaultValue<Value, DefaultValue> : Flag extends true ? FormatValue<Value> & Record<PropertyKey, any> : ParseDefaultValue<Value, DefaultValue> & Record<PropertyKey, any> : never;
13
+ type ParseObjCondition<T extends ConditionObjItem> = T extends {
14
+ condition: infer Flag extends boolean;
15
+ value: infer Value;
16
+ fullback?: infer DefaultValue;
17
+ } ? ParseArrayCondition<[Flag, Value, DefaultValue]> : never;
18
+ type FormatValue<V> = [V] extends [never] ? never : V extends any[] ? V : {
19
+ [K in keyof V as V[K] extends undefined ? never : K]: V[K];
20
+ };
21
+ type BuildConditionValue<T> = [T];
22
+ type ParseConditionValue<T extends ConditionItem> = UnionToIntersection<T extends infer IT ? BuildConditionValue<Printify<IT extends ConditionArrayItem ? ParseArrayCondition<IT> : IT extends ConditionObjItem ? ParseObjCondition<IT> : never>> : never>;
23
+ type MergedResult<T extends ConditionItem[]> = T extends [
24
+ infer First extends ConditionItem,
25
+ ...infer Last extends [ConditionItem, ...ConditionItem[]]
26
+ ] ? ParseConditionValue<First> & MergedResult<Last> : ParseConditionValue<T[0]>;
27
+ type CMInput = ConditionItem[];
28
+ type Printify<T> = T extends any[] ? T : [T] extends [never] ? T : {
29
+ [K in keyof T]: T[K];
30
+ };
31
+ type FormatResult<T extends any[]> = T[0] & Record<PropertyKey, any>;
32
+ export declare function conditionMerge<T extends CMInput>(...input: T): FormatResult<MergedResult<T>>;
33
+ export declare function conditionMerge<T extends CMInput>(input: T): FormatResult<MergedResult<T>>;
34
+ export {};
35
+ t {};
@@ -0,0 +1,30 @@
1
+ import { throwType } from "../throw-error/index.js";
2
+ function getEmpty(_v) {
3
+ return Array.isArray(_v) ? [] : {};
4
+ }
5
+ function valueCheck(_v) {
6
+ return Array.isArray(_v) || 'object' == typeof _v;
7
+ }
8
+ function conditionMerge(...input) {
9
+ const conditionItems = (input.length > 1 ? input : input[0]).map((item)=>{
10
+ let result = null;
11
+ if (Array.isArray(item)) {
12
+ const [condition, value, fullback] = item;
13
+ result = {
14
+ condition,
15
+ value,
16
+ fullback
17
+ };
18
+ } else if (Object.getOwnPropertyDescriptor(item, 'condition')) result = item;
19
+ else throwType('conditionMerge', 'input must be an ConditionItem');
20
+ const validValue = valueCheck(result.value);
21
+ const validFullback = void 0 === result.fullback || valueCheck(result.fullback);
22
+ if (!(validValue && validFullback)) throwType('conditionMerge', 'value and fullback must be an array or object');
23
+ return result;
24
+ });
25
+ const result = getEmpty(conditionItems[0].value);
26
+ const mergeFn = Array.isArray(result) ? (a1, a2)=>Reflect.apply(Array.prototype.splice.bind(a1, a1.length, 0), null, a2) : Object.assign;
27
+ for(let i = 0, item = conditionItems[i]; i < conditionItems.length; item = conditionItems[++i])mergeFn(result, item.condition ? item.value : item.fullback || getEmpty(item.value));
28
+ return result;
29
+ }
30
+ export { conditionMerge };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,108 @@
1
+ import { describe, expectTypeOf, test } from "vitest";
2
+ import { conditionMerge } from "./index.js";
3
+ describe('conditionMerge 类型测试', ()=>{
4
+ test(': 混合布尔类型', ()=>{
5
+ const t1 = conditionMerge([
6
+ {
7
+ condition: true,
8
+ value: {
9
+ num: 1
10
+ }
11
+ },
12
+ {
13
+ condition: Math.random() > 0.5,
14
+ value: {
15
+ num: 3,
16
+ str: '3'
17
+ },
18
+ fullback: {
19
+ str: '4'
20
+ }
21
+ }
22
+ ]);
23
+ expectTypeOf(t1).pick().toEqualTypeOf();
24
+ expectTypeOf(t1).pick().toEqualTypeOf();
25
+ expectTypeOf(conditionMerge({
26
+ condition: true,
27
+ value: {
28
+ num: 1
29
+ }
30
+ }, {
31
+ condition: Math.random() > 0.5,
32
+ value: {
33
+ num: 3,
34
+ str: '3'
35
+ },
36
+ fullback: {
37
+ str: '4'
38
+ }
39
+ })).toEqualTypeOf(t1);
40
+ const t3 = conditionMerge([
41
+ {
42
+ condition: true,
43
+ value: {
44
+ num: 1
45
+ }
46
+ },
47
+ {
48
+ condition: false,
49
+ value: {
50
+ num: 1
51
+ },
52
+ fullback: {
53
+ bool: true
54
+ }
55
+ },
56
+ {
57
+ condition: Math.random() > 0.5,
58
+ value: {
59
+ num: 3,
60
+ str: '3'
61
+ },
62
+ fullback: {
63
+ str: '4'
64
+ }
65
+ }
66
+ ]);
67
+ expectTypeOf(t3).pick().toEqualTypeOf();
68
+ expectTypeOf(t3).pick().toEqualTypeOf();
69
+ expectTypeOf(t3).pick().toEqualTypeOf();
70
+ });
71
+ test('类型测试: 纯 boolean 类型测试', ()=>{
72
+ const t1 = conditionMerge([
73
+ {
74
+ condition: Math.random() > 0.1,
75
+ value: {
76
+ num: 1
77
+ }
78
+ },
79
+ {
80
+ condition: Math.random() > 0.5,
81
+ value: {
82
+ num: 3,
83
+ str: '3'
84
+ },
85
+ fullback: {
86
+ str: '4'
87
+ }
88
+ }
89
+ ]);
90
+ expectTypeOf(t1).pick().toEqualTypeOf();
91
+ expectTypeOf(t1).pick().toEqualTypeOf();
92
+ expectTypeOf(conditionMerge({
93
+ condition: Math.random() > 0.1,
94
+ value: {
95
+ num: 1
96
+ }
97
+ }, {
98
+ condition: Math.random() > 0.5,
99
+ value: {
100
+ num: 3,
101
+ str: '3'
102
+ },
103
+ fullback: {
104
+ str: '4'
105
+ }
106
+ })).toEqualTypeOf(t1);
107
+ });
108
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,5 @@
1
1
  import type { DataHandlerOptions, Handler } from './types';
2
- export declare function dataHandler<M extends Record<PropertyKey, any>, O extends DataHandlerOptions<M> = DataHandlerOptions<M>>(data: M & Partial<O['defaultValue']>, handler: Handler<M>, options?: O): {
2
+ export declare function dataHandler<M extends Record<PropertyKey, any>, O extends DataHandlerOptions<M> = DataHandlerOptions<M>>(data: M & Partial<O['defaultValue']>, handler: Handler<M>, options?: O): O['unwrap'] extends true ? M & O['defaultValue'] : {
3
3
  result: M & O['defaultValue'];
4
4
  errors: string[];
5
5
  };
@@ -47,7 +47,7 @@ function handleProcess(data, keys, handleFn, getActions, actionHandlers) {
47
47
  function errorProcess(errors, errorHandler, strict) {
48
48
  if (!errors.length) return;
49
49
  if (errorHandler) errorHandler(errors);
50
- else if (strict) throwType(errors.join('\n'));
50
+ else if (strict) throwType('dataHandler', errors.join('\n'));
51
51
  }
52
52
  function filterData(data, ctx, defaultValue = {}) {
53
53
  ctx.handledErrorKeys.forEach((key)=>{
@@ -55,8 +55,8 @@ function filterData(data, ctx, defaultValue = {}) {
55
55
  });
56
56
  }
57
57
  function dataHandler(data, handler, options) {
58
- if (!handler) throwType('handler is required');
59
- const { strict = false, errorHandler, defaultValue } = options || {};
58
+ if (!handler) throwType('dataHandler', 'handler is required');
59
+ const { strict = false, errorHandler, defaultValue, unwrap = false } = options || {};
60
60
  const handlerIsFunction = 'function' == typeof handler;
61
61
  const handleFn = handlerIsFunction ? handler : (value, key, ...args)=>handler[key](value, ...args);
62
62
  const tempData = {
@@ -69,7 +69,7 @@ function dataHandler(data, handler, options) {
69
69
  errorProcess(ctx.errors, errorHandler, strict);
70
70
  transformApply(tempData, ctx.transforms);
71
71
  filterData(tempData, ctx, defaultValue);
72
- return {
72
+ return unwrap ? tempData : {
73
73
  result: tempData,
74
74
  errors: ctx.errors
75
75
  };
@@ -0,0 +1,44 @@
1
+ import { logger } from "../logger/index.js";
2
+ function getType(_v) {
3
+ return Object.prototype.toString.call(_v).slice(8, -1).toLowerCase();
4
+ }
5
+ function typeHandler(type, verifyFn) {
6
+ return (fullback)=>(_v, actions)=>{
7
+ if (verifyFn ? verifyFn(_v) : getType(_v) === type) return true;
8
+ if (null == fullback) return false;
9
+ let fullbackValue = fullback;
10
+ if ('function' == typeof fullback) fullbackValue = fullback(_v);
11
+ actions.transform(fullbackValue);
12
+ };
13
+ }
14
+ const $t = {
15
+ notNullable: typeHandler('notNullable', (_v)=>null != _v),
16
+ string: typeHandler('string'),
17
+ validString: typeHandler('validString', (_v)=>'string' == typeof _v && _v.length > 0),
18
+ number: typeHandler('number'),
19
+ validNumber: typeHandler('validNumber', (_v)=>'number' == typeof _v && !Number.isNaN(_v)),
20
+ boolean: typeHandler('boolean'),
21
+ object: typeHandler('object'),
22
+ array: typeHandler('array'),
23
+ function: typeHandler('function'),
24
+ symbol: typeHandler('symbol')
25
+ };
26
+ function defineTransform(dataInfo) {
27
+ const verifyInfo = {};
28
+ const keys = Reflect.ownKeys(dataInfo);
29
+ for(let i = 0, key = keys[i], item = dataInfo[key]; i < keys.length; key = keys[++i], item = dataInfo[key]){
30
+ if ('function' == typeof item) {
31
+ verifyInfo[key] = item;
32
+ continue;
33
+ }
34
+ const handler = $t[item];
35
+ if (!handler) {
36
+ logger.warn('defineTransform', `${item} is not a valid type`);
37
+ continue;
38
+ }
39
+ verifyInfo[key] = handler();
40
+ }
41
+ return verifyInfo;
42
+ }
43
+ const $dt = defineTransform;
44
+ export { $dt, $t, defineTransform };
@@ -23,4 +23,5 @@ export interface DataHandlerOptions<M extends Record<PropertyKey, any>> {
23
23
  strict?: boolean;
24
24
  errorHandler?: (error: ActionContext['errors']) => void;
25
25
  defaultValue?: M;
26
+ unwrap?: boolean;
26
27
  }
File without changes
@@ -1 +1 @@
1
- export { $dt, $t, dataHandler, defineTransform, throwError, throwType } from "./607.js";
1
+ export { $dt, $t, dataHandler, defineTransform, throwError, throwType } from "../707.js";
@@ -1 +1,5 @@
1
- export declare const logger: Console;
1
+ type Logger = {
2
+ [K in keyof Omit<Console, 'table'> as Console[K] extends (...args: any[]) => any ? K : never]: Console[K] extends (...args: [any, ...infer AS]) => infer R ? (fnName: string, ...args: AS) => R : never;
3
+ };
4
+ export declare const logger: Logger;
5
+ export {};
@@ -1,8 +1,8 @@
1
1
  const logger = new Proxy(console, {
2
2
  get (target, prop, receiver) {
3
3
  const oldLog = Reflect.get(target, prop, receiver).bind(console);
4
- return (...args)=>{
5
- oldLog('[@cmtlyt/lingshu-toolkit]:', ...args);
4
+ return (fnName, ...args)=>{
5
+ oldLog(`[@cmtlyt/lingshu-toolkit#${fnName}]:`, ...args);
6
6
  };
7
7
  }
8
8
  });
@@ -1,2 +1,2 @@
1
- export declare function throwError(message: string, ErrorClass?: ErrorConstructor): never;
2
- export declare function throwType(message: string): never;
1
+ export declare function throwError(fnName: string, message: string, ErrorClass?: ErrorConstructor): never;
2
+ export declare function throwType(fnName: string, message: string): never;
@@ -1,7 +1,7 @@
1
- function throwError(message, ErrorClass = Error) {
2
- throw new ErrorClass(`[@cmtlyt/lingshu-toolkit]: ${message}`);
1
+ function throwError(fnName, message, ErrorClass = Error) {
2
+ throw new ErrorClass(`[@cmtlyt/lingshu-toolkit#${fnName}]: ${message}`);
3
3
  }
4
- function throwType(message) {
5
- throwError(message, TypeError);
4
+ function throwType(fnName, message) {
5
+ throwError(fnName, message, TypeError);
6
6
  }
7
7
  export { throwError, throwType };
@@ -0,0 +1,5 @@
1
+ export type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
2
+ export type NonUnion<T> = Equal<[T] extends [never] ? never : T[], T extends any ? T[] : never>;
3
+ export type UnionToIntersection<U> = [U] extends [never] ? never : (U extends any ? (_v: U) => void : never) extends (_v: infer I) => void ? I : never;
4
+ export type IsPrimitive<T> = T extends number | string | boolean | symbol | bigint | null | undefined ? true : false;
5
+ export type IsBasicType<T> = T extends number | string | boolean | symbol | bigint ? true : false;
File without changes
@@ -1,2 +1,2 @@
1
- export type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
2
- export type NotUnion<T> = Equal<[T] extends [never] ? never : T[], T extends any ? T[] : never>;
1
+ export * from './base';
2
+ export * from './pack';
@@ -0,0 +1,2 @@
1
+ export * from "./base.js";
2
+ export * from "./pack.js";
@@ -0,0 +1,9 @@
1
+ declare const __PACK__: unique symbol;
2
+ export type Pack<T> = {
3
+ [__PACK__]: T;
4
+ };
5
+ export type Unpack<T extends Pack<any>> = T extends Pack<infer U> ? U : never;
6
+ export type SafeUnpack<T extends Pack<any>> = T extends Pack<infer U> ? U : T;
7
+ export type IsPack<T> = Pack<any> extends T ? true : false;
8
+ export type HasPack<T> = (T extends any[] ? HasPack<T[number]> : IsPack<T>) extends false ? false : true;
9
+ export {};
@@ -0,0 +1 @@
1
+ Symbol('__PACK__');
@@ -0,0 +1 @@
1
+ export * from './use-title';
@@ -0,0 +1,29 @@
1
+ import { onScopeDispose, ref, toValue, watch } from "vue";
2
+ import { dataHandler, $t, $dt } from "../707.js";
3
+ function setTitle(title) {
4
+ if (!title || "u" < typeof document) return;
5
+ const oldTitle = document.title;
6
+ document.title = title;
7
+ return oldTitle;
8
+ }
9
+ const validInfo = $dt({
10
+ restoreOnUnmount: $t.boolean(true)
11
+ });
12
+ function useTitle(newTitle = '', options = {}) {
13
+ const { restoreOnUnmount } = dataHandler(options, validInfo, {
14
+ unwrap: true
15
+ });
16
+ const title = ref(toValue(newTitle));
17
+ const originalTitle = setTitle(title.value);
18
+ watch(title, setTitle, {
19
+ flush: 'sync'
20
+ });
21
+ watch(()=>toValue(newTitle), (value)=>{
22
+ title.value = value;
23
+ });
24
+ if (restoreOnUnmount) onScopeDispose(()=>{
25
+ setTitle(originalTitle);
26
+ });
27
+ return title;
28
+ }
29
+ export { useTitle };
@@ -0,0 +1,6 @@
1
+ import { type MaybeRefOrGetter } from 'vue';
2
+ interface UseTitleOptions {
3
+ restoreOnUnmount: boolean;
4
+ }
5
+ export declare function useTitle(newTitle?: MaybeRefOrGetter<string>, options?: Partial<UseTitleOptions>): import("vue").Ref<string, string>;
6
+ export {};
@@ -0,0 +1,29 @@
1
+ import { onScopeDispose, ref, toValue, watch } from "vue";
2
+ import { $dt, $t, dataHandler } from "../../shared/data-handler/index.js";
3
+ function setTitle(title) {
4
+ if (!title || "u" < typeof document) return;
5
+ const oldTitle = document.title;
6
+ document.title = title;
7
+ return oldTitle;
8
+ }
9
+ const validInfo = $dt({
10
+ restoreOnUnmount: $t.boolean(true)
11
+ });
12
+ function useTitle(newTitle = '', options = {}) {
13
+ const { restoreOnUnmount } = dataHandler(options, validInfo, {
14
+ unwrap: true
15
+ });
16
+ const title = ref(toValue(newTitle));
17
+ const originalTitle = setTitle(title.value);
18
+ watch(title, setTitle, {
19
+ flush: 'sync'
20
+ });
21
+ watch(()=>toValue(newTitle), (value)=>{
22
+ title.value = value;
23
+ });
24
+ if (restoreOnUnmount) onScopeDispose(()=>{
25
+ setTitle(originalTitle);
26
+ });
27
+ return title;
28
+ }
29
+ export { useTitle };
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmtlyt/lingshu-toolkit",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/shared.js",
6
6
  "module": "./dist/shared.js",
@@ -8,21 +8,31 @@
8
8
  "exports": {
9
9
  ".": {
10
10
  "types": "./dist/shared/index.d.ts",
11
- "import": "./dist/shared.js"
11
+ "import": "./dist/shared/index.js"
12
12
  },
13
13
  "./react": {
14
14
  "types": "./dist/react/index.d.ts",
15
- "import": "./dist/react.js"
15
+ "import": "./dist/react/index.js"
16
16
  },
17
17
  "./react/*": {
18
+ "types": "./dist/react/*/index.d.ts",
18
19
  "import": "./dist/react/*"
19
20
  },
20
21
  "./shared": {
21
22
  "types": "./dist/shared/index.d.ts",
22
- "import": "./dist/shared.js"
23
+ "import": "./dist/shared/index.js"
23
24
  },
24
25
  "./shared/*": {
26
+ "types": "./dist/shared/*/index.d.ts",
25
27
  "import": "./dist/shared/*"
28
+ },
29
+ "./vue": {
30
+ "types": "./dist/vue/index.d.ts",
31
+ "import": "./dist/vue/index.js"
32
+ },
33
+ "./vue/*": {
34
+ "types": "./dist/vue/*/index.d.ts",
35
+ "import": "./dist/vue/*"
26
36
  }
27
37
  },
28
38
  "author": {
@@ -102,6 +112,8 @@
102
112
  "build:docs": "rspress build",
103
113
  "check": "biome check --write",
104
114
  "dev:docs": "rspress dev",
115
+ "dev:registry": "pnpm dlx serve src/public -p 3000",
116
+ "preview:docs": "rspress preview",
105
117
  "format": "biome format --write",
106
118
  "test": "vitest --config=vitest.browser.config.ts --coverage.enabled --ui",
107
119
  "test:ci": "vitest run --config=vitest.browser.config.ts",