diff --git a/.gitignore b/.gitignore index e777e0f..8df0a14 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,8 @@ pnpm-debug.log* # Idea/VSCode settings .idea/ -.vscode/ +.vscode/* +!.vscode/settings.json # Miscellaneous *.tgz diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..719db94 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "singleQuote": true, + "vueIndentScriptAndStyle": true, + "singleAttributePerLine": true, + "htmlWhitespaceSensitivity": "strict", + "arrowParens": "avoid", + "bracketSameLine": true, + "jsxSingleQuote": true, + "proseWrap": "always" +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..89d1965 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" +} \ No newline at end of file diff --git a/package.json b/package.json index d932fb9..0910dac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nuxt-use-async-data-wrapper", - "version": "1.0.1", + "version": "1.1.0", "description": "A utility to wrap Promise-returning functions with useAsyncData for Nuxt", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -25,10 +25,11 @@ "url": "https://github.com/leynier/nuxt-use-async-data-wrapper.git" }, "peerDependencies": { - "vue": "^3.0.0", - "nuxt": "^3.0.0" + "nuxt": "^3.0.0", + "vue": "^3.0.0" }, "devDependencies": { + "prettier": "^3.3.3", "typescript": "^5.7.2", "vue": "^3.5.13" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 85f4f5b..b76e4ab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,6 +12,9 @@ importers: specifier: ^3.0.0 version: 3.14.1592(@parcel/watcher@2.5.0)(@types/node@22.9.3)(ioredis@5.4.1)(magicast@0.3.5)(rollup@4.27.4)(terser@5.36.0)(typescript@5.7.2)(vite@5.4.11(@types/node@22.9.3)(terser@5.36.0)) devDependencies: + prettier: + specifier: ^3.3.3 + version: 3.3.3 typescript: specifier: ^5.7.2 version: 5.7.2 @@ -2394,6 +2397,11 @@ packages: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + engines: {node: '>=14'} + hasBin: true + pretty-bytes@6.1.1: resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} engines: {node: ^14.13.1 || >=16.0.0} @@ -5705,6 +5713,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + prettier@3.3.3: {} + pretty-bytes@6.1.1: {} process-nextick-args@2.0.1: {} diff --git a/src/index.ts b/src/index.ts index ab755a8..1268225 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,16 +10,18 @@ type AsyncDataResult = AsyncData; /** * Transforms an object's Promise-returning functions into functions compatible with useAsyncData. * + * Only includes functions that return Promises; other properties are excluded. + * * For each function in the object: * - If the function returns a Promise and takes no arguments, it becomes a function that accepts optional AsyncDataOptions. * - If the function returns a Promise and takes arguments, it becomes a function that accepts an argsSupplier and optional AsyncDataOptions. * - * This allows you to use the functions within a Nuxt application, leveraging the reactivity and data fetching capabilities of useAsyncData. - * * @template T - The type of the object. */ export type AsyncDataWrapper = { - [K in keyof T]: T[K] extends (...args: infer Args) => Promise + [K in keyof T as T[K] extends (...args: any[]) => Promise + ? K + : never]: T[K] extends (...args: infer Args) => Promise ? Args extends [] ? /** * Functions without arguments. @@ -33,7 +35,10 @@ export type AsyncDataWrapper = { * @param options - Optional AsyncDataOptions to configure useAsyncData. * @returns AsyncDataResult containing the data, pending state, and error. */ - (argsSupplier: () => Args, options?: AsyncDataOptions) => AsyncDataResult + ( + argsSupplier: () => Args, + options?: AsyncDataOptions, + ) => AsyncDataResult : never; }; @@ -56,13 +61,15 @@ export type AsyncDataWrapper = { * const wrappedObject = useAsyncDataWrapper(originalObject); * ``` */ -export function useAsyncDataWrapper>(obj: T): AsyncDataWrapper { +export function useAsyncDataWrapper>( + obj: T, +): AsyncDataWrapper { const composable = {} as AsyncDataWrapper; const proto = Object.getPrototypeOf(obj); // Get function names from the object's prototype, excluding the constructor const functionNames = Object.getOwnPropertyNames(proto).filter( - key => key !== 'constructor' && typeof obj[key] === 'function' + key => key !== 'constructor' && typeof obj[key] === 'function', ); for (const key of functionNames) { @@ -89,27 +96,41 @@ export function useAsyncDataWrapper>(obj: T): Asyn // Reactive reference to arguments const argsRef = computed(() => argsSupplier!()); // Unique key for useAsyncData - const dataKeyRef = computed(() => `${key}-${JSON.stringify(argsRef.value)}`); + const dataKeyRef = computed( + () => `${key}-${JSON.stringify(argsRef.value)}`, + ); // Call useAsyncData with the generated key and function const asyncDataResult = useAsyncData( dataKeyRef.value, - () => originalFunction(...unref(argsRef)), + () => { + const result = originalFunction(...unref(argsRef)); + // Ensure we return a Promise + return result instanceof Promise ? result : Promise.resolve(result); + }, { // Re-execute when arguments change watch: [argsRef], // Spread additional options ...options, - } + }, ); return asyncDataResult; } else { // For functions without arguments - const asyncDataResult = useAsyncData(key, () => originalFunction(), { - // Spread additional options - ...options, - }); + const asyncDataResult = useAsyncData( + key, + () => { + const result = originalFunction(); + // Ensure we return a Promise + return result instanceof Promise ? result : Promise.resolve(result); + }, + { + // Spread additional options + ...options, + }, + ); return asyncDataResult; }