feat(fs): accept baseDir in size (#3623)

In plugins/fs/guest-js/index.ts, the size function only sent `path`
although the Rust command accepts `options.baseDir` and the JSDoc example
passed `{ baseDir: BaseDirectory.AppData }` (a TS error, silently dropped
at runtime, so the relative path was rejected).

Adds an optional `options?: SizeOptions` parameter (new exported type).
api-iife.js regenerated. The e2e spec now measures a file and a directory
relative to AppData instead of working around the missing option.
This commit is contained in:
Lucas Fernandes Nogueira authored and GitHub committed 2026-09-23 12:58:03 -03:00
1 parent b46a88ff55
commit 97e865bc13
4 files changed
+30 -5

No files matched your search

+6
View File
@@ -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.
+5 -2
View File
@@ -116,10 +116,11 @@ describePlugin('fs', () => {
hasMtime: fileStat.mtime instanceof Date hasMtime: fileStat.mtime instanceof Date
}, },
lstatSize: fileLstat.size, lstatSize: fileLstat.size,
// `size` only takes absolute paths size: await api.fs.size(file, { baseDir }),
size: await api.fs.size( absoluteSize: await api.fs.size(
await api.path.join(await api.path.appDataDir(), file) await api.path.join(await api.path.appDataDir(), file)
), ),
dirSize: await api.fs.size(dir, { baseDir }),
dir: { isFile: dirStat.isFile, isDirectory: dirStat.isDirectory } dir: { isFile: dirStat.isFile, isDirectory: dirStat.isDirectory }
} }
}, dir) }, dir)
@@ -132,6 +133,8 @@ describePlugin('fs', () => {
}) })
expect(result.lstatSize).toBe(10) expect(result.lstatSize).toBe(10)
expect(result.size).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 }) expect(result.dir).toEqual({ isFile: false, isDirectory: true })
}) })
+1 -1
View File
@@ -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;e<t;e++)i*=256,i+=n[e];return i}(n.slice(-8)),o=n instanceof ArrayBuffer?new Uint8Array(n):n;return e.set(o.slice(0,o.length-8)),0===i?null:i}async seek(e,n){return await t.invoke("plugin:fs|seek",{rid:this.rid,offset:e,whence:n})}async stat(){return o(await t.invoke("plugin:fs|fstat",{rid:this.rid}))}async truncate(e){await t.invoke("plugin:fs|ftruncate",{rid:this.rid,len:e})}async write(e){return await t.invoke("plugin:fs|write",{rid:this.rid,data:e})}}async function a(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const i=await t.invoke("plugin:fs|open",{path:e instanceof URL?e.toString():e,options:n});return new r(i)}class s extends t.Resource{}async function c(e,n,i){const o=Array.isArray(e)?e:[e];for(const e of o)if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const r=new t.Channel;r.onmessage=n;const a=await t.invoke("plugin:fs|watch",{paths:o.map(e=>e 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,Line truncated 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;e<t;e++)i*=256,i+=n[e];return i}(n.slice(-8)),o=n instanceof ArrayBuffer?new Uint8Array(n):n;return e.set(o.slice(0,o.length-8)),0===i?null:i}async seek(e,n){return await t.invoke("plugin:fs|seek",{rid:this.rid,offset:e,whence:n})}async stat(){return o(await t.invoke("plugin:fs|fstat",{rid:this.rid}))}async truncate(e){await t.invoke("plugin:fs|ftruncate",{rid:this.rid,len:e})}async write(e){return await t.invoke("plugin:fs|write",{rid:this.rid,data:e})}}async function a(e,n){if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const i=await t.invoke("plugin:fs|open",{path:e instanceof URL?e.toString():e,options:n});return new r(i)}class s extends t.Resource{}async function c(e,n,i){const o=Array.isArray(e)?e:[e];for(const e of o)if(e instanceof URL&&"file:"!==e.protocol)throw new TypeError("Must be a file URL.");const r=new t.Channel;r.onmessage=n;const a=await t.invoke("plugin:fs|watch",{paths:o.map(e=>e 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,Line truncated
+18 -2
View File
@@ -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. * 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 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. * @returns A promise resolving to the size in bytes.
* @since 2.1.0 * @since 2.1.0
*/ */
async function size(path: string | URL): Promise<number> { async function size(
path: string | URL,
options?: SizeOptions
): Promise<number> {
if (path instanceof URL && path.protocol !== 'file:') { if (path instanceof URL && path.protocol !== 'file:') {
throw new TypeError('Must be a file URL.') throw new TypeError('Must be a file URL.')
} }
return await invoke('plugin:fs|size', { 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, TruncateOptions,
WriteFileOptions, WriteFileOptions,
ExistsOptions, ExistsOptions,
SizeOptions,
FileInfo, FileInfo,
WatchOptions, WatchOptions,
DebouncedWatchOptions, DebouncedWatchOptions,