diff --git a/EXPLAINER.md b/EXPLAINER.md index dbe9e5f..c2392ec 100644 --- a/EXPLAINER.md +++ b/EXPLAINER.md @@ -230,8 +230,9 @@ if (!dir_ref) { return; } // Read directory contents. -for await (const entry of dir_ref.getEntries()) { +for await (const [name, entry] of dir_ref) { // entry is a FileSystemFileHandle or a FileSystemDirectoryHandle. + // name is equal to entry.name } // Get a specific file. @@ -302,7 +303,7 @@ const sandboxed_dir = await self.getSandboxedFileSystem(); // The website can freely create files and directories in this directory. const cache_dir = await sandboxed_dir.getDirectory('cache', {create: true}); -for await (const entry of cache_dir.getEntries()) { +for await (const entry of cache_dir.values()) { // Do something with entry. }; @@ -318,7 +319,7 @@ similar. Could still include some kind of permission prompt if needed. ```javascript const font_dir = await FileSystemDirectoryHandle.getSystemDirectory({type: 'fonts'}); -for await (const entry of font_dir.getEntries()) { +for await (const entry of font_dir.values()) { // Use font entry. }; ``` diff --git a/index.bs b/index.bs index c916546..fc85556 100644 --- a/index.bs +++ b/index.bs @@ -460,12 +460,11 @@ dictionary FileSystemRemoveOptions { [Exposed=(Window,Worker), SecureContext, Serializable] interface FileSystemDirectoryHandle : FileSystemHandle { + async iterable; + Promise getFile(USVString name, optional FileSystemGetFileOptions options = {}); Promise getDirectory(USVString name, optional FileSystemGetDirectoryOptions options = {}); - // This really returns an async iterable, but that is not yet expressable in WebIDL. - object getEntries(); - Promise removeEntry(USVString name, optional FileSystemRemoveOptions options = {}); Promise?> resolve(FileSystemHandle possibleDescendant); @@ -487,8 +486,82 @@ Issue(98): Having getFile methods in both FileSystemDirectoryHandle and FileSyst with very different behavior might be confusing? Perhaps rename at least one of them (but see also previous issue). -Issue(47): Should getEntries be its own method, or should FileSystemDirectoryHandle just be an async -iterable itself? +### Directory iteration ### {#api-filesystemdirectoryhandle-asynciterable} + +
+ : for await (let [|name|, |handle|] of |directoryHandle|) {} + : for await (let [|name|, |handle|] of |directoryHandle| . entries()) {} + : for await (let |handle| of |directoryHandle| . values()) {} + : for await (let |name| of |directoryHandle| . keys()) {} + :: Iterates over all entries whose parent is the entry represented by |directoryHandle|. Entries + that are created or deleted while the iteration is in progress might or might not be included. + No guarantees are given either way. +
+ +Advisement: In Chrome this is currently implemented as a `directoryHandle.getEntries()` method that can be used in a `for await..of` loop. +This `getEntries()` method returns more or less the same async iterable as what is returned by `values()` in this specification. +The proper async iterable declaration is not yet implemented. + +Issue(173): In the future we might want to add arguments to the async iterable declaration to +support for example recursive iteration. + +
+The [=asynchronous iterator initialization steps=] for a {{FileSystemDirectoryHandle}} |handle| +ant its async iterator |iterator| are: + +1. Let |entry| be |handle|'s [=FileSystemHandle/entry=]. + +1. Let |permissionStatus| be the result of running + |entry|'s [=query permission steps=] given + «[ "{{FileSystemHandlePermissionDescriptor/writable}}" → `false` ]» + and [=this=]'s [=relevant settings object=]. + +1. If |permissionStatus| is not {{PermissionState/"granted"}}, + throw a {{NotAllowedError}}. + +1. Set |iterator|'s past results to an empty [=/set=]. + +
+ +
+To [=get the next iteration result=] for a {{FileSystemDirectoryHandle}} |handle| +and its async iterator |iterator|: + +1. Let |promise| be [=a new promise=]. + +1. Let |directory| be |handle|'s [=FileSystemHandle/entry=]. + +1. Let |permissionStatus| be the result of running + |directory|'s [=query permission steps=] given + «[ "{{FileSystemHandlePermissionDescriptor/writable}}" → `false` ]» + and [=this=]'s [=relevant settings object=]. + +1. If |permissionStatus| is not {{PermissionState/"granted"}}, + reject |promise| with a {{NotAllowedError}} and return |promise|. + +1. Let |child| be an [=/entry=] in |directory|'s [=directory entry/children=], + such that |child|'s [=entry/name=] is not contained in |iterator|'s [=past results=], + or `null` if no such entry exists. + + Note: This is intentionally very vague about the iteration order. Different platforms + and file systems provide different guarantees about iteration order, and we want it to + be possible to efficiently implement this on all platforms. As such no guarantees are given + about the exact order in which elements are returned. + +1. If |child| is `null`, then: + 1. [=/Resolve=] |promise| with `undefined`. + +1. Otherwise: + 1. [=set/Append=] |child|'s [=entry/name=] to |iterator|'s [=past results=]. + 1. If |child| is a [=file entry=]: + 1. Let |result| be a new {{FileSystemFileHandle}} associated with |child|. + 1. Otherwise: + 1. Let |result| be a new {{FileSystemDirectoryHandle}} associated with |child|. + 1. [=/Resolve=] |promise| with (|child|'s [=entry/name=], |result|). + +1. Return |promise|. + +
### The {{FileSystemDirectoryHandle/getFile()}} method ### {#api-filesystemdirectoryhandle-getfile} @@ -625,33 +698,6 @@ invoked, must run these steps: -### The {{FileSystemDirectoryHandle/getEntries()}} method ### {#api-filesystemdirectoryhandle-getentries} - -
- : for await (const |handle| of |directoryHandle| . {{FileSystemDirectoryHandle/getEntries()}}) {} - :: Iterates over all entries whose parent is the entry represented by |directoryHandle|. -
- -Issue(158): Should {{FileSystemDirectoryHandle}} itself be async iterable, instead of having this getEntries method? - -
-The getEntries() method, when invoked, must run -these steps: - -1. Let |result| be [=a new promise=]. -1. Run the following steps [=in parallel=]: - 1. Let |entry| be [=this=]'s [=FileSystemHandle/entry=]. - 1. Let |permissionStatus| be the result of running - |entry|'s [=query permission steps=] given - «[ "{{FileSystemHandlePermissionDescriptor/writable}}" → `false` ]» - and [=this=]'s [=relevant settings object=]. - 1. If |permissionStatus| is not {{PermissionState/"granted"}}, - reject |result| with a {{NotAllowedError}} and abort. - 1. TODO (depends on WebIDL support for value async-iterators). -1. Return |result|. - -
- ### The {{FileSystemDirectoryHandle/removeEntry()}} method ### {#api-filesystemdirectoryhandle-removeentry}