@fgv/ts-web-extras 5.1.0-0 → 5.1.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. package/.rush/temp/chunked-rush-logs/ts-web-extras.build.chunks.jsonl +56 -33
  2. package/.rush/temp/chunked-rush-logs/ts-web-extras.test.chunks.jsonl +70 -0
  3. package/.rush/temp/operation/build/all.log +56 -33
  4. package/.rush/temp/operation/build/error.log +18 -0
  5. package/.rush/temp/operation/build/log-chunks.jsonl +56 -33
  6. package/.rush/temp/operation/build/state.json +1 -1
  7. package/.rush/temp/operation/test/all.log +70 -0
  8. package/.rush/temp/operation/test/error.log +16 -0
  9. package/.rush/temp/operation/test/log-chunks.jsonl +70 -0
  10. package/.rush/temp/operation/test/state.json +3 -0
  11. package/dist/packlets/file-tree/fileApiTreeAccessors.js +15 -0
  12. package/dist/packlets/file-tree/fileApiTreeAccessors.js.map +1 -1
  13. package/dist/packlets/file-tree/fileSystemAccessTreeAccessors.js +79 -10
  14. package/dist/packlets/file-tree/fileSystemAccessTreeAccessors.js.map +1 -1
  15. package/dist/packlets/file-tree/httpTreeAccessors.js +279 -0
  16. package/dist/packlets/file-tree/httpTreeAccessors.js.map +1 -0
  17. package/dist/packlets/file-tree/index.js +1 -0
  18. package/dist/packlets/file-tree/index.js.map +1 -1
  19. package/dist/packlets/file-tree/localStorageTreeAccessors.js +51 -0
  20. package/dist/packlets/file-tree/localStorageTreeAccessors.js.map +1 -1
  21. package/dist/test/unit/fileApiTreeAccessors.test.js +51 -0
  22. package/dist/test/unit/fileApiTreeAccessors.test.js.map +1 -1
  23. package/dist/test/unit/fileSystemAccessTreeAccessors.test.js +265 -160
  24. package/dist/test/unit/fileSystemAccessTreeAccessors.test.js.map +1 -1
  25. package/dist/test/unit/httpTreeAccessors.test.js +1000 -0
  26. package/dist/test/unit/httpTreeAccessors.test.js.map +1 -0
  27. package/dist/test/unit/localStorageTreeAccessors.test.js +218 -1
  28. package/dist/test/unit/localStorageTreeAccessors.test.js.map +1 -1
  29. package/dist/ts-web-extras.d.ts +124 -0
  30. package/docs/@fgv/namespaces/CryptoUtils/README.md +18 -0
  31. package/docs/@fgv/namespaces/CryptoUtils/classes/BrowserCryptoProvider.md +203 -0
  32. package/docs/@fgv/namespaces/CryptoUtils/classes/BrowserHashProvider.md +63 -0
  33. package/docs/@fgv/namespaces/CryptoUtils/functions/createBrowserCryptoProvider.md +18 -0
  34. package/docs/@fgv/namespaces/FileTreeHelpers/README.md +19 -0
  35. package/docs/@fgv/namespaces/FileTreeHelpers/functions/extractFileListMetadata.md +23 -0
  36. package/docs/@fgv/namespaces/FileTreeHelpers/functions/extractFileMetadata.md +23 -0
  37. package/docs/@fgv/namespaces/FileTreeHelpers/functions/fromDirectoryUpload.md +33 -0
  38. package/docs/@fgv/namespaces/FileTreeHelpers/functions/fromFileList.md +33 -0
  39. package/docs/@fgv/namespaces/FileTreeHelpers/functions/getOriginalFile.md +25 -0
  40. package/docs/@fgv/namespaces/FileTreeHelpers/variables/defaultFileApiTreeInitParams.md +11 -0
  41. package/docs/README.md +78 -0
  42. package/docs/classes/DirectoryHandleStore.md +116 -0
  43. package/docs/classes/FileApiTreeAccessors.md +286 -0
  44. package/docs/classes/FileSystemAccessTreeAccessors.md +557 -0
  45. package/docs/classes/HttpTreeAccessors.md +508 -0
  46. package/docs/classes/LocalStorageTreeAccessors.md +520 -0
  47. package/docs/functions/exportAsJson.md +23 -0
  48. package/docs/functions/exportUsingFileSystemAPI.md +26 -0
  49. package/docs/functions/extractDirectoryPath.md +23 -0
  50. package/docs/functions/isDirectoryHandle.md +23 -0
  51. package/docs/functions/isFileHandle.md +23 -0
  52. package/docs/functions/isFilePath.md +21 -0
  53. package/docs/functions/parseContextFilter.md +22 -0
  54. package/docs/functions/parseQualifierDefaults.md +22 -0
  55. package/docs/functions/parseResourceTypes.md +22 -0
  56. package/docs/functions/parseUrlParameters.md +15 -0
  57. package/docs/functions/safeShowDirectoryPicker.md +24 -0
  58. package/docs/functions/safeShowOpenFilePicker.md +24 -0
  59. package/docs/functions/safeShowSaveFilePicker.md +24 -0
  60. package/docs/functions/supportsFileSystemAccess.md +23 -0
  61. package/docs/interfaces/FilePickerAcceptType.md +16 -0
  62. package/docs/interfaces/FileSystemCreateWritableOptions.md +15 -0
  63. package/docs/interfaces/FileSystemDirectoryHandle.md +187 -0
  64. package/docs/interfaces/FileSystemFileHandle.md +106 -0
  65. package/docs/interfaces/FileSystemGetDirectoryOptions.md +15 -0
  66. package/docs/interfaces/FileSystemGetFileOptions.md +15 -0
  67. package/docs/interfaces/FileSystemHandle.md +69 -0
  68. package/docs/interfaces/FileSystemHandlePermissionDescriptor.md +15 -0
  69. package/docs/interfaces/FileSystemRemoveOptions.md +15 -0
  70. package/docs/interfaces/FileSystemWritableFileStream.md +127 -0
  71. package/docs/interfaces/IDirectoryHandleTreeInitializer.md +17 -0
  72. package/docs/interfaces/IFileHandleTreeInitializer.md +16 -0
  73. package/docs/interfaces/IFileListTreeInitializer.md +15 -0
  74. package/docs/interfaces/IFileMetadata.md +19 -0
  75. package/docs/interfaces/IFileSystemAccessTreeParams.md +30 -0
  76. package/docs/interfaces/IFsAccessApis.md +57 -0
  77. package/docs/interfaces/IHttpTreeParams.md +32 -0
  78. package/docs/interfaces/ILocalStorageTreeParams.md +30 -0
  79. package/docs/interfaces/IUrlConfigOptions.md +27 -0
  80. package/docs/interfaces/ShowDirectoryPickerOptions.md +17 -0
  81. package/docs/interfaces/ShowOpenFilePickerOptions.md +19 -0
  82. package/docs/interfaces/ShowSaveFilePickerOptions.md +19 -0
  83. package/docs/type-aliases/TreeInitializer.md +11 -0
  84. package/docs/type-aliases/WellKnownDirectory.md +11 -0
  85. package/docs/type-aliases/WindowWithFsAccess.md +11 -0
  86. package/docs/variables/DEFAULT_DIRECTORY_HANDLE_DB.md +11 -0
  87. package/docs/variables/DEFAULT_DIRECTORY_HANDLE_STORE.md +11 -0
  88. package/etc/ts-web-extras.api.md +33 -0
  89. package/lib/packlets/file-tree/fileApiTreeAccessors.d.ts +9 -0
  90. package/lib/packlets/file-tree/fileApiTreeAccessors.d.ts.map +1 -1
  91. package/lib/packlets/file-tree/fileApiTreeAccessors.js +15 -0
  92. package/lib/packlets/file-tree/fileApiTreeAccessors.js.map +1 -1
  93. package/lib/packlets/file-tree/fileSystemAccessTreeAccessors.d.ts +17 -1
  94. package/lib/packlets/file-tree/fileSystemAccessTreeAccessors.d.ts.map +1 -1
  95. package/lib/packlets/file-tree/fileSystemAccessTreeAccessors.js +78 -9
  96. package/lib/packlets/file-tree/fileSystemAccessTreeAccessors.js.map +1 -1
  97. package/lib/packlets/file-tree/httpTreeAccessors.d.ts +88 -0
  98. package/lib/packlets/file-tree/httpTreeAccessors.d.ts.map +1 -0
  99. package/lib/packlets/file-tree/httpTreeAccessors.js +283 -0
  100. package/lib/packlets/file-tree/httpTreeAccessors.js.map +1 -0
  101. package/lib/packlets/file-tree/index.d.ts +1 -0
  102. package/lib/packlets/file-tree/index.d.ts.map +1 -1
  103. package/lib/packlets/file-tree/index.js +1 -0
  104. package/lib/packlets/file-tree/index.js.map +1 -1
  105. package/lib/packlets/file-tree/localStorageTreeAccessors.d.ts +12 -0
  106. package/lib/packlets/file-tree/localStorageTreeAccessors.d.ts.map +1 -1
  107. package/lib/packlets/file-tree/localStorageTreeAccessors.js +51 -0
  108. package/lib/packlets/file-tree/localStorageTreeAccessors.js.map +1 -1
  109. package/lib/test/unit/fileApiTreeAccessors.test.js +51 -0
  110. package/lib/test/unit/fileApiTreeAccessors.test.js.map +1 -1
  111. package/lib/test/unit/fileSystemAccessTreeAccessors.test.js +265 -160
  112. package/lib/test/unit/fileSystemAccessTreeAccessors.test.js.map +1 -1
  113. package/lib/test/unit/httpTreeAccessors.test.d.ts +2 -0
  114. package/lib/test/unit/httpTreeAccessors.test.d.ts.map +1 -0
  115. package/lib/test/unit/httpTreeAccessors.test.js +1002 -0
  116. package/lib/test/unit/httpTreeAccessors.test.js.map +1 -0
  117. package/lib/test/unit/localStorageTreeAccessors.test.js +218 -1
  118. package/lib/test/unit/localStorageTreeAccessors.test.js.map +1 -1
  119. package/package.json +25 -25
  120. package/rush-logs/ts-web-extras.build.cache.log +0 -3
  121. package/rush-logs/ts-web-extras.build.error.log +18 -0
  122. package/rush-logs/ts-web-extras.build.log +56 -33
  123. package/rush-logs/ts-web-extras.test.cache.log +1 -0
  124. package/rush-logs/ts-web-extras.test.error.log +16 -0
  125. package/rush-logs/ts-web-extras.test.log +70 -0
  126. package/src/packlets/file-tree/fileApiTreeAccessors.ts +18 -0
  127. package/src/packlets/file-tree/fileSystemAccessTreeAccessors.ts +100 -8
  128. package/src/packlets/file-tree/httpTreeAccessors.ts +381 -0
  129. package/src/packlets/file-tree/index.ts +1 -0
  130. package/src/packlets/file-tree/localStorageTreeAccessors.ts +53 -0
  131. package/src/test/unit/fileApiTreeAccessors.test.ts +69 -0
  132. package/src/test/unit/fileSystemAccessTreeAccessors.test.ts +341 -188
  133. package/src/test/unit/httpTreeAccessors.test.ts +1278 -0
  134. package/src/test/unit/localStorageTreeAccessors.test.ts +269 -1
  135. package/temp/build/typescript/ts_8nwakTlr.json +1 -1
  136. package/temp/coverage/crypto/browserHashProvider.ts.html +304 -0
  137. package/temp/coverage/crypto/index.html +116 -0
  138. package/temp/coverage/crypto-utils/browserCryptoProvider.ts.html +1 -1
  139. package/temp/coverage/crypto-utils/browserHashProvider.ts.html +1 -1
  140. package/temp/coverage/crypto-utils/index.html +1 -1
  141. package/temp/coverage/file-tree/directoryHandleStore.ts.html +1 -1
  142. package/temp/coverage/file-tree/fileApiTreeAccessors.ts.html +60 -6
  143. package/temp/coverage/file-tree/fileSystemAccessTreeAccessors.ts.html +410 -134
  144. package/temp/coverage/file-tree/httpTreeAccessors.ts.html +1228 -0
  145. package/temp/coverage/file-tree/index.html +35 -20
  146. package/temp/coverage/file-tree/localStorageTreeAccessors.ts.html +318 -159
  147. package/temp/coverage/helpers/fileTreeHelpers.ts.html +1 -1
  148. package/temp/coverage/helpers/index.html +1 -1
  149. package/temp/coverage/index.html +11 -11
  150. package/temp/coverage/lcov-report/crypto/browserHashProvider.ts.html +304 -0
  151. package/temp/coverage/lcov-report/crypto/index.html +116 -0
  152. package/temp/coverage/lcov-report/crypto-utils/browserCryptoProvider.ts.html +1 -1
  153. package/temp/coverage/lcov-report/crypto-utils/browserHashProvider.ts.html +1 -1
  154. package/temp/coverage/lcov-report/crypto-utils/index.html +1 -1
  155. package/temp/coverage/lcov-report/file-tree/directoryHandleStore.ts.html +1 -1
  156. package/temp/coverage/lcov-report/file-tree/fileApiTreeAccessors.ts.html +60 -6
  157. package/temp/coverage/lcov-report/file-tree/fileSystemAccessTreeAccessors.ts.html +410 -134
  158. package/temp/coverage/lcov-report/file-tree/httpTreeAccessors.ts.html +1228 -0
  159. package/temp/coverage/lcov-report/file-tree/index.html +35 -20
  160. package/temp/coverage/lcov-report/file-tree/localStorageTreeAccessors.ts.html +318 -159
  161. package/temp/coverage/lcov-report/helpers/fileTreeHelpers.ts.html +1 -1
  162. package/temp/coverage/lcov-report/helpers/index.html +1 -1
  163. package/temp/coverage/lcov-report/index.html +11 -11
  164. package/temp/coverage/lcov-report/url-utils/index.html +1 -1
  165. package/temp/coverage/lcov-report/url-utils/urlParams.ts.html +1 -1
  166. package/temp/coverage/lcov.info +1920 -1196
  167. package/temp/coverage/url-utils/index.html +1 -1
  168. package/temp/coverage/url-utils/urlParams.ts.html +1 -1
  169. package/temp/test/jest/haste-map-b931e4e63102f86c5bd4949f7dced44f-9d713eb41149188b4e5c0ae3d86d0a57-2ad8e16b24e391b8cdbe50b55c137169 +0 -0
  170. package/temp/test/jest/perf-cache-b931e4e63102f86c5bd4949f7dced44f-da39a3ee5e6b4b0d3255bfef95601890 +1 -0
  171. package/temp/ts-web-extras.api.json +1313 -354
  172. package/temp/ts-web-extras.api.md +33 -0
  173. package/.rush/temp/81e0881271ff236956b2f52e8ca99da6574c6e1e.tar.log +0 -223
  174. package/docs/index.md +0 -34
  175. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider._constructor_.md +0 -50
  176. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.decrypt.md +0 -104
  177. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.derivekey.md +0 -88
  178. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.encrypt.md +0 -72
  179. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.frombase64.md +0 -56
  180. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.generatekey.md +0 -19
  181. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.generaterandombytes.md +0 -56
  182. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.md +0 -169
  183. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.tobase64.md +0 -56
  184. package/docs/ts-web-extras.cryptoutils.browserhashprovider.hashparts.md +0 -88
  185. package/docs/ts-web-extras.cryptoutils.browserhashprovider.hashstring.md +0 -72
  186. package/docs/ts-web-extras.cryptoutils.browserhashprovider.md +0 -66
  187. package/docs/ts-web-extras.cryptoutils.createbrowsercryptoprovider.md +0 -19
  188. package/docs/ts-web-extras.cryptoutils.md +0 -71
  189. package/docs/ts-web-extras.exportasjson.md +0 -70
  190. package/docs/ts-web-extras.exportusingfilesystemapi.md +0 -104
  191. package/docs/ts-web-extras.extractdirectorypath.md +0 -52
  192. package/docs/ts-web-extras.fileapitreeaccessors.create.md +0 -72
  193. package/docs/ts-web-extras.fileapitreeaccessors.createfromlocalstorage.md +0 -74
  194. package/docs/ts-web-extras.fileapitreeaccessors.createpersistent.md +0 -76
  195. package/docs/ts-web-extras.fileapitreeaccessors.extractfilemetadata.md +0 -54
  196. package/docs/ts-web-extras.fileapitreeaccessors.fromdirectoryupload.md +0 -72
  197. package/docs/ts-web-extras.fileapitreeaccessors.fromfilelist.md +0 -72
  198. package/docs/ts-web-extras.fileapitreeaccessors.getoriginalfile.md +0 -72
  199. package/docs/ts-web-extras.fileapitreeaccessors.md +0 -146
  200. package/docs/ts-web-extras.filepickeraccepttype.accept.md +0 -11
  201. package/docs/ts-web-extras.filepickeraccepttype.description.md +0 -11
  202. package/docs/ts-web-extras.filepickeraccepttype.md +0 -75
  203. package/docs/ts-web-extras.filesystemaccesstreeaccessors._constructor_.md +0 -114
  204. package/docs/ts-web-extras.filesystemaccesstreeaccessors.fileismutable.md +0 -52
  205. package/docs/ts-web-extras.filesystemaccesstreeaccessors.fromdirectoryhandle.md +0 -72
  206. package/docs/ts-web-extras.filesystemaccesstreeaccessors.getdirtypaths.md +0 -17
  207. package/docs/ts-web-extras.filesystemaccesstreeaccessors.isdirty.md +0 -17
  208. package/docs/ts-web-extras.filesystemaccesstreeaccessors.md +0 -159
  209. package/docs/ts-web-extras.filesystemaccesstreeaccessors.savefilecontents.md +0 -66
  210. package/docs/ts-web-extras.filesystemaccesstreeaccessors.synctodisk.md +0 -17
  211. package/docs/ts-web-extras.filesystemcreatewritableoptions_2.keepexistingdata.md +0 -11
  212. package/docs/ts-web-extras.filesystemcreatewritableoptions_2.md +0 -58
  213. package/docs/ts-web-extras.filesystemdirectoryhandle_2._symbol.asynciterator_.md +0 -15
  214. package/docs/ts-web-extras.filesystemdirectoryhandle_2.entries.md +0 -15
  215. package/docs/ts-web-extras.filesystemdirectoryhandle_2.getdirectoryhandle.md +0 -66
  216. package/docs/ts-web-extras.filesystemdirectoryhandle_2.getfilehandle.md +0 -66
  217. package/docs/ts-web-extras.filesystemdirectoryhandle_2.keys.md +0 -15
  218. package/docs/ts-web-extras.filesystemdirectoryhandle_2.kind.md +0 -11
  219. package/docs/ts-web-extras.filesystemdirectoryhandle_2.md +0 -146
  220. package/docs/ts-web-extras.filesystemdirectoryhandle_2.removeentry.md +0 -66
  221. package/docs/ts-web-extras.filesystemdirectoryhandle_2.resolve.md +0 -50
  222. package/docs/ts-web-extras.filesystemdirectoryhandle_2.values.md +0 -15
  223. package/docs/ts-web-extras.filesystemfilehandle_2.createwritable.md +0 -52
  224. package/docs/ts-web-extras.filesystemfilehandle_2.getfile.md +0 -15
  225. package/docs/ts-web-extras.filesystemfilehandle_2.kind.md +0 -11
  226. package/docs/ts-web-extras.filesystemfilehandle_2.md +0 -92
  227. package/docs/ts-web-extras.filesystemgetdirectoryoptions_2.create.md +0 -11
  228. package/docs/ts-web-extras.filesystemgetdirectoryoptions_2.md +0 -58
  229. package/docs/ts-web-extras.filesystemgetfileoptions_2.create.md +0 -11
  230. package/docs/ts-web-extras.filesystemgetfileoptions_2.md +0 -58
  231. package/docs/ts-web-extras.filesystemhandle_2.issameentry.md +0 -50
  232. package/docs/ts-web-extras.filesystemhandle_2.kind.md +0 -11
  233. package/docs/ts-web-extras.filesystemhandle_2.md +0 -119
  234. package/docs/ts-web-extras.filesystemhandle_2.name.md +0 -11
  235. package/docs/ts-web-extras.filesystemhandle_2.querypermission.md +0 -52
  236. package/docs/ts-web-extras.filesystemhandle_2.requestpermission.md +0 -52
  237. package/docs/ts-web-extras.filesystemhandlepermissiondescriptor.md +0 -58
  238. package/docs/ts-web-extras.filesystemhandlepermissiondescriptor.mode.md +0 -11
  239. package/docs/ts-web-extras.filesystemremoveoptions_2.md +0 -58
  240. package/docs/ts-web-extras.filesystemremoveoptions_2.recursive.md +0 -11
  241. package/docs/ts-web-extras.filesystemwritablefilestream_2.md +0 -57
  242. package/docs/ts-web-extras.filesystemwritablefilestream_2.seek.md +0 -50
  243. package/docs/ts-web-extras.filesystemwritablefilestream_2.truncate.md +0 -50
  244. package/docs/ts-web-extras.filesystemwritablefilestream_2.write.md +0 -50
  245. package/docs/ts-web-extras.filetreehelpers.defaultfileapitreeinitparams.md +0 -13
  246. package/docs/ts-web-extras.filetreehelpers.extractfilelistmetadata.md +0 -56
  247. package/docs/ts-web-extras.filetreehelpers.extractfilemetadata.md +0 -56
  248. package/docs/ts-web-extras.filetreehelpers.fromdirectoryupload.md +0 -76
  249. package/docs/ts-web-extras.filetreehelpers.fromfilelist.md +0 -76
  250. package/docs/ts-web-extras.filetreehelpers.getoriginalfile.md +0 -72
  251. package/docs/ts-web-extras.filetreehelpers.md +0 -102
  252. package/docs/ts-web-extras.idirectoryhandletreeinitializer.dirhandles.md +0 -11
  253. package/docs/ts-web-extras.idirectoryhandletreeinitializer.md +0 -100
  254. package/docs/ts-web-extras.idirectoryhandletreeinitializer.nonrecursive.md +0 -11
  255. package/docs/ts-web-extras.idirectoryhandletreeinitializer.prefix.md +0 -11
  256. package/docs/ts-web-extras.ifilehandletreeinitializer.filehandles.md +0 -11
  257. package/docs/ts-web-extras.ifilehandletreeinitializer.md +0 -79
  258. package/docs/ts-web-extras.ifilehandletreeinitializer.prefix.md +0 -11
  259. package/docs/ts-web-extras.ifilelisttreeinitializer.filelist.md +0 -11
  260. package/docs/ts-web-extras.ifilelisttreeinitializer.md +0 -58
  261. package/docs/ts-web-extras.ifilemetadata.lastmodified.md +0 -11
  262. package/docs/ts-web-extras.ifilemetadata.md +0 -124
  263. package/docs/ts-web-extras.ifilemetadata.name.md +0 -11
  264. package/docs/ts-web-extras.ifilemetadata.path.md +0 -11
  265. package/docs/ts-web-extras.ifilemetadata.size.md +0 -11
  266. package/docs/ts-web-extras.ifilemetadata.type.md +0 -11
  267. package/docs/ts-web-extras.ifilesystemaccesstreeparams.autosync.md +0 -13
  268. package/docs/ts-web-extras.ifilesystemaccesstreeparams.md +0 -78
  269. package/docs/ts-web-extras.ifilesystemaccesstreeparams.requirewritepermission.md +0 -13
  270. package/docs/ts-web-extras.ifsaccessapis.md +0 -56
  271. package/docs/ts-web-extras.ifsaccessapis.showdirectorypicker.md +0 -52
  272. package/docs/ts-web-extras.ifsaccessapis.showopenfilepicker.md +0 -52
  273. package/docs/ts-web-extras.ifsaccessapis.showsavefilepicker.md +0 -52
  274. package/docs/ts-web-extras.ilocalstoragetreeparams.autosync.md +0 -13
  275. package/docs/ts-web-extras.ilocalstoragetreeparams.md +0 -97
  276. package/docs/ts-web-extras.ilocalstoragetreeparams.pathtokeymap.md +0 -13
  277. package/docs/ts-web-extras.ilocalstoragetreeparams.storage.md +0 -13
  278. package/docs/ts-web-extras.isdirectoryhandle.md +0 -56
  279. package/docs/ts-web-extras.isfilehandle.md +0 -56
  280. package/docs/ts-web-extras.isfilepath.md +0 -52
  281. package/docs/ts-web-extras.iurlconfigoptions.config.md +0 -13
  282. package/docs/ts-web-extras.iurlconfigoptions.configstartdir.md +0 -13
  283. package/docs/ts-web-extras.iurlconfigoptions.contextfilter.md +0 -13
  284. package/docs/ts-web-extras.iurlconfigoptions.input.md +0 -13
  285. package/docs/ts-web-extras.iurlconfigoptions.inputstartdir.md +0 -13
  286. package/docs/ts-web-extras.iurlconfigoptions.interactive.md +0 -13
  287. package/docs/ts-web-extras.iurlconfigoptions.loadzip.md +0 -13
  288. package/docs/ts-web-extras.iurlconfigoptions.maxdistance.md +0 -13
  289. package/docs/ts-web-extras.iurlconfigoptions.md +0 -286
  290. package/docs/ts-web-extras.iurlconfigoptions.qualifierdefaults.md +0 -13
  291. package/docs/ts-web-extras.iurlconfigoptions.reducequalifiers.md +0 -13
  292. package/docs/ts-web-extras.iurlconfigoptions.resourcetypes.md +0 -13
  293. package/docs/ts-web-extras.iurlconfigoptions.zipfile.md +0 -13
  294. package/docs/ts-web-extras.iurlconfigoptions.zippath.md +0 -13
  295. package/docs/ts-web-extras.localstoragetreeaccessors.fileismutable.md +0 -56
  296. package/docs/ts-web-extras.localstoragetreeaccessors.fromstorage.md +0 -56
  297. package/docs/ts-web-extras.localstoragetreeaccessors.getdirtypaths.md +0 -19
  298. package/docs/ts-web-extras.localstoragetreeaccessors.isdirty.md +0 -19
  299. package/docs/ts-web-extras.localstoragetreeaccessors.md +0 -131
  300. package/docs/ts-web-extras.localstoragetreeaccessors.savefilecontents.md +0 -72
  301. package/docs/ts-web-extras.localstoragetreeaccessors.synctodisk.md +0 -19
  302. package/docs/ts-web-extras.md +0 -558
  303. package/docs/ts-web-extras.parsecontextfilter.md +0 -52
  304. package/docs/ts-web-extras.parsequalifierdefaults.md +0 -52
  305. package/docs/ts-web-extras.parseresourcetypes.md +0 -52
  306. package/docs/ts-web-extras.parseurlparameters.md +0 -17
  307. package/docs/ts-web-extras.safeshowdirectorypicker.md +0 -72
  308. package/docs/ts-web-extras.safeshowopenfilepicker.md +0 -72
  309. package/docs/ts-web-extras.safeshowsavefilepicker.md +0 -72
  310. package/docs/ts-web-extras.showdirectorypickeroptions.id.md +0 -11
  311. package/docs/ts-web-extras.showdirectorypickeroptions.md +0 -96
  312. package/docs/ts-web-extras.showdirectorypickeroptions.mode.md +0 -11
  313. package/docs/ts-web-extras.showdirectorypickeroptions.startin.md +0 -11
  314. package/docs/ts-web-extras.showopenfilepickeroptions.excludeacceptalloption.md +0 -11
  315. package/docs/ts-web-extras.showopenfilepickeroptions.id.md +0 -11
  316. package/docs/ts-web-extras.showopenfilepickeroptions.md +0 -134
  317. package/docs/ts-web-extras.showopenfilepickeroptions.multiple.md +0 -11
  318. package/docs/ts-web-extras.showopenfilepickeroptions.startin.md +0 -11
  319. package/docs/ts-web-extras.showopenfilepickeroptions.types.md +0 -11
  320. package/docs/ts-web-extras.showsavefilepickeroptions.excludeacceptalloption.md +0 -11
  321. package/docs/ts-web-extras.showsavefilepickeroptions.id.md +0 -11
  322. package/docs/ts-web-extras.showsavefilepickeroptions.md +0 -134
  323. package/docs/ts-web-extras.showsavefilepickeroptions.startin.md +0 -11
  324. package/docs/ts-web-extras.showsavefilepickeroptions.suggestedname.md +0 -11
  325. package/docs/ts-web-extras.showsavefilepickeroptions.types.md +0 -11
  326. package/docs/ts-web-extras.supportsfilesystemaccess.md +0 -56
  327. package/docs/ts-web-extras.treeinitializer.md +0 -15
  328. package/docs/ts-web-extras.wellknowndirectory.md +0 -13
  329. package/docs/ts-web-extras.windowwithfsaccess.md +0 -15
  330. package/temp/test/jest/haste-map-7492f1b44480e0cdd1f220078fb3afd8-c8dd6c3430605adeb2f1cadf4f75e791-8c9336785555d572065b28c111982ba4 +0 -0
  331. package/temp/test/jest/perf-cache-7492f1b44480e0cdd1f220078fb3afd8-da39a3ee5e6b4b0d3255bfef95601890 +0 -1
  332. /package/temp/test/jest/{jest-transform-cache-7492f1b44480e0cdd1f220078fb3afd8-79ef2876fae7ca75eedb2aa53dc48338/8d/package_8dcbedef69e4299f0f51fcda8f4f1c8e → jest-transform-cache-b931e4e63102f86c5bd4949f7dced44f-79ef2876fae7ca75eedb2aa53dc48338/b5/package_b5f57afc9ec2c011239b1608ee5bdfa5} +0 -0
@@ -21,6 +21,7 @@
21
21
  */
22
22
 
23
23
  import '@fgv/ts-utils-jest';
24
+ import { fail, type Result, Logging } from '@fgv/ts-utils';
24
25
  import { FileSystemAccessTreeAccessors } from '../../packlets/file-tree';
25
26
  import { FileApiTreeAccessors } from '../../packlets/file-tree';
26
27
  import { FileTree } from '@fgv/ts-json-base';
@@ -166,7 +167,7 @@ describe('FileSystemAccessTreeAccessors', () => {
166
167
 
167
168
  test('fails gracefully when queryPermission throws', async () => {
168
169
  const fileHandle = {
169
- kind: 'file' as const,
170
+ kind: 'file',
170
171
  name: 'collection.yaml',
171
172
  async getFile(): Promise<File> {
172
173
  return createMockFileHandle('collection.yaml', {
@@ -466,267 +467,419 @@ describe('FileSystemAccessTreeAccessors', () => {
466
467
  accessors.saveFileContents('/test.txt', 'modified').orThrow();
467
468
 
468
469
  // Verify file is marked dirty but not synced
469
- expect(accessors.isDirty()).toBe(true);
470
470
  expect(accessors.getDirtyPaths()).toContain('/test.txt');
471
471
 
472
472
  // In-memory content should be modified
473
473
  expect(accessors.getFileContents('/test.txt')).toSucceedWith('modified');
474
474
  });
475
- });
476
- });
477
475
 
478
- describe('fileIsMutable', () => {
479
- test('returns persistent detail when write permission granted', async () => {
480
- const dirHandle = createMockDirectoryHandle('/', {
481
- 'test.txt': { content: 'test', type: 'text/plain' }
476
+ test('logs when save auto-sync returns a failure Result', async () => {
477
+ const logger = {
478
+ detail: jest.fn(),
479
+ info: jest.fn(),
480
+ warn: jest.fn(),
481
+ error: jest.fn()
482
+ } as unknown as Logging.LogReporter<unknown>;
483
+ const dirHandle = createMockDirectoryHandle('/', {
484
+ 'test.txt': { content: 'original', type: 'text/plain' }
485
+ });
486
+
487
+ const accessors = (
488
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, {
489
+ mutable: true,
490
+ autoSync: true,
491
+ logger
492
+ })
493
+ ).orThrow();
494
+
495
+ (
496
+ accessors as unknown as {
497
+ _syncFile: (_path: string) => Promise<Result<void>>;
498
+ }
499
+ )._syncFile = async () => fail<void>('simulated save sync failure');
500
+
501
+ accessors.saveFileContents('/test.txt', 'modified').orThrow();
502
+ await new Promise<void>((resolve) => setTimeout(resolve, 0));
503
+
504
+ expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('simulated save sync failure'));
482
505
  });
483
506
 
484
- const accessors = (
485
- await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
486
- ).orThrow();
507
+ test('logs when delete auto-sync throws unexpectedly', async () => {
508
+ const logger = {
509
+ detail: jest.fn(),
510
+ info: jest.fn(),
511
+ warn: jest.fn(),
512
+ error: jest.fn()
513
+ } as unknown as Logging.LogReporter<unknown>;
514
+ const dirHandle = createMockDirectoryHandle('/', {
515
+ 'test.txt': { content: 'original', type: 'text/plain' }
516
+ });
487
517
 
488
- const result = accessors.fileIsMutable('/test.txt');
489
- expect(result).toSucceedWithDetail(true, 'persistent');
490
- });
518
+ const accessors = (
519
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, {
520
+ mutable: true,
521
+ autoSync: true,
522
+ logger
523
+ })
524
+ ).orThrow();
491
525
 
492
- test('returns transient detail when write permission not granted', async () => {
493
- const dirHandle = createMockDirectoryHandle(
494
- '/',
495
- { 'test.txt': { content: 'test', type: 'text/plain' } },
496
- { hasWritePermission: false }
497
- );
526
+ (
527
+ accessors as unknown as {
528
+ _deleteFileFromDisk: (_path: string) => Promise<Result<void>>;
529
+ }
530
+ )._deleteFileFromDisk = async () => {
531
+ throw new Error('simulated delete throw');
532
+ };
498
533
 
499
- const accessors = (
500
- await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, {
501
- mutable: true,
502
- requireWritePermission: false
503
- })
504
- ).orThrow();
534
+ accessors.deleteFile('/test.txt').orThrow();
535
+ await new Promise<void>((resolve) => setTimeout(resolve, 0));
505
536
 
506
- const result = accessors.fileIsMutable('/test.txt');
507
- expect(result).toSucceedWithDetail(true, 'transient');
537
+ expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('simulated delete throw'));
538
+ });
508
539
  });
509
540
 
510
- test('returns not-mutable when mutability disabled', async () => {
511
- const dirHandle = createMockDirectoryHandle('/', {
512
- 'test.txt': { content: 'test', type: 'text/plain' }
541
+ describe('fileIsMutable', () => {
542
+ test('returns persistent detail when write permission granted', async () => {
543
+ const dirHandle = createMockDirectoryHandle('/', {
544
+ 'test.txt': { content: 'test', type: 'text/plain' }
545
+ });
546
+
547
+ const accessors = (
548
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
549
+ ).orThrow();
550
+
551
+ const result = accessors.fileIsMutable('/test.txt');
552
+ expect(result).toSucceedWithDetail(true, 'persistent');
513
553
  });
514
554
 
515
- const accessors = (
516
- await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: false })
517
- ).orThrow();
555
+ test('returns transient detail when write permission not granted', async () => {
556
+ const dirHandle = createMockDirectoryHandle(
557
+ '/',
558
+ { 'test.txt': { content: 'test', type: 'text/plain' } },
559
+ { hasWritePermission: false }
560
+ );
518
561
 
519
- const result = accessors.fileIsMutable('/test.txt');
520
- expect(result).toFailWithDetail(/mutability is disabled/i, 'not-mutable');
521
- });
522
- });
562
+ const accessors = (
563
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, {
564
+ mutable: true,
565
+ requireWritePermission: false
566
+ })
567
+ ).orThrow();
523
568
 
524
- describe('integration with FileApiTreeAccessors', () => {
525
- test('createPersistent creates FileTree with persistent accessors', async () => {
526
- const dirHandle = createMockDirectoryHandle('/', {
527
- 'test.txt': { content: 'test content', type: 'text/plain' }
569
+ const result = accessors.fileIsMutable('/test.txt');
570
+ expect(result).toSucceedWithDetail(true, 'transient');
528
571
  });
529
572
 
530
- const result = await FileApiTreeAccessors.createPersistent(dirHandle, { mutable: true });
531
- expect(result).toSucceed();
573
+ test('returns not-mutable when mutability disabled', async () => {
574
+ const dirHandle = createMockDirectoryHandle('/', {
575
+ 'test.txt': { content: 'test', type: 'text/plain' }
576
+ });
532
577
 
533
- const tree = result.orThrow();
534
- expect(tree).toBeInstanceOf(FileTree.FileTree);
535
- expect(FileTree.isPersistentAccessors(tree.hal)).toBe(true);
578
+ const accessors = (
579
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: false })
580
+ ).orThrow();
536
581
 
537
- const file = tree.getFile('/test.txt').orThrow();
538
- expect(file.getIsMutable()).toSucceedWithDetail(true, 'persistent');
582
+ const result = accessors.fileIsMutable('/test.txt');
583
+ expect(result).toFailWithDetail(/mutability is disabled/i, 'not-mutable');
584
+ });
539
585
  });
540
586
 
541
- test('createPersistent with autoSync option', async () => {
542
- const dirHandle = createMockDirectoryHandle('/', {
543
- 'test.txt': { content: 'original', type: 'text/plain' }
544
- });
587
+ describe('integration with FileApiTreeAccessors', () => {
588
+ test('createPersistent creates FileTree with persistent accessors', async () => {
589
+ const dirHandle = createMockDirectoryHandle('/', {
590
+ 'test.txt': { content: 'test content', type: 'text/plain' }
591
+ });
545
592
 
546
- const result = await FileApiTreeAccessors.createPersistent(dirHandle, {
547
- mutable: true,
548
- autoSync: true
549
- });
593
+ const result = await FileApiTreeAccessors.createPersistent(dirHandle, { mutable: true });
594
+ expect(result).toSucceed();
550
595
 
551
- expect(result).toSucceedAndSatisfy((tree) => {
596
+ const tree = result.orThrow();
552
597
  expect(tree).toBeInstanceOf(FileTree.FileTree);
598
+ expect(FileTree.isPersistentAccessors(tree.hal)).toBe(true);
599
+
600
+ const file = tree.getFile('/test.txt').orThrow();
601
+ expect(FileTree.isMutableFileItem(file)).toBe(true);
602
+ if (FileTree.isMutableFileItem(file)) {
603
+ expect(file.getIsMutable()).toSucceedWithDetail(true, 'persistent');
604
+ }
553
605
  });
554
606
 
555
- const tree = result.orThrow();
556
- const file = tree.getFile('/test.txt').orThrow();
557
- file.setRawContents('modified').orThrow();
607
+ test('createPersistent with autoSync option', async () => {
608
+ const dirHandle = createMockDirectoryHandle('/', {
609
+ 'test.txt': { content: 'original', type: 'text/plain' }
610
+ });
558
611
 
559
- // Give auto-sync time to complete
560
- await new Promise((resolve) => setTimeout(resolve, 10));
612
+ const result = await FileApiTreeAccessors.createPersistent(dirHandle, {
613
+ mutable: true,
614
+ autoSync: true
615
+ });
561
616
 
562
- // Verify file was written
563
- const fileHandle = await dirHandle.getFileHandle('test.txt');
564
- const diskFile = await fileHandle.getFile();
565
- const content = await diskFile.text();
566
- expect(content).toBe('modified');
567
- });
617
+ expect(result).toSucceedAndSatisfy((tree) => {
618
+ expect(tree).toBeInstanceOf(FileTree.FileTree);
619
+ });
568
620
 
569
- test('createPersistent fails with appropriate error', async () => {
570
- const dirHandle = createMockDirectoryHandle(
571
- '/',
572
- { 'test.txt': { content: 'test', type: 'text/plain' } },
573
- { hasWritePermission: false }
574
- );
621
+ const tree = result.orThrow();
622
+ const file = tree.getFile('/test.txt').orThrow();
623
+ expect(FileTree.isMutableFileItem(file)).toBe(true);
624
+ if (FileTree.isMutableFileItem(file)) {
625
+ file.setRawContents('modified').orThrow();
626
+ }
575
627
 
576
- const result = await FileApiTreeAccessors.createPersistent(dirHandle, {
577
- requireWritePermission: true
628
+ // Give auto-sync time to complete
629
+ await new Promise((resolve) => setTimeout(resolve, 10));
630
+
631
+ // Verify file was written
632
+ const fileHandle = await dirHandle.getFileHandle('test.txt');
633
+ const diskFile = await fileHandle.getFile();
634
+ const content = await diskFile.text();
635
+ expect(content).toBe('modified');
578
636
  });
579
- expect(result).toFailWith(/write permission required/i);
580
- });
581
- });
582
637
 
583
- describe('error handling', () => {
584
- test('handles permission query errors gracefully', async () => {
585
- const dirHandle = createMockDirectoryHandle(
586
- '/',
587
- { 'test.txt': { content: 'test', type: 'text/plain' } },
588
- { permissionError: true }
589
- );
638
+ test('createPersistent fails with appropriate error', async () => {
639
+ const dirHandle = createMockDirectoryHandle(
640
+ '/',
641
+ { 'test.txt': { content: 'test', type: 'text/plain' } },
642
+ { hasWritePermission: false }
643
+ );
590
644
 
591
- const result = await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, {
592
- requireWritePermission: false
645
+ const result = await FileApiTreeAccessors.createPersistent(dirHandle, {
646
+ requireWritePermission: true
647
+ });
648
+ expect(result).toFailWith(/write permission required/i);
593
649
  });
594
- // Should succeed but without write permission due to error
595
- expect(result).toSucceed();
596
650
  });
597
651
 
598
- test('handles permission status "prompt" by requesting permission', async () => {
599
- const dirHandle = createMockDirectoryHandle(
600
- '/',
601
- { 'test.txt': { content: 'test', type: 'text/plain' } },
602
- { permissionStatus: 'prompt', requestGranted: true }
603
- );
652
+ describe('error handling', () => {
653
+ test('handles permission query errors gracefully', async () => {
654
+ const dirHandle = createMockDirectoryHandle(
655
+ '/',
656
+ { 'test.txt': { content: 'test', type: 'text/plain' } },
657
+ { permissionError: true }
658
+ );
604
659
 
605
- const result = await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, {
606
- requireWritePermission: true
660
+ const result = await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, {
661
+ requireWritePermission: false
662
+ });
663
+ // Should succeed but without write permission due to error
664
+ expect(result).toSucceed();
607
665
  });
608
- expect(result).toSucceedAndSatisfy((accessors) => {
609
- expect(accessors).toBeInstanceOf(FileSystemAccessTreeAccessors);
666
+
667
+ test('handles permission status "prompt" by requesting permission', async () => {
668
+ const dirHandle = createMockDirectoryHandle(
669
+ '/',
670
+ { 'test.txt': { content: 'test', type: 'text/plain' } },
671
+ { permissionStatus: 'prompt', requestGranted: true }
672
+ );
673
+
674
+ const result = await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, {
675
+ requireWritePermission: true
676
+ });
677
+ expect(result).toSucceedAndSatisfy((accessors) => {
678
+ expect(accessors).toBeInstanceOf(FileSystemAccessTreeAccessors);
679
+ });
610
680
  });
611
- });
612
681
 
613
- test('handles sync failures with aggregated errors', async () => {
614
- const dirHandle = createMockDirectoryHandle('/', {
615
- 'file1.txt': { content: 'content1', type: 'text/plain' },
616
- 'file2.txt': { content: 'content2', type: 'text/plain' }
682
+ test('handles sync failures with aggregated errors', async () => {
683
+ const dirHandle = createMockDirectoryHandle('/', {
684
+ 'file1.txt': { content: 'content1', type: 'text/plain' },
685
+ 'file2.txt': { content: 'content2', type: 'text/plain' }
686
+ });
687
+
688
+ const accessors = (
689
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
690
+ ).orThrow();
691
+
692
+ // Modify files
693
+ accessors.saveFileContents('/file1.txt', 'modified1').orThrow();
694
+ accessors.saveFileContents('/file2.txt', 'modified2').orThrow();
695
+
696
+ // Replace the file handles with ones that fail to write
697
+ const handles = (accessors as any)._handles as Map<string, any>;
698
+ for (const [, handle] of handles) {
699
+ handle.createWritable = jest.fn().mockRejectedValue(new Error('Write permission denied'));
700
+ }
701
+
702
+ const syncResult = await accessors.syncToDisk();
703
+ expect(syncResult).toFailWith(/Failed to sync 2 file\(s\)/i);
617
704
  });
618
705
 
619
- const accessors = (
620
- await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
621
- ).orThrow();
706
+ test('handles getFileContents failure during sync', async () => {
707
+ const dirHandle = createMockDirectoryHandle('/', {
708
+ 'test.txt': { content: 'original', type: 'text/plain' }
709
+ });
622
710
 
623
- // Modify files
624
- accessors.saveFileContents('/file1.txt', 'modified1').orThrow();
625
- accessors.saveFileContents('/file2.txt', 'modified2').orThrow();
711
+ const accessors = (
712
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
713
+ ).orThrow();
626
714
 
627
- // Replace the file handles with ones that fail to write
628
- const handles = (accessors as any)._handles as Map<string, any>;
629
- for (const [, handle] of handles) {
630
- handle.createWritable = jest.fn().mockRejectedValue(new Error('Write permission denied'));
631
- }
715
+ // Add a new file
716
+ accessors.saveFileContents('/newfile.txt', 'new content').orThrow();
632
717
 
633
- const syncResult = await accessors.syncToDisk();
634
- expect(syncResult).toFailWith(/Failed to sync 2 file\(s\)/i);
635
- });
718
+ // Override getFileContents to fail
719
+ const originalGetFileContents = accessors.getFileContents.bind(accessors);
720
+ accessors.getFileContents = jest.fn((path: string) => {
721
+ if (path === '/newfile.txt') {
722
+ return { isSuccess: () => false, isFailure: () => true, message: 'File read error' } as any;
723
+ }
724
+ return originalGetFileContents(path);
725
+ });
636
726
 
637
- test('handles getFileContents failure during sync', async () => {
638
- const dirHandle = createMockDirectoryHandle('/', {
639
- 'test.txt': { content: 'original', type: 'text/plain' }
727
+ const syncResult = await accessors.syncToDisk();
728
+ expect(syncResult).toFailWith(/File read error/i);
640
729
  });
641
730
 
642
- const accessors = (
643
- await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
644
- ).orThrow();
731
+ test('handles file write failure during sync', async () => {
732
+ const dirHandle = createMockDirectoryHandle('/', {
733
+ 'test.txt': { content: 'original', type: 'text/plain' }
734
+ });
645
735
 
646
- // Add a new file
647
- accessors.saveFileContents('/newfile.txt', 'new content').orThrow();
736
+ const accessors = (
737
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
738
+ ).orThrow();
648
739
 
649
- // Override getFileContents to fail
650
- const originalGetFileContents = accessors.getFileContents.bind(accessors);
651
- accessors.getFileContents = jest.fn((path: string) => {
652
- if (path === '/newfile.txt') {
653
- return { isSuccess: () => false, isFailure: () => true, message: 'File read error' } as any;
654
- }
655
- return originalGetFileContents(path);
740
+ accessors.saveFileContents('/test.txt', 'modified').orThrow();
741
+
742
+ // Replace the handle with one that fails to write
743
+ const handles = (accessors as any)._handles as Map<string, any>;
744
+ const handle = handles.get('/test.txt');
745
+ handle.createWritable = jest.fn().mockRejectedValue(new Error('Disk full'));
746
+
747
+ const syncResult = await accessors.syncToDisk();
748
+ expect(syncResult).toFailWith(/Failed to write file.*Disk full/i);
656
749
  });
657
750
 
658
- const syncResult = await accessors.syncToDisk();
659
- expect(syncResult).toFailWith(/File read error/i);
660
- });
751
+ test('handles invalid file path with no filename', async () => {
752
+ const dirHandle = createMockDirectoryHandle('/', {
753
+ 'existing.txt': { content: 'existing', type: 'text/plain' }
754
+ });
661
755
 
662
- test('handles file write failure during sync', async () => {
663
- const dirHandle = createMockDirectoryHandle('/', {
664
- 'test.txt': { content: 'original', type: 'text/plain' }
756
+ const accessors = (
757
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
758
+ ).orThrow();
759
+
760
+ // Override resolveAbsolutePath to return an empty path to trigger the error
761
+ const originalResolveAbsolutePath = (accessors as any).resolveAbsolutePath.bind(accessors);
762
+ (accessors as any).resolveAbsolutePath = jest.fn((path: string) => {
763
+ if (path === '/badpath') {
764
+ return ''; // This will result in no parts after split
765
+ }
766
+ return originalResolveAbsolutePath(path);
767
+ });
768
+
769
+ // Create a new file with the bad path - don't throw if it fails
770
+ const saveResult = accessors.saveFileContents('/badpath', 'content');
771
+ if (saveResult.isFailure()) {
772
+ // saveFileContents itself might reject the path
773
+ expect(saveResult).toFailWith(/invalid file path/i);
774
+ } else {
775
+ // If save succeeded, sync should fail
776
+ const syncResult = await accessors.syncToDisk();
777
+ expect(syncResult).toFailWith(/Invalid file path/i);
778
+ }
665
779
  });
666
780
 
667
- const accessors = (
668
- await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
669
- ).orThrow();
781
+ test('handles file creation failure in _createAndWriteFile', async () => {
782
+ const dirHandle = createMockDirectoryHandle('/', {
783
+ 'existing.txt': { content: 'existing', type: 'text/plain' }
784
+ });
670
785
 
671
- accessors.saveFileContents('/test.txt', 'modified').orThrow();
786
+ const accessors = (
787
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
788
+ ).orThrow();
672
789
 
673
- // Replace the handle with one that fails to write
674
- const handles = (accessors as any)._handles as Map<string, any>;
675
- const handle = handles.get('/test.txt');
676
- handle.createWritable = jest.fn().mockRejectedValue(new Error('Disk full'));
790
+ // Add a new file that will need to be created
791
+ accessors.saveFileContents('/newdir/newfile.txt', 'new content').orThrow();
677
792
 
678
- const syncResult = await accessors.syncToDisk();
679
- expect(syncResult).toFailWith(/Failed to write file.*Disk full/i);
680
- });
793
+ // Mock getDirectoryHandle to fail
794
+ const rootDir = (accessors as any)._rootDir;
795
+ rootDir.getDirectoryHandle = jest.fn().mockRejectedValue(new Error('Permission denied'));
681
796
 
682
- test('handles invalid file path with no filename', async () => {
683
- const dirHandle = createMockDirectoryHandle('/', {
684
- 'existing.txt': { content: 'existing', type: 'text/plain' }
797
+ const syncResult = await accessors.syncToDisk();
798
+ expect(syncResult).toFailWith(/Failed to create file.*Permission denied/i);
685
799
  });
686
800
 
687
- const accessors = (
688
- await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
689
- ).orThrow();
801
+ test('successfully deletes a root-level file from disk via syncToDisk pending deletions', async () => {
802
+ // Covers lines 329-333: the pending deletions loop in syncToDisk
803
+ const dirHandle = createMockDirectoryHandle('/', {
804
+ 'toDelete.txt': { content: 'will be deleted', type: 'text/plain' },
805
+ 'keep.txt': { content: 'stays', type: 'text/plain' }
806
+ });
690
807
 
691
- // Override resolveAbsolutePath to return an empty path to trigger the error
692
- const originalResolveAbsolutePath = (accessors as any).resolveAbsolutePath.bind(accessors);
693
- (accessors as any).resolveAbsolutePath = jest.fn((path: string) => {
694
- if (path === '/badpath') {
695
- return ''; // This will result in no parts after split
696
- }
697
- return originalResolveAbsolutePath(path);
808
+ const accessors = (
809
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
810
+ ).orThrow();
811
+
812
+ // Delete the file from in-memory tree
813
+ accessors.deleteFile('/toDelete.txt').orThrow();
814
+ expect(accessors.isDirty()).toBe(true);
815
+ expect(accessors.getDirtyPaths()).toContain('/toDelete.txt');
816
+
817
+ // syncToDisk should process the pending deletion
818
+ const syncResult = await accessors.syncToDisk();
819
+ expect(syncResult).toSucceed();
820
+ expect(accessors.isDirty()).toBe(false);
698
821
  });
699
822
 
700
- // Create a new file with the bad path - don't throw if it fails
701
- const saveResult = accessors.saveFileContents('/badpath', 'content');
702
- if (saveResult.isFailure()) {
703
- // saveFileContents itself might reject the path
704
- expect(saveResult).toFailWith(/invalid file path/i);
705
- } else {
706
- // If save succeeded, sync should fail
823
+ test('successfully deletes a nested file from disk via syncToDisk (navigates parent dirs)', async () => {
824
+ // Covers lines 468-469: getDirectoryHandle navigation loop in _deleteFileFromDisk
825
+ const dirHandle = createMockDirectoryHandle('/', {
826
+ 'src/utils/helper.txt': { content: 'to be deleted', type: 'text/plain' },
827
+ 'src/index.txt': { content: 'stays', type: 'text/plain' }
828
+ });
829
+
830
+ const accessors = (
831
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
832
+ ).orThrow();
833
+
834
+ // Delete the nested file
835
+ accessors.deleteFile('/src/utils/helper.txt').orThrow();
836
+ expect(accessors.isDirty()).toBe(true);
837
+
707
838
  const syncResult = await accessors.syncToDisk();
708
- expect(syncResult).toFailWith(/Invalid file path/i);
709
- }
710
- });
839
+ expect(syncResult).toSucceed();
840
+ expect(accessors.isDirty()).toBe(false);
841
+ });
711
842
 
712
- test('handles file creation failure in _createAndWriteFile', async () => {
713
- const dirHandle = createMockDirectoryHandle('/', {
714
- 'existing.txt': { content: 'existing', type: 'text/plain' }
843
+ test('aggregates deletion errors when _deleteFileFromDisk fails during syncToDisk', async () => {
844
+ // Covers lines 330-332: the error aggregation when _deleteFileFromDisk returns failure
845
+ const dirHandle = createMockDirectoryHandle('/', {
846
+ 'toDelete.txt': { content: 'content', type: 'text/plain' }
847
+ });
848
+
849
+ const accessors = (
850
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
851
+ ).orThrow();
852
+
853
+ accessors.deleteFile('/toDelete.txt').orThrow();
854
+
855
+ // Make removeEntry fail to trigger the error path in _deleteFileFromDisk
856
+ const rootDir = (accessors as any)._rootDir;
857
+ rootDir.removeEntry = jest.fn().mockRejectedValue(new Error('Cannot delete: file locked'));
858
+
859
+ const syncResult = await accessors.syncToDisk();
860
+ expect(syncResult).toFailWith(/Failed to sync 1 file/i);
861
+ expect(syncResult).toFailWith(/delete.*toDelete\.txt/i);
715
862
  });
716
863
 
717
- const accessors = (
718
- await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
719
- ).orThrow();
864
+ test('catch block in _deleteFileFromDisk when removeEntry throws', async () => {
865
+ // Covers lines 473-476: the catch block in _deleteFileFromDisk
866
+ const dirHandle = createMockDirectoryHandle('/', {
867
+ 'target.txt': { content: 'content', type: 'text/plain' }
868
+ });
869
+
870
+ const accessors = (
871
+ await FileSystemAccessTreeAccessors.fromDirectoryHandle(dirHandle, { mutable: true })
872
+ ).orThrow();
720
873
 
721
- // Add a new file that will need to be created
722
- accessors.saveFileContents('/newdir/newfile.txt', 'new content').orThrow();
874
+ accessors.deleteFile('/target.txt').orThrow();
723
875
 
724
- // Mock getDirectoryHandle to fail
725
- const rootDir = (accessors as any)._rootDir;
726
- rootDir.getDirectoryHandle = jest.fn().mockRejectedValue(new Error('Permission denied'));
876
+ // Directly make _rootDir.removeEntry throw a non-Error value to test the catch branch
877
+ const rootDir = (accessors as any)._rootDir;
878
+ rootDir.removeEntry = jest.fn().mockRejectedValue('non-error string');
727
879
 
728
- const syncResult = await accessors.syncToDisk();
729
- expect(syncResult).toFailWith(/Failed to create file.*Permission denied/i);
880
+ const syncResult = await accessors.syncToDisk();
881
+ expect(syncResult).toFailWith(/Failed to delete file.*non-error string/i);
882
+ });
730
883
  });
731
884
  });
732
885
  });