|
| 1 | +module Js.Blob |
| 2 | + ( Blob |
| 3 | + , BlobEnding(..) |
| 4 | + , BlobOptions |
| 5 | + , ByteIdx |
| 6 | + , EndByte(..) |
| 7 | + , StartByte(..) |
| 8 | + , fromArrayBuffers |
| 9 | + , fromBlobs |
| 10 | + , fromDataView |
| 11 | + , fromString |
| 12 | + , fromStrings |
| 13 | + , idxFromInt |
| 14 | + , idxFromNumber |
| 15 | + , size |
| 16 | + , slice |
| 17 | + , slice' |
| 18 | + , text |
| 19 | + , toArrayBuffer |
| 20 | + , type_ |
| 21 | + ) where |
| 22 | + |
| 23 | +import Control.Applicative ((<#>)) |
| 24 | +import Data.Array.NonEmpty (NonEmptyArray) |
| 25 | +import Data.Array.NonEmpty as NonEmptyArray |
| 26 | +import Data.ArrayBuffer.Types (ArrayBuffer, DataView) |
| 27 | +import Data.Int (toNumber) |
| 28 | +import Data.Maybe (Maybe(..)) |
| 29 | +import Data.MediaType (MediaType(..)) |
| 30 | +import Data.Newtype (un) |
| 31 | +import Data.Nullable (Nullable, toNullable) |
| 32 | +import Data.Nullable as Nullable |
| 33 | +import Data.Number (round) |
| 34 | +import Effect (Effect) |
| 35 | +import Prelude ((#), (==), (>>>)) |
| 36 | +import Promise (Promise) |
| 37 | +import Unsafe.Coerce (unsafeCoerce) |
| 38 | + |
| 39 | +foreign import data Blob :: Type |
| 40 | + |
| 41 | +data BlobEnding = Transparent | Native |
| 42 | + |
| 43 | +type BlobOptions = |
| 44 | + { "type" :: MediaType |
| 45 | + , endings :: BlobEnding |
| 46 | + } |
| 47 | + |
| 48 | +type BlobOptionsImpl = |
| 49 | + { "type" :: String |
| 50 | + , endings :: String |
| 51 | + } |
| 52 | + |
| 53 | +toBlobOptionsImpl :: BlobOptions -> BlobOptionsImpl |
| 54 | +toBlobOptionsImpl { "type": mediaType, endings } = |
| 55 | + { "type": un MediaType mediaType |
| 56 | + , endings: toEndings endings |
| 57 | + } |
| 58 | + where |
| 59 | + toEndings Transparent = "transparent" |
| 60 | + toEndings Native = "native" |
| 61 | + |
| 62 | +foreign import fromStringsImpl :: Array String -> Nullable BlobOptionsImpl -> Blob |
| 63 | + |
| 64 | +-- | Creates a String with the given Mediatype |
| 65 | +-- | For example: |
| 66 | +-- | ``` |
| 67 | +-- | myBlob = fromString (unsafeStringify { name: "Carl", age: 25 }) (MediaType "application/json") |
| 68 | +-- | ``` |
| 69 | +fromString :: String -> Maybe BlobOptions -> Blob |
| 70 | +fromString strs opts = fromStringsImpl [ strs ] (opts <#> toBlobOptionsImpl # toNullable) |
| 71 | + |
| 72 | +-- | Creates a new Blob from one or more strings |
| 73 | +fromStrings :: NonEmptyArray String -> Maybe BlobOptions -> Blob |
| 74 | +fromStrings strs opts = fromStringsImpl (NonEmptyArray.toArray strs) (opts <#> toBlobOptionsImpl # toNullable) |
| 75 | + |
| 76 | +foreign import typeImpl :: Blob -> String |
| 77 | + |
| 78 | +-- | `MediaType` of the data contained in the `Blob`. |
| 79 | +-- | Returns `Nothing` if the `MediaType` is unknown. |
| 80 | +type_ :: Blob -> Maybe MediaType |
| 81 | +type_ blob = |
| 82 | + let |
| 83 | + blobType = typeImpl blob |
| 84 | + in |
| 85 | + if blobType == "" then Nothing |
| 86 | + else Just (MediaType blobType) |
| 87 | + |
| 88 | +-- | The size (in bytes) of the data contained in the `Blob`. |
| 89 | +foreign import size :: Blob -> Int |
| 90 | + |
| 91 | +-- | An index into the Blob indicating the first byte to include in the new Blob. |
| 92 | +-- | If you specify a negative value, it's treated as an offset from the end of the |
| 93 | +-- | string toward the beginning. For example, -10 would be the 10th from last byte |
| 94 | +-- | in the Blob. If you specify a value for start that is larger than the size |
| 95 | +-- | of the source Blob, the returned Blob has size 0 and contains no data. |
| 96 | +newtype StartByte = StartByte ByteIdx |
| 97 | + |
| 98 | +-- | An index into the Blob indicating the first byte that will *not* be included |
| 99 | +-- | in the new Blob (i.e. the byte exactly at this index is not included). |
| 100 | +-- | If you specify a negative value, it's treated as an offset from the end of |
| 101 | +-- | the string toward the beginning. For example, -10 would be the 10th from |
| 102 | +-- | last byte in the Blob. The default value is size. |
| 103 | +newtype EndByte = EndByte ByteIdx |
| 104 | + |
| 105 | +foreign import data ByteIdx :: Type |
| 106 | + |
| 107 | +-- | Creates `ByteIdx` from `Int` value |
| 108 | +idxFromInt :: Int -> ByteIdx |
| 109 | +idxFromInt = toNumber >>> unsafeCoerce |
| 110 | + |
| 111 | +-- | Creates `ByteIdx` from `Number` value using `Math.round`. |
| 112 | +idxFromNumber :: Number -> ByteIdx |
| 113 | +idxFromNumber = round >>> unsafeCoerce |
| 114 | + |
| 115 | +-- | Creates a new `Blob` object (with specified `MediaType`), containing the |
| 116 | +-- | data in the specified range of bytes of the source Blob, by setting . |
| 117 | +foreign import sliceImpl ∷ Nullable MediaType -> StartByte -> EndByte -> Blob -> Blob |
| 118 | + |
| 119 | +-- | Creates a new `Blob` object containing the data in the specified range |
| 120 | +-- | of bytes of the source Blob. |
| 121 | +slice ∷ MediaType -> StartByte -> EndByte -> Blob -> Blob |
| 122 | +slice mt = sliceImpl (Nullable.notNull mt) |
| 123 | + |
| 124 | +-- | Creates a new `Blob` object containing the data in the specified range |
| 125 | +-- | of bytes of the source Blob. |
| 126 | +slice' ∷ StartByte -> EndByte -> Blob -> Blob |
| 127 | +slice' = sliceImpl (Nullable.null) |
| 128 | + |
| 129 | +-- | Returns a promise that fulfills with the contents of the Blob decoded as a UTF-8 string. |
| 130 | +foreign import text :: Blob -> Effect (Promise String) |
| 131 | + |
| 132 | +-- | Copies the data in the Blob to a new JS ArrayBuffer |
| 133 | +foreign import toArrayBuffer :: Blob -> Effect (Promise ArrayBuffer) |
| 134 | + |
| 135 | +foreign import fromArrayBuffersImpl :: NonEmptyArray ArrayBuffer -> Nullable BlobOptionsImpl -> Blob |
| 136 | + |
| 137 | +-- | Creates a new Blob from one ore more `ArrayBuffer`s |
| 138 | +fromArrayBuffers :: NonEmptyArray ArrayBuffer -> Maybe BlobOptions -> Blob |
| 139 | +fromArrayBuffers strs opts = fromArrayBuffersImpl strs (opts <#> toBlobOptionsImpl # toNullable) |
| 140 | + |
| 141 | +foreign import fromBlobsImpl :: NonEmptyArray Blob -> Nullable BlobOptionsImpl -> Blob |
| 142 | + |
| 143 | +-- | Creates a new Blob from one ore more `Blob`s |
| 144 | +fromBlobs :: NonEmptyArray Blob -> Maybe BlobOptions -> Blob |
| 145 | +fromBlobs strs opts = fromBlobsImpl strs (opts <#> toBlobOptionsImpl # toNullable) |
| 146 | + |
| 147 | +foreign import fromDataViewImpl :: NonEmptyArray DataView -> Nullable BlobOptionsImpl -> Blob |
| 148 | + |
| 149 | +-- | Creates a new Blob from one ore more `DataView`s |
| 150 | +fromDataView :: NonEmptyArray DataView -> Maybe BlobOptions -> Blob |
| 151 | +fromDataView strs opts = fromDataViewImpl strs (opts <#> toBlobOptionsImpl # toNullable) |
0 commit comments