@theia/filesystem 1.77.0-next.99 → 1.78.0-next.0

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 (442) hide show
  1. package/lib/browser/breadcrumbs/filepath-breadcrumb.js +4 -8
  2. package/lib/browser/breadcrumbs/filepath-breadcrumb.js.map +1 -1
  3. package/lib/browser/breadcrumbs/filepath-breadcrumbs-container.d.ts +1 -1
  4. package/lib/browser/breadcrumbs/filepath-breadcrumbs-container.d.ts.map +1 -1
  5. package/lib/browser/breadcrumbs/filepath-breadcrumbs-container.js +18 -25
  6. package/lib/browser/breadcrumbs/filepath-breadcrumbs-container.js.map +1 -1
  7. package/lib/browser/breadcrumbs/filepath-breadcrumbs-contribution.d.ts +5 -5
  8. package/lib/browser/breadcrumbs/filepath-breadcrumbs-contribution.d.ts.map +1 -1
  9. package/lib/browser/breadcrumbs/filepath-breadcrumbs-contribution.js +27 -33
  10. package/lib/browser/breadcrumbs/filepath-breadcrumbs-contribution.js.map +1 -1
  11. package/lib/browser/download/file-download-command-contribution.d.ts +1 -1
  12. package/lib/browser/download/file-download-command-contribution.d.ts.map +1 -1
  13. package/lib/browser/download/file-download-command-contribution.js +28 -33
  14. package/lib/browser/download/file-download-command-contribution.js.map +1 -1
  15. package/lib/browser/download/file-download-frontend-module.js +8 -10
  16. package/lib/browser/download/file-download-frontend-module.js.map +1 -1
  17. package/lib/browser/download/file-download-service.d.ts +1 -1
  18. package/lib/browser/download/file-download-service.d.ts.map +1 -1
  19. package/lib/browser/download/file-download-service.js +19 -24
  20. package/lib/browser/download/file-download-service.js.map +1 -1
  21. package/lib/browser/file-dialog/file-dialog-container.d.ts +1 -1
  22. package/lib/browser/file-dialog/file-dialog-container.d.ts.map +1 -1
  23. package/lib/browser/file-dialog/file-dialog-container.js +25 -30
  24. package/lib/browser/file-dialog/file-dialog-container.js.map +1 -1
  25. package/lib/browser/file-dialog/file-dialog-hidden-files-renderer.d.ts +1 -1
  26. package/lib/browser/file-dialog/file-dialog-hidden-files-renderer.d.ts.map +1 -1
  27. package/lib/browser/file-dialog/file-dialog-hidden-files-renderer.js +13 -21
  28. package/lib/browser/file-dialog/file-dialog-hidden-files-renderer.js.map +1 -1
  29. package/lib/browser/file-dialog/file-dialog-model.d.ts +2 -2
  30. package/lib/browser/file-dialog/file-dialog-model.d.ts.map +1 -1
  31. package/lib/browser/file-dialog/file-dialog-model.js +20 -27
  32. package/lib/browser/file-dialog/file-dialog-model.js.map +1 -1
  33. package/lib/browser/file-dialog/file-dialog-module.js +21 -23
  34. package/lib/browser/file-dialog/file-dialog-module.js.map +1 -1
  35. package/lib/browser/file-dialog/file-dialog-service.d.ts +4 -4
  36. package/lib/browser/file-dialog/file-dialog-service.d.ts.map +1 -1
  37. package/lib/browser/file-dialog/file-dialog-service.js +29 -38
  38. package/lib/browser/file-dialog/file-dialog-service.js.map +1 -1
  39. package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.d.ts +1 -1
  40. package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.d.ts.map +1 -1
  41. package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.js +16 -21
  42. package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.js.map +1 -1
  43. package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.spec.js +9 -11
  44. package/lib/browser/file-dialog/file-dialog-tree-filters-renderer.spec.js.map +1 -1
  45. package/lib/browser/file-dialog/file-dialog-tree.d.ts +2 -2
  46. package/lib/browser/file-dialog/file-dialog-tree.d.ts.map +1 -1
  47. package/lib/browser/file-dialog/file-dialog-tree.js +8 -11
  48. package/lib/browser/file-dialog/file-dialog-tree.js.map +1 -1
  49. package/lib/browser/file-dialog/file-dialog-widget.d.ts +2 -2
  50. package/lib/browser/file-dialog/file-dialog-widget.d.ts.map +1 -1
  51. package/lib/browser/file-dialog/file-dialog-widget.js +18 -23
  52. package/lib/browser/file-dialog/file-dialog-widget.js.map +1 -1
  53. package/lib/browser/file-dialog/file-dialog.d.ts +6 -6
  54. package/lib/browser/file-dialog/file-dialog.d.ts.map +1 -1
  55. package/lib/browser/file-dialog/file-dialog.js +114 -132
  56. package/lib/browser/file-dialog/file-dialog.js.map +1 -1
  57. package/lib/browser/file-dialog/index.d.ts +4 -4
  58. package/lib/browser/file-dialog/index.d.ts.map +1 -1
  59. package/lib/browser/file-dialog/index.js +4 -7
  60. package/lib/browser/file-dialog/index.js.map +1 -1
  61. package/lib/browser/file-resource.d.ts +2 -2
  62. package/lib/browser/file-resource.d.ts.map +1 -1
  63. package/lib/browser/file-resource.js +64 -71
  64. package/lib/browser/file-resource.js.map +1 -1
  65. package/lib/browser/file-resource.spec.js +39 -42
  66. package/lib/browser/file-resource.spec.js.map +1 -1
  67. package/lib/browser/file-selection.d.ts +1 -1
  68. package/lib/browser/file-selection.d.ts.map +1 -1
  69. package/lib/browser/file-selection.js +7 -10
  70. package/lib/browser/file-selection.js.map +1 -1
  71. package/lib/browser/file-service-activation.spec.js +14 -16
  72. package/lib/browser/file-service-activation.spec.js.map +1 -1
  73. package/lib/browser/file-service-copy.spec.js +44 -47
  74. package/lib/browser/file-service-copy.spec.js.map +1 -1
  75. package/lib/browser/file-service-watcher.spec.js +199 -202
  76. package/lib/browser/file-service-watcher.spec.js.map +1 -1
  77. package/lib/browser/file-service.d.ts +3 -3
  78. package/lib/browser/file-service.d.ts.map +1 -1
  79. package/lib/browser/file-service.js +166 -181
  80. package/lib/browser/file-service.js.map +1 -1
  81. package/lib/browser/file-tree/file-tree-container.js +12 -15
  82. package/lib/browser/file-tree/file-tree-container.js.map +1 -1
  83. package/lib/browser/file-tree/file-tree-decorator-adapter.js +23 -31
  84. package/lib/browser/file-tree/file-tree-decorator-adapter.js.map +1 -1
  85. package/lib/browser/file-tree/file-tree-decorator-adapter.spec.js +26 -29
  86. package/lib/browser/file-tree/file-tree-decorator-adapter.spec.js.map +1 -1
  87. package/lib/browser/file-tree/file-tree-label-provider.d.ts +1 -1
  88. package/lib/browser/file-tree/file-tree-label-provider.d.ts.map +1 -1
  89. package/lib/browser/file-tree/file-tree-label-provider.js +13 -18
  90. package/lib/browser/file-tree/file-tree-label-provider.js.map +1 -1
  91. package/lib/browser/file-tree/file-tree-model.d.ts +5 -5
  92. package/lib/browser/file-tree/file-tree-model.d.ts.map +1 -1
  93. package/lib/browser/file-tree/file-tree-model.js +48 -52
  94. package/lib/browser/file-tree/file-tree-model.js.map +1 -1
  95. package/lib/browser/file-tree/file-tree-widget.d.ts +3 -3
  96. package/lib/browser/file-tree/file-tree-widget.d.ts.map +1 -1
  97. package/lib/browser/file-tree/file-tree-widget.js +66 -72
  98. package/lib/browser/file-tree/file-tree-widget.js.map +1 -1
  99. package/lib/browser/file-tree/file-tree.d.ts +3 -3
  100. package/lib/browser/file-tree/file-tree.d.ts.map +1 -1
  101. package/lib/browser/file-tree/file-tree.js +26 -31
  102. package/lib/browser/file-tree/file-tree.js.map +1 -1
  103. package/lib/browser/file-tree/index.d.ts +6 -6
  104. package/lib/browser/file-tree/index.d.ts.map +1 -1
  105. package/lib/browser/file-tree/index.js +6 -9
  106. package/lib/browser/file-tree/index.js.map +1 -1
  107. package/lib/browser/filesystem-frontend-contribution.d.ts +6 -6
  108. package/lib/browser/filesystem-frontend-contribution.d.ts.map +1 -1
  109. package/lib/browser/filesystem-frontend-contribution.js +75 -90
  110. package/lib/browser/filesystem-frontend-contribution.js.map +1 -1
  111. package/lib/browser/filesystem-frontend-module.js +47 -50
  112. package/lib/browser/filesystem-frontend-module.js.map +1 -1
  113. package/lib/browser/filesystem-saveable-service.d.ts +2 -2
  114. package/lib/browser/filesystem-saveable-service.d.ts.map +1 -1
  115. package/lib/browser/filesystem-saveable-service.js +35 -44
  116. package/lib/browser/filesystem-saveable-service.js.map +1 -1
  117. package/lib/browser/filesystem-watcher-error-handler.js +13 -18
  118. package/lib/browser/filesystem-watcher-error-handler.js.map +1 -1
  119. package/lib/browser/index.d.ts +4 -4
  120. package/lib/browser/index.d.ts.map +1 -1
  121. package/lib/browser/index.js +4 -7
  122. package/lib/browser/index.js.map +1 -1
  123. package/lib/browser/location/index.d.ts +2 -2
  124. package/lib/browser/location/index.d.ts.map +1 -1
  125. package/lib/browser/location/index.js +2 -5
  126. package/lib/browser/location/index.js.map +1 -1
  127. package/lib/browser/location/location-renderer.d.ts +3 -3
  128. package/lib/browser/location/location-renderer.d.ts.map +1 -1
  129. package/lib/browser/location/location-renderer.js +42 -51
  130. package/lib/browser/location/location-renderer.js.map +1 -1
  131. package/lib/browser/location/location-renderer.spec.js +61 -64
  132. package/lib/browser/location/location-renderer.spec.js.map +1 -1
  133. package/lib/browser/location/location-service.js +1 -2
  134. package/lib/browser/location/location-service.js.map +1 -1
  135. package/lib/browser/remote-file-service-contribution.d.ts +2 -2
  136. package/lib/browser/remote-file-service-contribution.d.ts.map +1 -1
  137. package/lib/browser/remote-file-service-contribution.js +8 -12
  138. package/lib/browser/remote-file-service-contribution.js.map +1 -1
  139. package/lib/browser/upload/file-upload-service-impl.d.ts +3 -3
  140. package/lib/browser/upload/file-upload-service-impl.d.ts.map +1 -1
  141. package/lib/browser/upload/file-upload-service-impl.js +55 -64
  142. package/lib/browser/upload/file-upload-service-impl.js.map +1 -1
  143. package/lib/browser/vscode-file-service-contribution.d.ts +2 -2
  144. package/lib/browser/vscode-file-service-contribution.d.ts.map +1 -1
  145. package/lib/browser/vscode-file-service-contribution.js +23 -28
  146. package/lib/browser/vscode-file-service-contribution.js.map +1 -1
  147. package/lib/browser-only/browser-only-filesystem-frontend-module.js +21 -23
  148. package/lib/browser-only/browser-only-filesystem-frontend-module.js.map +1 -1
  149. package/lib/browser-only/browser-only-filesystem-provider-server.d.ts +1 -1
  150. package/lib/browser-only/browser-only-filesystem-provider-server.d.ts.map +1 -1
  151. package/lib/browser-only/browser-only-filesystem-provider-server.js +10 -13
  152. package/lib/browser-only/browser-only-filesystem-provider-server.js.map +1 -1
  153. package/lib/browser-only/download/file-download-command-contribution.d.ts +1 -1
  154. package/lib/browser-only/download/file-download-command-contribution.d.ts.map +1 -1
  155. package/lib/browser-only/download/file-download-command-contribution.js +14 -19
  156. package/lib/browser-only/download/file-download-command-contribution.js.map +1 -1
  157. package/lib/browser-only/download/file-download-frontend-module.js +8 -10
  158. package/lib/browser-only/download/file-download-frontend-module.js.map +1 -1
  159. package/lib/browser-only/download/file-download-service.d.ts +3 -3
  160. package/lib/browser-only/download/file-download-service.d.ts.map +1 -1
  161. package/lib/browser-only/download/file-download-service.js +26 -33
  162. package/lib/browser-only/download/file-download-service.js.map +1 -1
  163. package/lib/browser-only/file-search.d.ts.map +1 -1
  164. package/lib/browser-only/file-search.js +9 -15
  165. package/lib/browser-only/file-search.js.map +1 -1
  166. package/lib/browser-only/opfs-filesystem-initialization.d.ts +1 -1
  167. package/lib/browser-only/opfs-filesystem-initialization.d.ts.map +1 -1
  168. package/lib/browser-only/opfs-filesystem-initialization.js +6 -9
  169. package/lib/browser-only/opfs-filesystem-initialization.js.map +1 -1
  170. package/lib/browser-only/opfs-filesystem-provider.d.ts +2 -2
  171. package/lib/browser-only/opfs-filesystem-provider.d.ts.map +1 -1
  172. package/lib/browser-only/opfs-filesystem-provider.js +60 -68
  173. package/lib/browser-only/opfs-filesystem-provider.js.map +1 -1
  174. package/lib/browser-only/upload/file-upload-service-impl.d.ts +3 -3
  175. package/lib/browser-only/upload/file-upload-service-impl.d.ts.map +1 -1
  176. package/lib/browser-only/upload/file-upload-service-impl.js +51 -60
  177. package/lib/browser-only/upload/file-upload-service-impl.js.map +1 -1
  178. package/lib/common/delegating-file-system-provider.d.ts +1 -1
  179. package/lib/common/delegating-file-system-provider.d.ts.map +1 -1
  180. package/lib/common/delegating-file-system-provider.js +18 -22
  181. package/lib/common/delegating-file-system-provider.js.map +1 -1
  182. package/lib/common/download/file-download.js +5 -8
  183. package/lib/common/download/file-download.js.map +1 -1
  184. package/lib/common/file-upload.js +1 -4
  185. package/lib/common/file-upload.js.map +1 -1
  186. package/lib/common/files.js +38 -59
  187. package/lib/common/files.js.map +1 -1
  188. package/lib/common/files.spec.js +22 -25
  189. package/lib/common/files.spec.js.map +1 -1
  190. package/lib/common/filesystem-preferences.js +39 -44
  191. package/lib/common/filesystem-preferences.js.map +1 -1
  192. package/lib/common/filesystem-utils.d.ts +1 -1
  193. package/lib/common/filesystem-utils.d.ts.map +1 -1
  194. package/lib/common/filesystem-utils.js +2 -5
  195. package/lib/common/filesystem-utils.js.map +1 -1
  196. package/lib/common/filesystem-utils.spec.js +227 -229
  197. package/lib/common/filesystem-utils.spec.js.map +1 -1
  198. package/lib/common/filesystem-watcher-protocol.d.ts +1 -1
  199. package/lib/common/filesystem-watcher-protocol.d.ts.map +1 -1
  200. package/lib/common/filesystem-watcher-protocol.js +2 -5
  201. package/lib/common/filesystem-watcher-protocol.js.map +1 -1
  202. package/lib/common/filesystem.js +2 -5
  203. package/lib/common/filesystem.js.map +1 -1
  204. package/lib/common/index.d.ts +3 -3
  205. package/lib/common/index.d.ts.map +1 -1
  206. package/lib/common/index.js +3 -6
  207. package/lib/common/index.js.map +1 -1
  208. package/lib/common/io.d.ts +2 -2
  209. package/lib/common/io.d.ts.map +1 -1
  210. package/lib/common/io.js +10 -13
  211. package/lib/common/io.js.map +1 -1
  212. package/lib/common/remote-file-system-provider.d.ts +5 -5
  213. package/lib/common/remote-file-system-provider.d.ts.map +1 -1
  214. package/lib/common/remote-file-system-provider.js +81 -93
  215. package/lib/common/remote-file-system-provider.js.map +1 -1
  216. package/lib/common/upload/file-upload.js +1 -4
  217. package/lib/common/upload/file-upload.js.map +1 -1
  218. package/lib/electron-browser/file-dialog/electron-file-dialog-module.js +6 -8
  219. package/lib/electron-browser/file-dialog/electron-file-dialog-module.js.map +1 -1
  220. package/lib/electron-browser/file-dialog/electron-file-dialog-service.d.ts +3 -3
  221. package/lib/electron-browser/file-dialog/electron-file-dialog-service.d.ts.map +1 -1
  222. package/lib/electron-browser/file-dialog/electron-file-dialog-service.js +21 -23
  223. package/lib/electron-browser/file-dialog/electron-file-dialog-service.js.map +1 -1
  224. package/lib/electron-browser/file-dialog/electron-file-dialog-service.spec.js +33 -12
  225. package/lib/electron-browser/file-dialog/electron-file-dialog-service.spec.js.map +1 -1
  226. package/lib/electron-browser/preload.js +6 -9
  227. package/lib/electron-browser/preload.js.map +1 -1
  228. package/lib/electron-common/electron-api.d.ts +4 -0
  229. package/lib/electron-common/electron-api.d.ts.map +1 -1
  230. package/lib/electron-common/electron-api.js +2 -5
  231. package/lib/electron-common/electron-api.js.map +1 -1
  232. package/lib/electron-main/electron-api-main.d.ts.map +1 -1
  233. package/lib/electron-main/electron-api-main.js +19 -18
  234. package/lib/electron-main/electron-api-main.js.map +1 -1
  235. package/lib/electron-main/electron-main-module.js +6 -8
  236. package/lib/electron-main/electron-main-module.js.map +1 -1
  237. package/lib/node/archive/archive-extractor.d.ts +86 -0
  238. package/lib/node/archive/archive-extractor.d.ts.map +1 -0
  239. package/lib/node/archive/archive-extractor.js +290 -0
  240. package/lib/node/archive/archive-extractor.js.map +1 -0
  241. package/lib/node/archive/archive-extractor.spec.d.ts +2 -0
  242. package/lib/node/archive/archive-extractor.spec.d.ts.map +1 -0
  243. package/lib/node/archive/archive-extractor.spec.js +317 -0
  244. package/lib/node/archive/archive-extractor.spec.js.map +1 -0
  245. package/lib/node/archive/test/test-archives.d.ts +20 -0
  246. package/lib/node/archive/test/test-archives.d.ts.map +1 -0
  247. package/lib/node/archive/test/test-archives.js +97 -0
  248. package/lib/node/archive/test/test-archives.js.map +1 -0
  249. package/lib/node/disk-file-system-provider.d.ts +2 -2
  250. package/lib/node/disk-file-system-provider.d.ts.map +1 -1
  251. package/lib/node/disk-file-system-provider.js +111 -119
  252. package/lib/node/disk-file-system-provider.js.map +1 -1
  253. package/lib/node/disk-file-system-provider.spec.js +53 -56
  254. package/lib/node/disk-file-system-provider.spec.js.map +1 -1
  255. package/lib/node/download/directory-archiver.js +13 -16
  256. package/lib/node/download/directory-archiver.js.map +1 -1
  257. package/lib/node/download/directory-archiver.spec.js +20 -23
  258. package/lib/node/download/directory-archiver.spec.js.map +1 -1
  259. package/lib/node/download/file-download-backend-module.js +14 -16
  260. package/lib/node/download/file-download-backend-module.js.map +1 -1
  261. package/lib/node/download/file-download-cache.js +11 -15
  262. package/lib/node/download/file-download-cache.js.map +1 -1
  263. package/lib/node/download/file-download-endpoint.d.ts +1 -1
  264. package/lib/node/download/file-download-endpoint.d.ts.map +1 -1
  265. package/lib/node/download/file-download-endpoint.js +25 -31
  266. package/lib/node/download/file-download-endpoint.js.map +1 -1
  267. package/lib/node/download/file-download-handler.d.ts +2 -2
  268. package/lib/node/download/file-download-handler.d.ts.map +1 -1
  269. package/lib/node/download/file-download-handler.js +70 -76
  270. package/lib/node/download/file-download-handler.js.map +1 -1
  271. package/lib/node/download/test/mock-directory-archiver.d.ts +1 -1
  272. package/lib/node/download/test/mock-directory-archiver.d.ts.map +1 -1
  273. package/lib/node/download/test/mock-directory-archiver.js +2 -6
  274. package/lib/node/download/test/mock-directory-archiver.js.map +1 -1
  275. package/lib/node/file-change-collection.d.ts +1 -1
  276. package/lib/node/file-change-collection.d.ts.map +1 -1
  277. package/lib/node/file-change-collection.js +1 -5
  278. package/lib/node/file-change-collection.js.map +1 -1
  279. package/lib/node/file-change-collection.spec.js +5 -8
  280. package/lib/node/file-change-collection.spec.js.map +1 -1
  281. package/lib/node/filesystem-backend-module.d.ts +1 -1
  282. package/lib/node/filesystem-backend-module.d.ts.map +1 -1
  283. package/lib/node/filesystem-backend-module.js +60 -64
  284. package/lib/node/filesystem-backend-module.js.map +1 -1
  285. package/lib/node/filesystem-watcher-client.d.ts +2 -2
  286. package/lib/node/filesystem-watcher-client.d.ts.map +1 -1
  287. package/lib/node/filesystem-watcher-client.js +11 -16
  288. package/lib/node/filesystem-watcher-client.js.map +1 -1
  289. package/lib/node/filesystem-watcher-dispatcher.d.ts +1 -1
  290. package/lib/node/filesystem-watcher-dispatcher.d.ts.map +1 -1
  291. package/lib/node/filesystem-watcher-dispatcher.js +9 -13
  292. package/lib/node/filesystem-watcher-dispatcher.js.map +1 -1
  293. package/lib/node/filesystem-watcher-service-impl.d.ts +3 -3
  294. package/lib/node/filesystem-watcher-service-impl.d.ts.map +1 -1
  295. package/lib/node/filesystem-watcher-service-impl.js +7 -11
  296. package/lib/node/filesystem-watcher-service-impl.js.map +1 -1
  297. package/lib/node/filesystem-watcher-service-impl.spec.js +23 -26
  298. package/lib/node/filesystem-watcher-service-impl.spec.js.map +1 -1
  299. package/lib/node/filesystem-watcher.d.ts +1 -1
  300. package/lib/node/filesystem-watcher.d.ts.map +1 -1
  301. package/lib/node/filesystem-watcher.js +6 -11
  302. package/lib/node/filesystem-watcher.js.map +1 -1
  303. package/lib/node/nodejs-watcher/node-directory-watcher.d.ts +4 -4
  304. package/lib/node/nodejs-watcher/node-directory-watcher.d.ts.map +1 -1
  305. package/lib/node/nodejs-watcher/node-directory-watcher.js +20 -26
  306. package/lib/node/nodejs-watcher/node-directory-watcher.js.map +1 -1
  307. package/lib/node/nodejs-watcher/node-directory-watcher.spec.js +51 -54
  308. package/lib/node/nodejs-watcher/node-directory-watcher.spec.js.map +1 -1
  309. package/lib/node/nodejs-watcher/watch-request-router.d.ts +3 -3
  310. package/lib/node/nodejs-watcher/watch-request-router.d.ts.map +1 -1
  311. package/lib/node/nodejs-watcher/watch-request-router.js +8 -13
  312. package/lib/node/nodejs-watcher/watch-request-router.js.map +1 -1
  313. package/lib/node/nodejs-watcher/watcher-host.d.ts +1 -1
  314. package/lib/node/nodejs-watcher/watcher-host.d.ts.map +1 -1
  315. package/lib/node/nodejs-watcher/watcher-host.js +7 -12
  316. package/lib/node/nodejs-watcher/watcher-host.js.map +1 -1
  317. package/lib/node/parcel-watcher/index.js +6 -9
  318. package/lib/node/parcel-watcher/index.js.map +1 -1
  319. package/lib/node/parcel-watcher/parcel-filesystem-service.d.ts +4 -4
  320. package/lib/node/parcel-watcher/parcel-filesystem-service.d.ts.map +1 -1
  321. package/lib/node/parcel-watcher/parcel-filesystem-service.js +4 -8
  322. package/lib/node/parcel-watcher/parcel-filesystem-service.js.map +1 -1
  323. package/lib/node/parcel-watcher/parcel-filesystem-watcher.spec.js +23 -26
  324. package/lib/node/parcel-watcher/parcel-filesystem-watcher.spec.js.map +1 -1
  325. package/lib/node/parcel-watcher/parcel-options.js +1 -4
  326. package/lib/node/parcel-watcher/parcel-options.js.map +1 -1
  327. package/lib/node/parcel-watcher/parcel-watcher-exclude.spec.js +11 -16
  328. package/lib/node/parcel-watcher/parcel-watcher-exclude.spec.js.map +1 -1
  329. package/lib/node/parcel-watcher/parcel-watcher-retry.spec.js +11 -16
  330. package/lib/node/parcel-watcher/parcel-watcher-retry.spec.js.map +1 -1
  331. package/lib/node/parcel-watcher/parcel-watcher.d.ts +3 -3
  332. package/lib/node/parcel-watcher/parcel-watcher.d.ts.map +1 -1
  333. package/lib/node/parcel-watcher/parcel-watcher.js +28 -32
  334. package/lib/node/parcel-watcher/parcel-watcher.js.map +1 -1
  335. package/lib/node/test/watcher-test-helper.d.ts +1 -1
  336. package/lib/node/test/watcher-test-helper.d.ts.map +1 -1
  337. package/lib/node/test/watcher-test-helper.js +5 -10
  338. package/lib/node/test/watcher-test-helper.js.map +1 -1
  339. package/lib/node/upload/node-file-upload-service.d.ts +1 -1
  340. package/lib/node/upload/node-file-upload-service.d.ts.map +1 -1
  341. package/lib/node/upload/node-file-upload-service.js +20 -25
  342. package/lib/node/upload/node-file-upload-service.js.map +1 -1
  343. package/lib/node/upload/node-file-upload-service.spec.js +21 -24
  344. package/lib/node/upload/node-file-upload-service.spec.js.map +1 -1
  345. package/package.json +21 -5
  346. package/src/browser/breadcrumbs/filepath-breadcrumb.ts +1 -1
  347. package/src/browser/breadcrumbs/filepath-breadcrumbs-container.ts +1 -1
  348. package/src/browser/breadcrumbs/filepath-breadcrumbs-contribution.ts +5 -5
  349. package/src/browser/download/file-download-command-contribution.ts +1 -1
  350. package/src/browser/download/file-download-frontend-module.ts +3 -3
  351. package/src/browser/download/file-download-service.ts +1 -1
  352. package/src/browser/file-dialog/file-dialog-container.ts +5 -5
  353. package/src/browser/file-dialog/file-dialog-hidden-files-renderer.tsx +1 -1
  354. package/src/browser/file-dialog/file-dialog-model.ts +2 -2
  355. package/src/browser/file-dialog/file-dialog-module.ts +5 -5
  356. package/src/browser/file-dialog/file-dialog-service.ts +4 -4
  357. package/src/browser/file-dialog/file-dialog-tree-filters-renderer.spec.ts +2 -2
  358. package/src/browser/file-dialog/file-dialog-tree-filters-renderer.tsx +1 -1
  359. package/src/browser/file-dialog/file-dialog-tree.ts +2 -2
  360. package/src/browser/file-dialog/file-dialog-widget.ts +2 -2
  361. package/src/browser/file-dialog/file-dialog.ts +16 -13
  362. package/src/browser/file-dialog/index.ts +4 -4
  363. package/src/browser/file-resource.spec.ts +3 -3
  364. package/src/browser/file-resource.ts +3 -3
  365. package/src/browser/file-selection.ts +1 -1
  366. package/src/browser/file-service-activation.spec.ts +2 -2
  367. package/src/browser/file-service-copy.spec.ts +2 -2
  368. package/src/browser/file-service-watcher.spec.ts +2 -2
  369. package/src/browser/file-service.ts +6 -6
  370. package/src/browser/file-tree/file-tree-container.ts +3 -3
  371. package/src/browser/file-tree/file-tree-decorator-adapter.spec.ts +1 -1
  372. package/src/browser/file-tree/file-tree-decorator-adapter.ts +1 -1
  373. package/src/browser/file-tree/file-tree-label-provider.ts +1 -1
  374. package/src/browser/file-tree/file-tree-model.ts +12 -6
  375. package/src/browser/file-tree/file-tree-widget.tsx +8 -5
  376. package/src/browser/file-tree/file-tree.ts +3 -3
  377. package/src/browser/file-tree/index.ts +6 -6
  378. package/src/browser/filesystem-frontend-contribution.ts +6 -6
  379. package/src/browser/filesystem-frontend-module.ts +14 -14
  380. package/src/browser/filesystem-saveable-service.ts +2 -2
  381. package/src/browser/index.ts +4 -4
  382. package/src/browser/location/index.ts +2 -2
  383. package/src/browser/location/location-renderer.spec.ts +3 -3
  384. package/src/browser/location/location-renderer.tsx +3 -3
  385. package/src/browser/remote-file-service-contribution.ts +2 -2
  386. package/src/browser/upload/file-upload-service-impl.ts +5 -5
  387. package/src/browser/vscode-file-service-contribution.ts +2 -2
  388. package/src/browser-only/browser-only-filesystem-frontend-module.ts +7 -7
  389. package/src/browser-only/browser-only-filesystem-provider-server.ts +1 -1
  390. package/src/browser-only/download/file-download-command-contribution.ts +2 -2
  391. package/src/browser-only/download/file-download-frontend-module.ts +3 -3
  392. package/src/browser-only/download/file-download-service.ts +3 -3
  393. package/src/browser-only/file-search.ts +2 -1
  394. package/src/browser-only/opfs-filesystem-initialization.ts +1 -1
  395. package/src/browser-only/opfs-filesystem-provider.ts +3 -3
  396. package/src/browser-only/upload/file-upload-service-impl.ts +4 -4
  397. package/src/common/delegating-file-system-provider.ts +1 -1
  398. package/src/common/files.spec.ts +1 -1
  399. package/src/common/filesystem-utils.spec.ts +2 -2
  400. package/src/common/filesystem-utils.ts +1 -1
  401. package/src/common/filesystem-watcher-protocol.ts +1 -1
  402. package/src/common/index.ts +3 -3
  403. package/src/common/io.ts +2 -2
  404. package/src/common/remote-file-system-provider.ts +1 -1
  405. package/src/electron-browser/file-dialog/electron-file-dialog-module.ts +2 -2
  406. package/src/electron-browser/file-dialog/electron-file-dialog-service.spec.ts +30 -3
  407. package/src/electron-browser/file-dialog/electron-file-dialog-service.ts +8 -6
  408. package/src/electron-browser/preload.ts +1 -1
  409. package/src/electron-common/electron-api.ts +4 -0
  410. package/src/electron-main/electron-api-main.ts +7 -3
  411. package/src/electron-main/electron-main-module.ts +1 -1
  412. package/src/node/archive/archive-extractor.spec.ts +359 -0
  413. package/src/node/archive/archive-extractor.ts +350 -0
  414. package/src/node/archive/test/test-archives.ts +117 -0
  415. package/src/node/disk-file-system-provider.spec.ts +3 -3
  416. package/src/node/disk-file-system-provider.ts +7 -6
  417. package/src/node/download/directory-archiver.spec.ts +1 -1
  418. package/src/node/download/file-download-backend-module.ts +4 -4
  419. package/src/node/download/file-download-endpoint.ts +4 -3
  420. package/src/node/download/file-download-handler.ts +3 -3
  421. package/src/node/download/test/mock-directory-archiver.ts +1 -1
  422. package/src/node/file-change-collection.spec.ts +2 -2
  423. package/src/node/file-change-collection.ts +1 -1
  424. package/src/node/filesystem-backend-module.ts +15 -12
  425. package/src/node/filesystem-watcher-client.ts +2 -2
  426. package/src/node/filesystem-watcher-dispatcher.ts +1 -1
  427. package/src/node/filesystem-watcher-service-impl.spec.ts +5 -5
  428. package/src/node/filesystem-watcher-service-impl.ts +4 -4
  429. package/src/node/filesystem-watcher.ts +1 -1
  430. package/src/node/nodejs-watcher/node-directory-watcher.spec.ts +5 -5
  431. package/src/node/nodejs-watcher/node-directory-watcher.ts +5 -5
  432. package/src/node/nodejs-watcher/watch-request-router.ts +4 -4
  433. package/src/node/nodejs-watcher/watcher-host.ts +1 -1
  434. package/src/node/parcel-watcher/index.ts +2 -2
  435. package/src/node/parcel-watcher/parcel-filesystem-service.ts +4 -4
  436. package/src/node/parcel-watcher/parcel-filesystem-watcher.spec.ts +2 -2
  437. package/src/node/parcel-watcher/parcel-watcher-exclude.spec.ts +4 -8
  438. package/src/node/parcel-watcher/parcel-watcher-retry.spec.ts +4 -6
  439. package/src/node/parcel-watcher/parcel-watcher.ts +7 -6
  440. package/src/node/test/watcher-test-helper.ts +1 -1
  441. package/src/node/upload/node-file-upload-service.spec.ts +1 -1
  442. package/src/node/upload/node-file-upload-service.ts +6 -6
package/src/common/io.ts CHANGED
@@ -22,9 +22,9 @@
22
22
  /* eslint-disable max-len */
23
23
 
24
24
  import URI from '@theia/core/lib/common/uri';
25
- import { BinaryBuffer } from '@theia/core/lib/common//buffer';
25
+ import { BinaryBuffer } from '@theia/core/lib/common/buffer';
26
26
  import { CancellationToken, cancelled as canceled } from '@theia/core/lib/common/cancellation';
27
- import { FileSystemProviderWithOpenReadWriteCloseCapability, FileReadStreamOptions, ensureFileSystemProviderError, createFileSystemProviderError, FileSystemProviderErrorCode } from './files';
27
+ import { FileSystemProviderWithOpenReadWriteCloseCapability, FileReadStreamOptions, ensureFileSystemProviderError, createFileSystemProviderError, FileSystemProviderErrorCode } from './files.js';
28
28
  import { WriteableStream, ErrorTransformer, DataTransformer } from '@theia/core/lib/common/stream';
29
29
 
30
30
  export interface CreateReadStreamOptions extends FileReadStreamOptions {
@@ -25,7 +25,7 @@ import {
25
25
  hasOpenReadWriteCloseCapability, hasFileFolderCopyCapability, hasReadWriteCapability, hasAccessCapability,
26
26
  FileSystemProviderError, FileSystemProviderErrorCode, FileUpdateOptions, hasUpdateCapability, FileUpdateResult, FileReadStreamOptions, hasFileReadStreamCapability,
27
27
  ReadOnlyMessageFileSystemProvider
28
- } from './files';
28
+ } from './files.js';
29
29
  import { RpcServer, RpcProxy, RpcProxyFactory } from '@theia/core/lib/common/messaging/proxy-factory';
30
30
  import { ApplicationError } from '@theia/core/lib/common/application-error';
31
31
  import { Deferred } from '@theia/core/lib/common/promise-util';
@@ -15,8 +15,8 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { ContainerModule } from '@theia/core/shared/inversify';
18
- import { ElectronFileDialogService } from './electron-file-dialog-service';
19
- import { FileDialogService } from '../../browser';
18
+ import { ElectronFileDialogService } from './electron-file-dialog-service.js';
19
+ import { FileDialogService } from '../../browser/index.js';
20
20
 
21
21
  export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
22
22
  bind(ElectronFileDialogService).toSelf().inSingletonScope();
@@ -20,9 +20,9 @@ let disableJSDOM = enableJSDOM();
20
20
  import { expect } from 'chai';
21
21
  import { FileUri } from '@theia/core/lib/common/file-uri';
22
22
  import URI from '@theia/core/lib/common/uri';
23
- import { OpenFileDialogProps } from '../../browser/file-dialog';
24
- import { OpenDialogOptions } from '../../electron-common/electron-api';
25
- import { ElectronFileDialogService } from './electron-file-dialog-service';
23
+ import { OpenFileDialogProps, SaveFileDialogProps } from '../../browser/file-dialog/index.js';
24
+ import { OpenDialogOptions, SaveDialogOptions } from '../../electron-common/electron-api.js';
25
+ import { ElectronFileDialogService } from './electron-file-dialog-service.js';
26
26
 
27
27
  disableJSDOM();
28
28
 
@@ -30,6 +30,9 @@ class TestElectronFileDialogService extends ElectronFileDialogService {
30
30
  override toOpenDialogOptions(uri: URI, props: OpenFileDialogProps): OpenDialogOptions {
31
31
  return super.toOpenDialogOptions(uri, props);
32
32
  }
33
+ override toSaveDialogOptions(uri: URI, props: SaveFileDialogProps): SaveDialogOptions {
34
+ return super.toSaveDialogOptions(uri, props);
35
+ }
33
36
  }
34
37
 
35
38
  describe('ElectronFileDialogService', () => {
@@ -54,4 +57,28 @@ describe('ElectronFileDialogService', () => {
54
57
  { name: 'Theia Workspace', extensions: ['theia-workspace'] }
55
58
  ]);
56
59
  });
60
+
61
+ describe('windowName forwarding', () => {
62
+ it('should pass windowName from targetWindow for open dialog', () => {
63
+ const targetWindow = { name: '123-secondaryWindow-0' } as Window;
64
+ const options = new TestElectronFileDialogService().toOpenDialogOptions(uri, { title: 'Open', canSelectFiles: true, targetWindow });
65
+ expect(options.windowName).to.equal('123-secondaryWindow-0');
66
+ });
67
+
68
+ it('should leave windowName undefined when no targetWindow is set for open dialog', () => {
69
+ const options = new TestElectronFileDialogService().toOpenDialogOptions(uri, { title: 'Open', canSelectFiles: true });
70
+ expect(options.windowName).to.be.undefined;
71
+ });
72
+
73
+ it('should pass windowName from targetWindow for save dialog', () => {
74
+ const targetWindow = { name: '123-secondaryWindow-0' } as Window;
75
+ const options = new TestElectronFileDialogService().toSaveDialogOptions(uri, { title: 'Save', targetWindow });
76
+ expect(options.windowName).to.equal('123-secondaryWindow-0');
77
+ });
78
+
79
+ it('should leave windowName undefined when no targetWindow is set for save dialog', () => {
80
+ const options = new TestElectronFileDialogService().toSaveDialogOptions(uri, { title: 'Save' });
81
+ expect(options.windowName).to.be.undefined;
82
+ });
83
+ });
57
84
  });
@@ -18,9 +18,9 @@ import { inject, injectable } from '@theia/core/shared/inversify';
18
18
  import URI from '@theia/core/lib/common/uri';
19
19
  import { MaybeArray } from '@theia/core/lib/common/types';
20
20
  import { MessageService } from '@theia/core/lib/common/message-service';
21
- import { FileStat } from '../../common/files';
22
- import { FileAccess } from '../../common/filesystem';
23
- import { DefaultFileDialogService, OpenFileDialogProps, SaveFileDialogProps } from '../../browser/file-dialog';
21
+ import { FileStat } from '../../common/files.js';
22
+ import { FileAccess } from '../../common/filesystem.js';
23
+ import { DefaultFileDialogService, OpenFileDialogProps, SaveFileDialogProps } from '../../browser/file-dialog/index.js';
24
24
  //
25
25
  // We are OK to use this here because the electron backend and frontend are on the same host.
26
26
  // If required, we can move this single service (and its module) to a dedicated Theia extension,
@@ -29,7 +29,7 @@ import { DefaultFileDialogService, OpenFileDialogProps, SaveFileDialogProps } fr
29
29
  //
30
30
  // eslint-disable-next-line @theia/runtime-import-check
31
31
  import { FileUri } from '@theia/core/lib/common/file-uri';
32
- import { OpenDialogOptions, SaveDialogOptions } from '../../electron-common/electron-api';
32
+ import { OpenDialogOptions, SaveDialogOptions } from '../../electron-common/electron-api.js';
33
33
 
34
34
  import '@theia/core/lib/electron-common/electron-api';
35
35
 
@@ -118,7 +118,8 @@ export class ElectronFileDialogService extends DefaultFileDialogService {
118
118
 
119
119
  protected toOpenDialogOptions(uri: URI, props: OpenFileDialogProps): OpenDialogOptions {
120
120
  const result: OpenDialogOptions = {
121
- path: FileUri.fsPath(uri)
121
+ path: FileUri.fsPath(uri),
122
+ windowName: props.targetWindow?.name
122
123
  };
123
124
 
124
125
  result.title = props.title;
@@ -152,7 +153,8 @@ export class ElectronFileDialogService extends DefaultFileDialogService {
152
153
  }
153
154
 
154
155
  const result: SaveDialogOptions = {
155
- path: FileUri.fsPath(uri)
156
+ path: FileUri.fsPath(uri),
157
+ windowName: props.targetWindow?.name
156
158
  };
157
159
 
158
160
  result.title = props.title;
@@ -13,7 +13,7 @@
13
13
  //
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
- import { CHANNEL_SHOW_OPEN, CHANNEL_SHOW_SAVE, OpenDialogOptions, SaveDialogOptions, TheiaFilesystemAPI } from '../electron-common/electron-api';
16
+ import { CHANNEL_SHOW_OPEN, CHANNEL_SHOW_SAVE, OpenDialogOptions, SaveDialogOptions, TheiaFilesystemAPI } from '../electron-common/electron-api.js';
17
17
 
18
18
  // eslint-disable-next-line import/no-extraneous-dependencies
19
19
  import { ipcRenderer, contextBridge } from '@theia/core/electron-shared/electron';
@@ -29,6 +29,8 @@ export interface OpenDialogOptions {
29
29
  openFolders?: boolean;
30
30
  selectMany?: boolean;
31
31
  filters?: FileFilter[];
32
+ /** Name of the target window for parenting the dialog. If omitted, the sender's window is used. */
33
+ windowName?: string;
32
34
  }
33
35
 
34
36
  export interface SaveDialogOptions {
@@ -38,6 +40,8 @@ export interface SaveDialogOptions {
38
40
  buttonLabel?: string,
39
41
  modal?: boolean,
40
42
  filters?: FileFilter[];
43
+ /** Name of the target window for parenting the dialog. If omitted, the sender's window is used. */
44
+ windowName?: string;
41
45
  }
42
46
 
43
47
  export interface TheiaFilesystemAPI {
@@ -18,7 +18,7 @@ import { injectable } from '@theia/core/shared/inversify';
18
18
 
19
19
  import { ElectronMainApplication, ElectronMainApplicationContribution } from '@theia/core/lib/electron-main/electron-main-application';
20
20
  import { MaybePromise } from '@theia/core';
21
- import { CHANNEL_SHOW_OPEN, CHANNEL_SHOW_SAVE, OpenDialogOptions, SaveDialogOptions } from '../electron-common/electron-api';
21
+ import { CHANNEL_SHOW_OPEN, CHANNEL_SHOW_SAVE, OpenDialogOptions, SaveDialogOptions } from '../electron-common/electron-api.js';
22
22
  import { ipcMain, OpenDialogOptions as ElectronOpenDialogOptions, SaveDialogOptions as ElectronSaveDialogOptions, BrowserWindow, dialog }
23
23
  from '@theia/core/electron-shared/electron';
24
24
 
@@ -50,7 +50,9 @@ export class ElectronApi implements ElectronMainApplicationContribution {
50
50
  };
51
51
 
52
52
  if (options.modal) {
53
- const win = BrowserWindow.fromWebContents(event.sender);
53
+ const win = options.windowName
54
+ ? BrowserWindow.getAllWindows().find(w => w.webContents.mainFrame.name === options.windowName)
55
+ : BrowserWindow.fromWebContents(event.sender);
54
56
  if (win) {
55
57
  return (await dialog.showOpenDialog(win, dialogOpts)).filePaths;
56
58
  }
@@ -66,7 +68,9 @@ export class ElectronApi implements ElectronMainApplicationContribution {
66
68
  title: options.title
67
69
  };
68
70
  if (options.modal) {
69
- const win = BrowserWindow.fromWebContents(event.sender);
71
+ const win = options.windowName
72
+ ? BrowserWindow.getAllWindows().find(w => w.webContents.mainFrame.name === options.windowName)
73
+ : BrowserWindow.fromWebContents(event.sender);
70
74
  if (win) {
71
75
  return (await dialog.showSaveDialog(win, dialogOpts)).filePath;
72
76
  }
@@ -15,7 +15,7 @@
15
15
  // *****************************************************************************
16
16
  import { ContainerModule } from '@theia/core/shared/inversify';
17
17
  import { ElectronMainApplicationContribution } from '@theia/core/lib/electron-main/electron-main-application';
18
- import { ElectronApi } from './electron-api-main';
18
+ import { ElectronApi } from './electron-api-main.js';
19
19
 
20
20
  export default new ContainerModule(bind => {
21
21
  bind(ElectronApi).toSelf().inSingletonScope();
@@ -0,0 +1,359 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2026 EclipseSource GmbH and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import * as fs from 'fs';
18
+ import { randomBytes } from 'crypto';
19
+ import * as os from 'os';
20
+ import * as path from 'path';
21
+ import { expect } from 'chai';
22
+ import * as sinon from 'sinon';
23
+ import { ILogger } from '@theia/core/lib/common/logger';
24
+ import { ArchiveExtractorImpl, ArchiveFormat } from './archive-extractor.js';
25
+ import { createTestTar, createTestZip } from './test/test-archives.js';
26
+
27
+ const isWindows = process.platform === 'win32';
28
+
29
+ describe('ArchiveExtractorImpl', () => {
30
+
31
+ let workspace: string;
32
+ let destination: string;
33
+ let outside: string;
34
+ let warnings: string[];
35
+
36
+ class TestArchiveExtractor extends ArchiveExtractorImpl {
37
+ override readonly logger = { warn: (message: string) => warnings.push(message) } as unknown as ILogger;
38
+ }
39
+ const extractor = new TestArchiveExtractor();
40
+
41
+ beforeEach(async () => {
42
+ workspace = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'archive-extractor-'));
43
+ destination = path.join(workspace, 'out');
44
+ outside = path.join(workspace, 'outside');
45
+ await fs.promises.mkdir(outside);
46
+ warnings = [];
47
+ });
48
+
49
+ afterEach(async () => {
50
+ await fs.promises.rm(workspace, { recursive: true, force: true });
51
+ });
52
+
53
+ async function expectRejection(promise: Promise<unknown>, message: RegExp): Promise<void> {
54
+ try {
55
+ await promise;
56
+ } catch (error) {
57
+ expect(String(error)).to.match(message);
58
+ return;
59
+ }
60
+ expect.fail('Expected the promise to be rejected');
61
+ }
62
+
63
+ async function listFiles(directory: string): Promise<string[]> {
64
+ const entries = await fs.promises.readdir(directory, { recursive: true });
65
+ return entries.map(entry => entry.split(path.sep).join('/')).sort();
66
+ }
67
+
68
+ /** Creating a file link on Windows requires elevated rights or developer mode. */
69
+ async function createFileLink(target: string, link: string): Promise<boolean> {
70
+ try {
71
+ await fs.promises.symlink(target, link, 'file');
72
+ return true;
73
+ } catch (error) {
74
+ if (isWindows && (error as NodeJS.ErrnoException).code === 'EPERM') {
75
+ return false;
76
+ }
77
+ throw error;
78
+ }
79
+ }
80
+
81
+ async function writeArchive(name: string, content: Buffer): Promise<string> {
82
+ const archivePath = path.join(workspace, name);
83
+ await fs.promises.writeFile(archivePath, content);
84
+ return archivePath;
85
+ }
86
+
87
+ const formats: { name: string, create: (entries: { name: string, type?: 'file' | 'directory', mode?: number, data?: string }[]) => Promise<Buffer> }[] = [
88
+ {
89
+ name: 'zip',
90
+ create: async entries => createTestZip(entries.map(entry => ({
91
+ name: entry.type === 'directory' ? entry.name + '/' : entry.name,
92
+ mode: (entry.type === 'directory' ? 0o040000 : 0o100000) | (entry.mode ?? (entry.type === 'directory' ? 0o755 : 0o644)),
93
+ data: entry.data
94
+ })))
95
+ },
96
+ { name: 'tar', create: entries => createTestTar(entries) },
97
+ { name: 'tgz', create: entries => createTestTar(entries, true) }
98
+ ];
99
+
100
+ for (const format of formats) {
101
+ describe(format.name, () => {
102
+
103
+ it('extracts files and directories from a path', async () => {
104
+ const archive = await writeArchive(`archive.${format.name}`, await format.create([
105
+ { name: 'extension', type: 'directory' },
106
+ { name: 'extension/package.json', data: '{}' },
107
+ { name: 'extension/nested/file.txt', data: 'content' }
108
+ ]));
109
+ const entries = await extractor.extract(archive, destination);
110
+ expect(entries.map(entry => `${entry.type}:${entry.path}`)).to.deep.equal([
111
+ 'directory:extension',
112
+ 'file:extension/package.json',
113
+ 'file:extension/nested/file.txt'
114
+ ]);
115
+ expect(await fs.promises.readFile(path.join(destination, 'extension', 'nested', 'file.txt'), 'utf8')).to.equal('content');
116
+ });
117
+
118
+ it('extracts from a buffer', async () => {
119
+ await extractor.extract(await format.create([{ name: 'file.txt', data: 'content' }]), destination);
120
+ expect(await fs.promises.readFile(path.join(destination, 'file.txt'), 'utf8')).to.equal('content');
121
+ });
122
+
123
+ it('reads the selected files without extracting', async () => {
124
+ const archive = await format.create([
125
+ { name: 'extension/package.json', data: '{"name":"test"}' },
126
+ { name: 'extension/README.md', data: 'readme' }
127
+ ]);
128
+ const files = await extractor.readFiles(archive, { filter: entryPath => entryPath === 'extension/package.json' });
129
+ expect(files.map(file => [file.path, file.data.toString('utf8')])).to.deep.equal([['extension/package.json', '{"name":"test"}']]);
130
+ expect(fs.existsSync(destination)).to.be.false;
131
+ });
132
+
133
+ (isWindows ? it.skip : it)('keeps permission bits but strips setuid, setgid and sticky bits', async () => {
134
+ const entries = await extractor.extract(await format.create([
135
+ { name: 'run.sh', mode: 0o755, data: '#!/bin/sh' },
136
+ { name: 'setuid', mode: 0o7755, data: 'evil' }
137
+ ]), destination);
138
+ expect(entries.map(entry => entry.mode)).to.deep.equal([0o755, 0o755]);
139
+ expect((await fs.promises.stat(path.join(destination, 'run.sh'))).mode & 0o7777).to.equal(0o755 & ~process.umask());
140
+ expect((await fs.promises.stat(path.join(destination, 'setuid'))).mode & 0o7000).to.equal(0);
141
+ });
142
+
143
+ it('rejects an entry that leaves the destination', async () => {
144
+ const archive = await format.create([{ name: '../outside/evil.txt', data: 'evil' }]);
145
+ await expectRejection(extractor.extract(archive, destination), /invalid relative path|leaves the extraction directory/);
146
+ expect(await listFiles(outside)).to.be.empty;
147
+ });
148
+
149
+ it('rejects an entry with an absolute path', async () => {
150
+ const target = path.join(outside, 'evil.txt').split(path.sep).join('/');
151
+ await expectRejection(extractor.extract(await format.create([{ name: target, data: 'evil' }]), destination), /absolute path/);
152
+ expect(await listFiles(outside)).to.be.empty;
153
+ });
154
+
155
+ it('does not write through a symlinked directory in the destination', async () => {
156
+ await fs.promises.mkdir(destination);
157
+ await fs.promises.symlink(outside, path.join(destination, 'link'), 'junction');
158
+ await expectRejection(extractor.extract(await format.create([{ name: 'link/evil.txt', data: 'evil' }]), destination), /leaves the extraction directory/);
159
+ expect(await listFiles(outside)).to.be.empty;
160
+ });
161
+
162
+ it('does not create directories through a symlinked directory in the destination', async () => {
163
+ await fs.promises.mkdir(destination);
164
+ await fs.promises.symlink(outside, path.join(destination, 'link'), 'junction');
165
+ await expectRejection(extractor.extract(await format.create([{ name: 'link/new-directory/evil.txt', data: 'evil' }]), destination),
166
+ /leaves the extraction directory/);
167
+ expect(await listFiles(outside)).to.be.empty;
168
+ });
169
+
170
+ it('does not write through a symlinked file in the destination', async function (): Promise<void> {
171
+ const target = path.join(outside, 'target.txt');
172
+ await fs.promises.writeFile(target, 'original');
173
+ await fs.promises.mkdir(destination);
174
+ if (!await createFileLink(target, path.join(destination, 'file.txt'))) {
175
+ this.skip();
176
+ }
177
+ await expectRejection(extractor.extract(await format.create([{ name: 'file.txt', data: 'evil' }]), destination), /written through a link/);
178
+ expect(await fs.promises.readFile(target, 'utf8')).to.equal('original');
179
+ });
180
+
181
+ it('does not write a file whose existing target cannot be inspected', async () => {
182
+ await fs.promises.mkdir(destination);
183
+ const target = path.join(await fs.promises.realpath(destination), 'file.txt');
184
+ await fs.promises.writeFile(target, 'original');
185
+ const lstat = sinon.stub(fs.promises, 'lstat').callThrough();
186
+ lstat.withArgs(target).rejects(Object.assign(new Error('EACCES: permission denied'), { code: 'EACCES' }));
187
+ try {
188
+ await expectRejection(extractor.extract(await format.create([{ name: 'file.txt', data: 'evil' }]), destination), /EACCES/);
189
+ } finally {
190
+ lstat.restore();
191
+ }
192
+ expect(await fs.promises.readFile(target, 'utf8')).to.equal('original');
193
+ });
194
+
195
+ it('accepts names that start with two dots', async () => {
196
+ await extractor.extract(await format.create([
197
+ { name: '..config/settings.json', data: '{}' },
198
+ { name: '..hidden', data: 'hidden' }
199
+ ]), destination);
200
+ expect(await listFiles(destination)).to.deep.equal(['..config', '..config/settings.json', '..hidden']);
201
+ });
202
+
203
+ it('creates parent directories that have no entry of their own', async () => {
204
+ const entries = await extractor.extract(await format.create([{ name: 'a/b/c.txt', data: 'content' }]), destination);
205
+ expect(entries.map(entry => entry.path)).to.deep.equal(['a/b/c.txt']);
206
+ expect(await fs.promises.readFile(path.join(destination, 'a', 'b', 'c.txt'), 'utf8')).to.equal('content');
207
+ });
208
+
209
+ it('overwrites existing files in the destination', async () => {
210
+ await fs.promises.mkdir(destination);
211
+ await fs.promises.writeFile(path.join(destination, 'file.txt'), 'old content that is longer');
212
+ await extractor.extract(await format.create([{ name: 'file.txt', data: 'new' }]), destination);
213
+ expect(await fs.promises.readFile(path.join(destination, 'file.txt'), 'utf8')).to.equal('new');
214
+ });
215
+
216
+ it('extracts long entry names', async () => {
217
+ const longName = ['a'.repeat(80), 'b'.repeat(80), 'c'.repeat(80), 'file.txt'].join('/');
218
+ await extractor.extract(await format.create([{ name: longName, data: 'long' }]), destination);
219
+ expect(await fs.promises.readFile(path.join(destination, ...longName.split('/')), 'utf8')).to.equal('long');
220
+ });
221
+
222
+ it('extracts a large file', async () => {
223
+ const data = randomBytes(3 * 1024 * 1024).toString('base64');
224
+ await extractor.extract(await format.create([{ name: 'large.txt', data }]), destination);
225
+ expect(await fs.promises.readFile(path.join(destination, 'large.txt'), 'utf8')).to.equal(data);
226
+ });
227
+
228
+ it('rejects a truncated archive', async () => {
229
+ const archive = await format.create([{ name: 'file.txt', data: randomBytes(64 * 1024).toString('base64') }]);
230
+ await expectRejection(extractor.extract(archive.subarray(0, archive.length / 2), destination), /end of (central directory|data|file)/i);
231
+ });
232
+
233
+ it('extracts an empty archive', async () => {
234
+ const entries = await extractor.extract(await format.create([]), destination, { format: format.name as ArchiveFormat });
235
+ expect(entries).to.be.empty;
236
+ expect(await listFiles(destination)).to.be.empty;
237
+ });
238
+
239
+ (process.platform === 'linux' ? it : it.skip)('closes the archive file after a failed extraction', async () => {
240
+ const archive = await writeArchive(`archive.${format.name}`, await format.create([
241
+ { name: 'file.txt', data: 'content' },
242
+ { name: '../outside/evil.txt', data: 'evil' }
243
+ ]));
244
+ const openBefore = (await fs.promises.readdir('/proc/self/fd')).length;
245
+ await expectRejection(extractor.extract(archive, destination), /invalid relative path|leaves the extraction directory/);
246
+ expect((await fs.promises.readdir('/proc/self/fd')).length).to.equal(openBefore);
247
+ });
248
+ });
249
+ }
250
+
251
+ describe('zip entries', () => {
252
+
253
+ (isWindows ? it.skip : it)('uses default permissions for entries without a Unix mode', async () => {
254
+ const entries = await extractor.extract(createTestZip([{ name: 'file.txt', mode: 0, data: 'content' }]), destination);
255
+ expect(entries.map(entry => entry.mode)).to.deep.equal([undefined]);
256
+ expect((await fs.promises.stat(path.join(destination, 'file.txt'))).mode & 0o777).to.equal(0o666 & ~process.umask());
257
+ });
258
+
259
+ it('accepts backslashes as separators', async () => {
260
+ await extractor.extract(createTestZip([{ name: 'dir\\file.txt', data: 'content' }]), destination);
261
+ expect(await listFiles(destination)).to.deep.equal(['dir', 'dir/file.txt']);
262
+ });
263
+
264
+ it('rejects an entry that leaves the destination with backslashes', async () => {
265
+ await expectRejection(extractor.extract(createTestZip([{ name: '..\\outside\\evil.txt', data: 'evil' }]), destination),
266
+ /invalid relative path|leaves the extraction directory/);
267
+ expect(await listFiles(outside)).to.be.empty;
268
+ });
269
+ });
270
+
271
+ describe('zip links', () => {
272
+
273
+ it('skips a symlink entry', async () => {
274
+ const entries = await extractor.extract(createTestZip([
275
+ { name: 'link', mode: 0o120777, data: outside },
276
+ { name: 'file.txt', data: 'content' }
277
+ ]), destination);
278
+ expect(entries.map(entry => entry.path)).to.deep.equal(['file.txt']);
279
+ expect(await listFiles(destination)).to.deep.equal(['file.txt']);
280
+ expect(warnings.join()).to.contain('link');
281
+ });
282
+
283
+ it('keeps a file inside the destination when it follows a symlink entry of the same name', async () => {
284
+ await extractor.extract(createTestZip([
285
+ { name: 'link', mode: 0o120777, data: outside },
286
+ { name: 'link/evil.txt', data: 'evil' }
287
+ ]), destination);
288
+ expect(await listFiles(destination)).to.deep.equal(['link', 'link/evil.txt']);
289
+ expect(await listFiles(outside)).to.be.empty;
290
+ });
291
+ });
292
+
293
+ describe('tar links', () => {
294
+
295
+ it('skips a chain of symlink entries', async () => {
296
+ await extractor.extract(await createTestTar([
297
+ { name: 'a', type: 'symlink', linkname: '..' },
298
+ { name: 'a/b', type: 'symlink', linkname: '../outside' },
299
+ { name: 'a/b/evil.txt', data: 'evil' }
300
+ ]), destination);
301
+ expect(await listFiles(destination)).to.deep.equal(['a', 'a/b', 'a/b/evil.txt']);
302
+ expect(await listFiles(outside)).to.be.empty;
303
+ });
304
+
305
+ it('skips a hardlink entry', async () => {
306
+ const target = path.join(outside, 'secret.txt');
307
+ await fs.promises.writeFile(target, 'secret');
308
+ const entries = await extractor.extract(await createTestTar([
309
+ { name: 'secret.txt', type: 'link', linkname: target },
310
+ { name: 'file.txt', data: 'content' }
311
+ ]), destination);
312
+ expect(entries.map(entry => entry.path)).to.deep.equal(['file.txt']);
313
+ expect(await listFiles(destination)).to.deep.equal(['file.txt']);
314
+ expect(warnings.join()).to.contain('secret.txt');
315
+ });
316
+
317
+ it('skips special entries', async () => {
318
+ const entries = await extractor.extract(await createTestTar([
319
+ { name: 'pipe', type: 'fifo' },
320
+ { name: 'file.txt', data: 'content' }
321
+ ]), destination);
322
+ expect(entries.map(entry => entry.path)).to.deep.equal(['file.txt']);
323
+ });
324
+
325
+ it('reports links that are skipped while reading files', async () => {
326
+ const files = await extractor.readFiles(await createTestTar([
327
+ { name: 'link', type: 'symlink', linkname: '/etc/passwd' },
328
+ { name: 'file.txt', data: 'content' }
329
+ ]));
330
+ expect(files.map(file => file.path)).to.deep.equal(['file.txt']);
331
+ expect(warnings.join()).to.contain('link');
332
+ });
333
+
334
+ it('reports skipped entries on the console without a logger', async () => {
335
+ const warn = sinon.stub(console, 'warn');
336
+ try {
337
+ await new ArchiveExtractorImpl().extract(await createTestTar([
338
+ { name: 'link', type: 'symlink', linkname: '/etc/passwd' },
339
+ { name: 'file.txt', data: 'content' }
340
+ ]), destination);
341
+ expect(warn.calledOnceWith('Skipped 1 link or special entries of archive: link')).to.be.true;
342
+ } finally {
343
+ warn.restore();
344
+ }
345
+ });
346
+ });
347
+
348
+ it('rejects an unsupported format', async () => {
349
+ await expectRejection(extractor.extract(Buffer.from('not an archive'), destination), /Unsupported archive format/);
350
+ });
351
+
352
+ it('rejects a header that only resembles a zip signature', async () => {
353
+ await expectRejection(extractor.extract(Buffer.from('PK\x03\x06 not an archive', 'latin1'), destination), /Unsupported archive format/);
354
+ });
355
+
356
+ it('uses the given format instead of detecting it', async () => {
357
+ await expectRejection(extractor.extract(createTestZip([{ name: 'file.txt' }]), destination, { format: 'tgz' }), /incorrect header check/);
358
+ });
359
+ });