You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FileSystemAPIUtils.ts 2.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import { basename } from 'node:path'
  2. import mime from 'mime'
  3. class FileSystemEntry {
  4. private _isFile: boolean
  5. private _fullPath: string
  6. constructor(isFile: boolean, fullPath: string) {
  7. this._isFile = isFile
  8. this._fullPath = fullPath
  9. }
  10. get isFile() {
  11. return !!this._isFile
  12. }
  13. get isDirectory() {
  14. return !this.isFile
  15. }
  16. get name() {
  17. return basename(this._fullPath)
  18. }
  19. }
  20. export class FileSystemFileEntry extends FileSystemEntry {
  21. private _contents: string
  22. private _lastModified: number
  23. constructor(fullPath: string, contents: string, lastModified = Date.now()) {
  24. super(true, fullPath)
  25. this._contents = contents
  26. this._lastModified = lastModified
  27. }
  28. file(success: (file: File) => void) {
  29. const lastModified = this._lastModified
  30. // Faking the mime by using the file extension
  31. const type = mime.getType(this.name) || ''
  32. success(new File([this._contents], this.name, { lastModified, type }))
  33. }
  34. }
  35. export class FileSystemDirectoryEntry extends FileSystemEntry {
  36. private _entries: FileSystemEntry[]
  37. constructor(fullPath: string, entries: FileSystemEntry[]) {
  38. super(false, fullPath)
  39. this._entries = entries || []
  40. }
  41. createReader() {
  42. let read = false
  43. return {
  44. readEntries: (success: (entries: FileSystemEntry[]) => void) => {
  45. if (read) {
  46. return success([])
  47. }
  48. read = true
  49. success(this._entries)
  50. },
  51. }
  52. }
  53. }
  54. /**
  55. * This mocks the File API's File class
  56. * It will allow us to test the Filesystem API as well as the
  57. * File API in the same test suite.
  58. */
  59. export class DataTransferItem {
  60. private _type: string
  61. private _entry: FileSystemEntry
  62. getAsEntry?: () => FileSystemEntry
  63. constructor(type = '', entry: FileSystemEntry, isFileSystemAPIAvailable = true) {
  64. this._type = type
  65. this._entry = entry
  66. // Only when the Files API is available we are
  67. // able to get the entry
  68. if (isFileSystemAPIAvailable) {
  69. this.getAsEntry = () => this._entry
  70. }
  71. }
  72. get kind() {
  73. return 'file'
  74. }
  75. get type() {
  76. return this._type
  77. }
  78. getAsFile(): File|null {
  79. if (this._entry.isFile && this._entry instanceof FileSystemFileEntry) {
  80. let file: File | null = null
  81. this._entry.file((f) => {
  82. file = f
  83. })
  84. return file
  85. }
  86. // The browser will return an empty File object if the entry is a directory
  87. return new File([], this._entry.name, { type: '' })
  88. }
  89. }
  90. export const fileSystemEntryToDataTransferItem = (entry: FileSystemEntry, isFileSystemAPIAvailable = true): DataTransferItem => {
  91. return new DataTransferItem(
  92. entry.isFile ? 'text/plain' : 'httpd/unix-directory',
  93. entry,
  94. isFileSystemAPIAvailable,
  95. )
  96. }