diff --git a/.changes/feat-fs-size-options.md b/.changes/feat-fs-size-options.md new file mode 100644 index 000000000..463ae615e --- /dev/null +++ b/.changes/feat-fs-size-options.md @@ -0,0 +1,6 @@ +--- +fs: minor +fs-js: minor +--- + +Added an `options` parameter with `baseDir` to `size`, so relative paths can be measured, like the other functions and like the JSDoc example already showed. The Rust command already accepted it. diff --git a/packages/api-e2e/test/specs/fs.spec.ts b/packages/api-e2e/test/specs/fs.spec.ts index 32767d606..0d0d21993 100644 --- a/packages/api-e2e/test/specs/fs.spec.ts +++ b/packages/api-e2e/test/specs/fs.spec.ts @@ -116,10 +116,11 @@ describePlugin('fs', () => { hasMtime: fileStat.mtime instanceof Date }, lstatSize: fileLstat.size, - // `size` only takes absolute paths - size: await api.fs.size( + size: await api.fs.size(file, { baseDir }), + absoluteSize: await api.fs.size( await api.path.join(await api.path.appDataDir(), file) ), + dirSize: await api.fs.size(dir, { baseDir }), dir: { isFile: dirStat.isFile, isDirectory: dirStat.isDirectory } } }, dir) @@ -132,6 +133,8 @@ describePlugin('fs', () => { }) expect(result.lstatSize).toBe(10) expect(result.size).toBe(10) + expect(result.absoluteSize).toBe(10) + expect(result.dirSize).toBeGreaterThanOrEqual(10) expect(result.dir).toEqual({ isFile: false, isDirectory: true }) }) diff --git a/plugins/fs/api-iife.js b/plugins/fs/api-iife.js index ba0603886..fe949f75b 100644 --- a/plugins/fs/api-iife.js +++ b/plugins/fs/api-iife.js @@ -1 +1 @@ -if("__TAURI__"in window){var __TAURI_PLUGIN_FS__=function(e,n,t){"use strict";var i;function o(e){return{isFile:e.isFile,isDirectory:e.isDirectory,isSymlink:e.isSymlink,size:e.size,mtime:null!==e.mtime?new Date(e.mtime):null,atime:null!==e.atime?new Date(e.atime):null,birthtime:null!==e.birthtime?new Date(e.birthtime):null,readonly:e.readonly,fileAttributes:e.fileAttributes,dev:e.dev,ino:e.ino,mode:e.mode,nlink:e.nlink,uid:e.uid,gid:e.gid,rdev:e.rdev,blksize:e.blksize,blocks:e.blocks}}e.SeekMode=void 0,(i=e.SeekMode||(e.SeekMode={}))[i.Start=0]="Start",i[i.Current=1]="Current",i[i.End=2]="End";class r extends t.Resource{async read(e){if(0===e.byteLength)return 0;const n=await t.invoke("plugin:fs|read",{rid:this.rid,len:e.byteLength}),i=function(e){const n=new Uint8ClampedArray(e),t=n.byteLength;let i=0;for(let e=0;ee instanceof URL?e.toString():e),options:i,onEvent:r}),c=new s(a);return()=>{c.close()}}return Object.defineProperty(e,"BaseDirectory",{enumerable:!0,get:function(){return n.BaseDirectory}}),e.FileHandle=r,e.copyFile=async function(e,n,i){if(e instanceof URL&&"file:"!==e.protocol||n instanceof URL&&"file:"!==n.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|copy_file",{fromPath:e instanceof URL?e.toString():e,toPath:n instanceof URL?n.toString():n,options:i})},e.create=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const i=await t.invoke("plugin:fs|create",{path:e instanceof URL?e.toString():e,options:n});return new r(i)},e.exists=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");return await t.invoke("plugin:fs|exists",{path:e instanceof URL?e.toString():e,options:n})},e.lstat=async function(e,n){return o(await t.invoke("plugin:fs|lstat",{path:e instanceof URL?e.toString():e,options:n}))},e.mkdir=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|mkdir",{path:e instanceof URL?e.toString():e,options:n})},e.open=a,e.readDir=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");return await t.invoke("plugin:fs|read_dir",{path:e instanceof URL?e.toString():e,options:n})},e.readFile=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const i=await t.invoke("plugin:fs|read_file",{path:e instanceof URL?e.toString():e,options:n});return i instanceof ArrayBuffer?new Uint8Array(i):Uint8Array.from(i)},e.readTextFile=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const i=await t.invoke("plugin:fs|read_text_file",{path:e instanceof URL?e.toString():e,options:n}),o=i instanceof ArrayBuffer?i:Uint8Array.from(i);return new TextDecoder(n?.encoding??"utf-8").decode(o)},e.readTextFileLines=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const i=e instanceof URL?e.toString():e;return await Promise.resolve({path:i,rid:null,async next(){const e=new TextDecoder(n?.encoding??"utf-8");if(null===this.rid){const o=e.encoding;this.rid=await t.invoke("plugin:fs|read_text_file_lines",{path:i,options:null!=n?{...n,encoding:o}:void 0})}const o=await t.invoke("plugin:fs|read_text_file_lines_next",{rid:this.rid}),r=o instanceof ArrayBuffer?new Uint8Array(o):Uint8Array.from(o),a=1===r[r.byteLength-1];if(a)return this.rid=null,{value:null,done:a};return{value:e.decode(r.slice(0,r.byteLength-1)),done:a}},[Symbol.asyncIterator](){return this}})},e.remove=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|remove",{path:e instanceof URL?e.toString():e,options:n})},e.rename=async function(e,n,i){if(e instanceof URL&&"file:"!==e.protocol||n instanceof URL&&"file:"!==n.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|rename",{oldPath:e instanceof URL?e.toString():e,newPath:n instanceof URL?n.toString():n,options:i})},e.size=async function(e){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");return await t.invoke("plugin:fs|size",{path:e instanceof URL?e.toString():e})},e.startAccessingSecurityScopedResource=async function(e){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|start_accessing_security_scoped_resource",{path:e instanceof URL?e.toString():e})},e.stat=async function(e,n){return o(await t.invoke("plugin:fs|stat",{path:e instanceof URL?e.toString():e,options:n}))},e.stopAccessingSecurityScopedResource=async function(e){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|stop_accessing_security_scoped_resource",{path:e instanceof URL?e.toString():e})},e.truncate=async function(e,n,i){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|truncate",{path:e instanceof URL?e.toString():e,len:n,options:i})},e.watch=async function(e,n,t){return await c(e,n,{delayMs:2e3,...t})},e.watchImmediate=async function(e,n,t){return await c(e,n,{...t,delayMs:void 0})},e.writeFile=async function(e,n,i){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");if(n instanceof ReadableStream){const t=await a(e,{read:!1,create:!0,write:!0,...i}),o=n.getReader();try{for(;;){const{done:e,value:n}=await o.read();if(e)break;await t.write(n)}}finally{o.releaseLock(),await t.close()}}else await t.invoke("plugin:fs|write_file",n,{headers:{path:encodeURIComponent(e instanceof URL?e.toString():e),options:JSON.stringify(i)}})},e.writeTextFile=async function(e,n,i){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const o=new TextEncoder;await t.invoke("plugin:fs|write_text_file",o.encode(n),{headers:{path:encodeURIComponent(e instanceof URL?e.toString():e),options:JSON.stringify(i)}})},e}({},window.__TAURI__.path,window.__TAURI__.core);Object.defineProperty(window.__TAURI__,"fs",{value:__TAURI_PLUGIN_FS__})} +if("__TAURI__"in window){var __TAURI_PLUGIN_FS__=function(e,n,t){"use strict";var i;function o(e){return{isFile:e.isFile,isDirectory:e.isDirectory,isSymlink:e.isSymlink,size:e.size,mtime:null!==e.mtime?new Date(e.mtime):null,atime:null!==e.atime?new Date(e.atime):null,birthtime:null!==e.birthtime?new Date(e.birthtime):null,readonly:e.readonly,fileAttributes:e.fileAttributes,dev:e.dev,ino:e.ino,mode:e.mode,nlink:e.nlink,uid:e.uid,gid:e.gid,rdev:e.rdev,blksize:e.blksize,blocks:e.blocks}}e.SeekMode=void 0,(i=e.SeekMode||(e.SeekMode={}))[i.Start=0]="Start",i[i.Current=1]="Current",i[i.End=2]="End";class r extends t.Resource{async read(e){if(0===e.byteLength)return 0;const n=await t.invoke("plugin:fs|read",{rid:this.rid,len:e.byteLength}),i=function(e){const n=new Uint8ClampedArray(e),t=n.byteLength;let i=0;for(let e=0;ee instanceof URL?e.toString():e),options:i,onEvent:r}),c=new s(a);return()=>{c.close()}}return Object.defineProperty(e,"BaseDirectory",{enumerable:!0,get:function(){return n.BaseDirectory}}),e.FileHandle=r,e.copyFile=async function(e,n,i){if(e instanceof URL&&"file:"!==e.protocol||n instanceof URL&&"file:"!==n.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|copy_file",{fromPath:e instanceof URL?e.toString():e,toPath:n instanceof URL?n.toString():n,options:i})},e.create=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const i=await t.invoke("plugin:fs|create",{path:e instanceof URL?e.toString():e,options:n});return new r(i)},e.exists=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");return await t.invoke("plugin:fs|exists",{path:e instanceof URL?e.toString():e,options:n})},e.lstat=async function(e,n){return o(await t.invoke("plugin:fs|lstat",{path:e instanceof URL?e.toString():e,options:n}))},e.mkdir=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|mkdir",{path:e instanceof URL?e.toString():e,options:n})},e.open=a,e.readDir=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");return await t.invoke("plugin:fs|read_dir",{path:e instanceof URL?e.toString():e,options:n})},e.readFile=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const i=await t.invoke("plugin:fs|read_file",{path:e instanceof URL?e.toString():e,options:n});return i instanceof ArrayBuffer?new Uint8Array(i):Uint8Array.from(i)},e.readTextFile=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const i=await t.invoke("plugin:fs|read_text_file",{path:e instanceof URL?e.toString():e,options:n}),o=i instanceof ArrayBuffer?i:Uint8Array.from(i);return new TextDecoder(n?.encoding??"utf-8").decode(o)},e.readTextFileLines=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const i=e instanceof URL?e.toString():e;return await Promise.resolve({path:i,rid:null,async next(){const e=new TextDecoder(n?.encoding??"utf-8");if(null===this.rid){const o=e.encoding;this.rid=await t.invoke("plugin:fs|read_text_file_lines",{path:i,options:null!=n?{...n,encoding:o}:void 0})}const o=await t.invoke("plugin:fs|read_text_file_lines_next",{rid:this.rid}),r=o instanceof ArrayBuffer?new Uint8Array(o):Uint8Array.from(o),a=1===r[r.byteLength-1];if(a)return this.rid=null,{value:null,done:a};return{value:e.decode(r.slice(0,r.byteLength-1)),done:a}},[Symbol.asyncIterator](){return this}})},e.remove=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|remove",{path:e instanceof URL?e.toString():e,options:n})},e.rename=async function(e,n,i){if(e instanceof URL&&"file:"!==e.protocol||n instanceof URL&&"file:"!==n.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|rename",{oldPath:e instanceof URL?e.toString():e,newPath:n instanceof URL?n.toString():n,options:i})},e.size=async function(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");return await t.invoke("plugin:fs|size",{path:e instanceof URL?e.toString():e,options:n})},e.startAccessingSecurityScopedResource=async function(e){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|start_accessing_security_scoped_resource",{path:e instanceof URL?e.toString():e})},e.stat=async function(e,n){return o(await t.invoke("plugin:fs|stat",{path:e instanceof URL?e.toString():e,options:n}))},e.stopAccessingSecurityScopedResource=async function(e){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|stop_accessing_security_scoped_resource",{path:e instanceof URL?e.toString():e})},e.truncate=async function(e,n,i){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");await t.invoke("plugin:fs|truncate",{path:e instanceof URL?e.toString():e,len:n,options:i})},e.watch=async function(e,n,t){return await c(e,n,{delayMs:2e3,...t})},e.watchImmediate=async function(e,n,t){return await c(e,n,{...t,delayMs:void 0})},e.writeFile=async function(e,n,i){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");if(n instanceof ReadableStream){const t=await a(e,{read:!1,create:!0,write:!0,...i}),o=n.getReader();try{for(;;){const{done:e,value:n}=await o.read();if(e)break;await t.write(n)}}finally{o.releaseLock(),await t.close()}}else await t.invoke("plugin:fs|write_file",n,{headers:{path:encodeURIComponent(e instanceof URL?e.toString():e),options:JSON.stringify(i)}})},e.writeTextFile=async function(e,n,i){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const o=new TextEncoder;await t.invoke("plugin:fs|write_text_file",o.encode(n),{headers:{path:encodeURIComponent(e instanceof URL?e.toString():e),options:JSON.stringify(i)}})},e}({},window.__TAURI__.path,window.__TAURI__.core);Object.defineProperty(window.__TAURI__,"fs",{value:__TAURI_PLUGIN_FS__})} diff --git a/plugins/fs/guest-js/index.ts b/plugins/fs/guest-js/index.ts index 2bea26943..e3d39a754 100644 --- a/plugins/fs/guest-js/index.ts +++ b/plugins/fs/guest-js/index.ts @@ -1493,6 +1493,16 @@ async function watchImmediate( }) } +/** + * Options for the `size` function. + * + * @since 2.6.0 + */ +interface SizeOptions { + /** Base directory for `path`. */ + baseDir?: BaseDirectory +} + /** * Get the size of a file or directory. For files, the `stat` functions can be used as well. * @@ -1507,16 +1517,21 @@ async function watchImmediate( * ``` * * @param path The path of the file or directory to measure. + * @param options Options defining the base directory of `path` (since 2.6.0). * @returns A promise resolving to the size in bytes. * @since 2.1.0 */ -async function size(path: string | URL): Promise { +async function size( + path: string | URL, + options?: SizeOptions +): Promise { if (path instanceof URL && path.protocol !== 'file:') { throw new TypeError('Must be a file URL.') } return await invoke('plugin:fs|size', { - path: path instanceof URL ? path.toString() : path + path: path instanceof URL ? path.toString() : path, + options }) } @@ -1609,6 +1624,7 @@ export type { TruncateOptions, WriteFileOptions, ExistsOptions, + SizeOptions, FileInfo, WatchOptions, DebouncedWatchOptions,