Skip to content

Commit 138cd1d

Browse files
authored
Merge pull request #1 from leynier/next
feat: ensure wraps only promise-returning functions and handles non-promise returns
2 parents 5742a47 + 6c1489b commit 138cd1d

File tree

6 files changed

+64
-17
lines changed

6 files changed

+64
-17
lines changed

Diff for: .gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ pnpm-debug.log*
2525

2626
# Idea/VSCode settings
2727
.idea/
28-
.vscode/
28+
.vscode/*
29+
!.vscode/settings.json
2930

3031
# Miscellaneous
3132
*.tgz

Diff for: .prettierrc

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"singleQuote": true,
3+
"vueIndentScriptAndStyle": true,
4+
"singleAttributePerLine": true,
5+
"htmlWhitespaceSensitivity": "strict",
6+
"arrowParens": "avoid",
7+
"bracketSameLine": true,
8+
"jsxSingleQuote": true,
9+
"proseWrap": "always"
10+
}

Diff for: .vscode/settings.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"editor.formatOnSave": true,
3+
"editor.defaultFormatter": "esbenp.prettier-vscode"
4+
}

Diff for: package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nuxt-use-async-data-wrapper",
3-
"version": "1.0.1",
3+
"version": "1.1.0",
44
"description": "A utility to wrap Promise-returning functions with useAsyncData for Nuxt",
55
"main": "lib/index.js",
66
"types": "lib/index.d.ts",
@@ -25,10 +25,11 @@
2525
"url": "https://github.com/leynier/nuxt-use-async-data-wrapper.git"
2626
},
2727
"peerDependencies": {
28-
"vue": "^3.0.0",
29-
"nuxt": "^3.0.0"
28+
"nuxt": "^3.0.0",
29+
"vue": "^3.0.0"
3030
},
3131
"devDependencies": {
32+
"prettier": "^3.3.3",
3233
"typescript": "^5.7.2",
3334
"vue": "^3.5.13"
3435
},

Diff for: pnpm-lock.yaml

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/index.ts

+34-13
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,18 @@ type AsyncDataResult<T> = AsyncData<T, Error>;
1010
/**
1111
* Transforms an object's Promise-returning functions into functions compatible with useAsyncData.
1212
*
13+
* Only includes functions that return Promises; other properties are excluded.
14+
*
1315
* For each function in the object:
1416
* - If the function returns a Promise and takes no arguments, it becomes a function that accepts optional AsyncDataOptions.
1517
* - If the function returns a Promise and takes arguments, it becomes a function that accepts an argsSupplier and optional AsyncDataOptions.
1618
*
17-
* This allows you to use the functions within a Nuxt application, leveraging the reactivity and data fetching capabilities of useAsyncData.
18-
*
1919
* @template T - The type of the object.
2020
*/
2121
export type AsyncDataWrapper<T> = {
22-
[K in keyof T]: T[K] extends (...args: infer Args) => Promise<infer R>
22+
[K in keyof T as T[K] extends (...args: any[]) => Promise<any>
23+
? K
24+
: never]: T[K] extends (...args: infer Args) => Promise<infer R>
2325
? Args extends []
2426
? /**
2527
* Functions without arguments.
@@ -33,7 +35,10 @@ export type AsyncDataWrapper<T> = {
3335
* @param options - Optional AsyncDataOptions to configure useAsyncData.
3436
* @returns AsyncDataResult containing the data, pending state, and error.
3537
*/
36-
(argsSupplier: () => Args, options?: AsyncDataOptions<R>) => AsyncDataResult<R>
38+
(
39+
argsSupplier: () => Args,
40+
options?: AsyncDataOptions<R>,
41+
) => AsyncDataResult<R>
3742
: never;
3843
};
3944

@@ -56,13 +61,15 @@ export type AsyncDataWrapper<T> = {
5661
* const wrappedObject = useAsyncDataWrapper(originalObject);
5762
* ```
5863
*/
59-
export function useAsyncDataWrapper<T extends Record<string, any>>(obj: T): AsyncDataWrapper<T> {
64+
export function useAsyncDataWrapper<T extends Record<string, any>>(
65+
obj: T,
66+
): AsyncDataWrapper<T> {
6067
const composable = {} as AsyncDataWrapper<T>;
6168
const proto = Object.getPrototypeOf(obj);
6269

6370
// Get function names from the object's prototype, excluding the constructor
6471
const functionNames = Object.getOwnPropertyNames(proto).filter(
65-
key => key !== 'constructor' && typeof obj[key] === 'function'
72+
key => key !== 'constructor' && typeof obj[key] === 'function',
6673
);
6774

6875
for (const key of functionNames) {
@@ -89,27 +96,41 @@ export function useAsyncDataWrapper<T extends Record<string, any>>(obj: T): Asyn
8996
// Reactive reference to arguments
9097
const argsRef = computed(() => argsSupplier!());
9198
// Unique key for useAsyncData
92-
const dataKeyRef = computed(() => `${key}-${JSON.stringify(argsRef.value)}`);
99+
const dataKeyRef = computed(
100+
() => `${key}-${JSON.stringify(argsRef.value)}`,
101+
);
93102

94103
// Call useAsyncData with the generated key and function
95104
const asyncDataResult = useAsyncData(
96105
dataKeyRef.value,
97-
() => originalFunction(...unref(argsRef)),
106+
() => {
107+
const result = originalFunction(...unref(argsRef));
108+
// Ensure we return a Promise
109+
return result instanceof Promise ? result : Promise.resolve(result);
110+
},
98111
{
99112
// Re-execute when arguments change
100113
watch: [argsRef],
101114
// Spread additional options
102115
...options,
103-
}
116+
},
104117
);
105118

106119
return asyncDataResult;
107120
} else {
108121
// For functions without arguments
109-
const asyncDataResult = useAsyncData(key, () => originalFunction(), {
110-
// Spread additional options
111-
...options,
112-
});
122+
const asyncDataResult = useAsyncData(
123+
key,
124+
() => {
125+
const result = originalFunction();
126+
// Ensure we return a Promise
127+
return result instanceof Promise ? result : Promise.resolve(result);
128+
},
129+
{
130+
// Spread additional options
131+
...options,
132+
},
133+
);
113134

114135
return asyncDataResult;
115136
}

0 commit comments

Comments
 (0)