index.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // @ts-check
  2. 'use strict'
  3. const assert = require('check-types').assert
  4. const Blob = require('../blob')
  5. /**
  6. * @import { BlobStore, ReadonlyBlobStore, RawFileData, CommentRawData } from "../types"
  7. * @import EditOperation from "../operation/edit_operation"
  8. * @import CommentList from "../file_data/comment_list"
  9. * @import TrackedChangeList from "../file_data/tracked_change_list"
  10. */
  11. /**
  12. * Helper to represent the content of a file. This class and its subclasses
  13. * should be used only through {@link File}.
  14. */
  15. class FileData {
  16. /** @see File.fromRaw
  17. * @param {RawFileData} raw
  18. */
  19. static fromRaw(raw) {
  20. // TODO(das7pad): can we teach typescript to understand our polymorphism?
  21. if (Object.prototype.hasOwnProperty.call(raw, 'hash')) {
  22. if (Object.prototype.hasOwnProperty.call(raw, 'byteLength'))
  23. // @ts-ignore
  24. return BinaryFileData.fromRaw(raw)
  25. if (Object.prototype.hasOwnProperty.call(raw, 'stringLength'))
  26. // @ts-ignore
  27. return LazyStringFileData.fromRaw(raw)
  28. // @ts-ignore
  29. return HashFileData.fromRaw(raw)
  30. }
  31. if (Object.prototype.hasOwnProperty.call(raw, 'byteLength'))
  32. // @ts-ignore
  33. return HollowBinaryFileData.fromRaw(raw)
  34. if (Object.prototype.hasOwnProperty.call(raw, 'stringLength'))
  35. // @ts-ignore
  36. return HollowStringFileData.fromRaw(raw)
  37. if (Object.prototype.hasOwnProperty.call(raw, 'content'))
  38. // @ts-ignore
  39. return StringFileData.fromRaw(raw)
  40. throw new Error('FileData: bad raw object ' + JSON.stringify(raw))
  41. }
  42. /** @see File.createHollow
  43. * @param {number} byteLength
  44. * @param {number} [stringLength]
  45. */
  46. static createHollow(byteLength, stringLength) {
  47. if (stringLength == null) {
  48. return new HollowBinaryFileData(byteLength)
  49. }
  50. return new HollowStringFileData(stringLength)
  51. }
  52. /**
  53. * @see File.createLazyFromBlob
  54. * @param {Blob} blob
  55. * @param {Blob} [rangesBlob]
  56. */
  57. static createLazyFromBlobs(blob, rangesBlob) {
  58. assert.instance(blob, Blob, 'FileData: bad blob')
  59. const stringLength = blob.getStringLength()
  60. if (stringLength == null) {
  61. return new BinaryFileData(blob.getHash(), blob.getByteLength())
  62. }
  63. return new LazyStringFileData(
  64. blob.getHash(),
  65. rangesBlob?.getHash(),
  66. stringLength
  67. )
  68. }
  69. /**
  70. * @returns {RawFileData}
  71. */
  72. toRaw() {
  73. throw new Error('FileData: toRaw not implemented')
  74. }
  75. /**
  76. * @returns {Record<string, number>}
  77. */
  78. toStats() {
  79. throw new Error('FileData: toStats not implemented')
  80. }
  81. /**
  82. * @see File#getHash
  83. * @return {string | null | undefined}
  84. */
  85. getHash() {
  86. return null
  87. }
  88. /**
  89. * @see File#getHash
  90. * @return {string | null | undefined}
  91. */
  92. getRangesHash() {
  93. return null
  94. }
  95. /**
  96. * @see File#getContent
  97. * @param {import('../file').FileGetContentOptions} [opts]
  98. * @return {string | null | undefined}
  99. */
  100. getContent(opts = {}) {
  101. return null
  102. }
  103. /**
  104. * @see File#isEditable
  105. * @return {boolean | null | undefined} null if it is not currently known
  106. */
  107. isEditable() {
  108. return null
  109. }
  110. /**
  111. * @see File#getByteLength
  112. * @return {number | null | undefined}
  113. */
  114. getByteLength() {
  115. return null
  116. }
  117. /**
  118. * @see File#getStringLength
  119. * @return {number | null | undefined}
  120. */
  121. getStringLength() {
  122. return null
  123. }
  124. /**
  125. * @see File#edit
  126. * @param {EditOperation} editOperation
  127. */
  128. edit(editOperation) {
  129. throw new Error('edit not implemented for ' + JSON.stringify(this))
  130. }
  131. /**
  132. * @function
  133. * @param {ReadonlyBlobStore} blobStore
  134. * @return {Promise<FileData>}
  135. * @abstract
  136. * @see FileData#load
  137. */
  138. async toEager(blobStore) {
  139. throw new Error('toEager not implemented for ' + JSON.stringify(this))
  140. }
  141. /**
  142. * @function
  143. * @param {ReadonlyBlobStore} blobStore
  144. * @return {Promise<FileData>}
  145. * @abstract
  146. * @see FileData#load
  147. */
  148. async toLazy(blobStore) {
  149. throw new Error('toLazy not implemented for ' + JSON.stringify(this))
  150. }
  151. /**
  152. * @function
  153. * @param {ReadonlyBlobStore} blobStore
  154. * @return {Promise<FileData>}
  155. * @abstract
  156. * @see FileData#load
  157. */
  158. async toHollow(blobStore) {
  159. throw new Error('toHollow not implemented for ' + JSON.stringify(this))
  160. }
  161. /**
  162. * @see File#load
  163. * @param {string} kind
  164. * @param {ReadonlyBlobStore} blobStore
  165. * @return {Promise<FileData>}
  166. */
  167. async load(kind, blobStore) {
  168. if (kind === 'eager') return await this.toEager(blobStore)
  169. if (kind === 'lazy') return await this.toLazy(blobStore)
  170. if (kind === 'hollow') return await this.toHollow(blobStore)
  171. throw new Error('bad file data load kind: ' + kind)
  172. }
  173. /**
  174. * @see File#store
  175. * @function
  176. * @param {BlobStore} blobStore
  177. * @return {Promise<RawFileData>} a raw HashFile
  178. * @abstract
  179. */
  180. async store(blobStore) {
  181. throw new Error('store not implemented for ' + JSON.stringify(this))
  182. }
  183. /**
  184. * @see File#getComments
  185. * @function
  186. * @return {CommentList}
  187. * @abstract
  188. */
  189. getComments() {
  190. throw new Error('getComments not implemented for ' + JSON.stringify(this))
  191. }
  192. /**
  193. * @see File#getTrackedChanges
  194. * @function
  195. * @return {TrackedChangeList}
  196. * @abstract
  197. */
  198. getTrackedChanges() {
  199. throw new Error(
  200. 'getTrackedChanges not implemented for ' + JSON.stringify(this)
  201. )
  202. }
  203. }
  204. module.exports = FileData
  205. const BinaryFileData = require('./binary_file_data')
  206. const HashFileData = require('./hash_file_data')
  207. const HollowBinaryFileData = require('./hollow_binary_file_data')
  208. const HollowStringFileData = require('./hollow_string_file_data')
  209. const LazyStringFileData = require('./lazy_string_file_data')
  210. const StringFileData = require('./string_file_data')