fesm2015.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*!
  2. MIT License
  3. Copyright (c) 2018 Arturas Molcanovas <a.molcanovas@gmail.com>
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in all
  11. copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. SOFTWARE.
  19. */
  20. /**
  21. * Abstracts constructing a Blob object, so it also works in older
  22. * browsers that don't support the native Blob constructor. (i.e.
  23. * old QtWebKit versions, at least).
  24. * Abstracts constructing a Blob object, so it also works in older
  25. * browsers that don't support the native Blob constructor. (i.e.
  26. * old QtWebKit versions, at least).
  27. *
  28. * @param parts
  29. * @param properties
  30. */
  31. function createBlob(parts, properties) {
  32. /* global BlobBuilder,MSBlobBuilder,MozBlobBuilder,WebKitBlobBuilder */
  33. parts = parts || [];
  34. properties = properties || {};
  35. try {
  36. return new Blob(parts, properties);
  37. }
  38. catch (e) {
  39. if (e.name !== 'TypeError') {
  40. throw e;
  41. }
  42. //tslint:disable-next-line:variable-name
  43. const Builder = typeof BlobBuilder !== 'undefined' ? BlobBuilder
  44. : typeof MSBlobBuilder !== 'undefined' ? MSBlobBuilder
  45. : typeof MozBlobBuilder !== 'undefined' ? MozBlobBuilder
  46. : WebKitBlobBuilder;
  47. const builder = new Builder();
  48. for (let i = 0; i < parts.length; i += 1) {
  49. builder.append(parts[i]);
  50. }
  51. return builder.getBlob(properties.type);
  52. }
  53. }
  54. const BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;
  55. const SERIALIZED_MARKER_LENGTH = "__lfsc__:" /* SERIALIZED_MARKER */.length;
  56. const TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + "arbf" /* TYPE_ARRAYBUFFER */.length;
  57. //tslint:disable:no-magic-numbers no-bitwise prefer-switch no-unbound-method
  58. const toString = Object.prototype.toString;
  59. function stringToBuffer(serializedString) {
  60. // Fill the string into a ArrayBuffer.
  61. let bufferLength = serializedString.length * 0.75;
  62. const len = serializedString.length;
  63. if (serializedString[serializedString.length - 1] === '=') {
  64. bufferLength--;
  65. if (serializedString[serializedString.length - 2] === '=') {
  66. bufferLength--;
  67. }
  68. }
  69. const buffer = new ArrayBuffer(bufferLength);
  70. const bytes = new Uint8Array(buffer);
  71. for (let i = 0, p = 0; i < len; i += 4) {
  72. const encoded1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */.indexOf(serializedString[i]);
  73. const encoded2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */.indexOf(serializedString[i + 1]);
  74. const encoded3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */.indexOf(serializedString[i + 2]);
  75. const encoded4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */.indexOf(serializedString[i + 3]);
  76. bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
  77. bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
  78. bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
  79. }
  80. return buffer;
  81. }
  82. /**
  83. * Converts a buffer to a string to store, serialized, in the backend
  84. * storage library.
  85. */
  86. function bufferToString(buffer) {
  87. // base64-arraybuffer
  88. const bytes = new Uint8Array(buffer);
  89. let base64String = '';
  90. for (let i = 0; i < bytes.length; i += 3) {
  91. /*jslint bitwise: true */
  92. base64String += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */[bytes[i] >> 2];
  93. base64String += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
  94. base64String +=
  95. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
  96. base64String += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" /* BASE_CHARS */[bytes[i + 2] & 63];
  97. }
  98. if (bytes.length % 3 === 2) {
  99. base64String = base64String.substring(0, base64String.length - 1) + '=';
  100. }
  101. else if (bytes.length % 3 === 1) {
  102. base64String = base64String.substring(0, base64String.length - 2) + '==';
  103. }
  104. return base64String;
  105. }
  106. /**
  107. * Serialize a value, afterwards executing a callback (which usually
  108. * instructs the `setItem()` callback/promise to be executed). This is how
  109. * we store binary data with localStorage.
  110. * @param value
  111. * @param callback
  112. */
  113. function serialize(value, callback) {
  114. let valueType = '';
  115. if (value) {
  116. valueType = toString.call(value);
  117. }
  118. // Cannot use `value instanceof ArrayBuffer` or such here, as these
  119. // checks fail when running the tests using casper.js...
  120. if (value && (valueType === '[object ArrayBuffer]' ||
  121. (value.buffer && toString.call(value.buffer) === '[object ArrayBuffer]'))) {
  122. // Convert binary arrays to a string and prefix the string with
  123. // a special marker.
  124. let buffer;
  125. let marker = "__lfsc__:" /* SERIALIZED_MARKER */;
  126. if (value instanceof ArrayBuffer) {
  127. buffer = value;
  128. marker += "arbf" /* TYPE_ARRAYBUFFER */;
  129. }
  130. else {
  131. buffer = value.buffer;
  132. if (valueType === '[object Int8Array]') {
  133. marker += "si08" /* TYPE_INT8ARRAY */;
  134. }
  135. else if (valueType === '[object Uint8Array]') {
  136. marker += "ui08" /* TYPE_UINT8ARRAY */;
  137. }
  138. else if (valueType === '[object Uint8ClampedArray]') {
  139. marker += "uic8" /* TYPE_UINT8CLAMPEDARRAY */;
  140. }
  141. else if (valueType === '[object Int16Array]') {
  142. marker += "si16" /* TYPE_INT16ARRAY */;
  143. }
  144. else if (valueType === '[object Uint16Array]') {
  145. marker += "ur16" /* TYPE_UINT16ARRAY */;
  146. }
  147. else if (valueType === '[object Int32Array]') {
  148. marker += "si32" /* TYPE_INT32ARRAY */;
  149. }
  150. else if (valueType === '[object Uint32Array]') {
  151. marker += "ui32" /* TYPE_UINT32ARRAY */;
  152. }
  153. else if (valueType === '[object Float32Array]') {
  154. marker += "fl32" /* TYPE_FLOAT32ARRAY */;
  155. }
  156. else if (valueType === '[object Float64Array]') {
  157. marker += "fl64" /* TYPE_FLOAT64ARRAY */;
  158. }
  159. else {
  160. callback(new Error('Failed to get type for BinaryArray'));
  161. }
  162. }
  163. callback(marker + bufferToString(buffer));
  164. }
  165. else if (valueType === '[object Blob]') {
  166. // Convert the blob to a binaryArray and then to a string.
  167. const fileReader = new FileReader();
  168. fileReader.onload = function () {
  169. // Backwards-compatible prefix for the blob type.
  170. //tslint:disable-next-line:restrict-plus-operands
  171. const str = `${"~~local_forage_type~" /* BLOB_TYPE_PREFIX */ + value.type}~${bufferToString(this.result)}`;
  172. callback("__lfsc__:" /* SERIALIZED_MARKER */ + "blob" /* TYPE_BLOB */ + str);
  173. };
  174. fileReader.readAsArrayBuffer(value);
  175. }
  176. else {
  177. try {
  178. callback(JSON.stringify(value));
  179. }
  180. catch (e) {
  181. console.error('Couldn\'t convert value into a JSON string: ', value);
  182. callback(null, e);
  183. }
  184. }
  185. }
  186. /**
  187. * Deserialize data we've inserted into a value column/field. We place
  188. * special markers into our strings to mark them as encoded; this isn't
  189. * as nice as a meta field, but it's the only sane thing we can do whilst
  190. * keeping localStorage support intact.
  191. *
  192. * Oftentimes this will just deserialize JSON content, but if we have a
  193. * special marker (SERIALIZED_MARKER, defined above), we will extract
  194. * some kind of arraybuffer/binary data/typed array out of the string.
  195. * @param value
  196. */
  197. function deserialize(value) {
  198. // If we haven't marked this string as being specially serialized (i.e.
  199. // something other than serialized JSON), we can just return it and be
  200. // done with it.
  201. if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== "__lfsc__:" /* SERIALIZED_MARKER */) {
  202. return JSON.parse(value);
  203. }
  204. // The following code deals with deserializing some kind of Blob or
  205. // TypedArray. First we separate out the type of data we're dealing
  206. // with from the data itself.
  207. let serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
  208. const type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);
  209. let blobType;
  210. // Backwards-compatible blob type serialization strategy.
  211. // DBs created with older versions of localForage will simply not have the blob type.
  212. if (type === "blob" /* TYPE_BLOB */ && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {
  213. const matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);
  214. blobType = matcher[1];
  215. serializedString = serializedString.substring(matcher[0].length);
  216. }
  217. const buffer = stringToBuffer(serializedString);
  218. // Return the right type based on the code/type set during
  219. // serialization.
  220. switch (type) {
  221. case "arbf" /* TYPE_ARRAYBUFFER */:
  222. return buffer;
  223. case "blob" /* TYPE_BLOB */:
  224. return createBlob([buffer], { type: blobType });
  225. case "si08" /* TYPE_INT8ARRAY */:
  226. return new Int8Array(buffer);
  227. case "ui08" /* TYPE_UINT8ARRAY */:
  228. return new Uint8Array(buffer);
  229. case "uic8" /* TYPE_UINT8CLAMPEDARRAY */:
  230. return new Uint8ClampedArray(buffer);
  231. case "si16" /* TYPE_INT16ARRAY */:
  232. return new Int16Array(buffer);
  233. case "ur16" /* TYPE_UINT16ARRAY */:
  234. return new Uint16Array(buffer);
  235. case "si32" /* TYPE_INT32ARRAY */:
  236. return new Int32Array(buffer);
  237. case "ui32" /* TYPE_UINT32ARRAY */:
  238. return new Uint32Array(buffer);
  239. case "fl32" /* TYPE_FLOAT32ARRAY */:
  240. return new Float32Array(buffer);
  241. case "fl64" /* TYPE_FLOAT64ARRAY */:
  242. return new Float64Array(buffer);
  243. default:
  244. throw new Error('Unkown type: ' + type);
  245. }
  246. }
  247. function clone(obj) {
  248. if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj) {
  249. return obj;
  250. }
  251. const temp = obj instanceof Date ? new Date(obj) : (obj.constructor());
  252. for (const key of Object.keys(obj)) {
  253. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  254. obj['isActiveClone'] = null;
  255. temp[key] = clone(obj[key]);
  256. delete obj['isActiveClone'];
  257. }
  258. }
  259. return temp;
  260. }
  261. function getKeyPrefix(options, defaultConfig) {
  262. return `${options.name || defaultConfig.name}/${options.storeName || defaultConfig.storeName}/`;
  263. }
  264. function executeCallback(promise, callback) {
  265. if (callback) {
  266. promise.then((result) => {
  267. callback(null, result);
  268. }, (error) => {
  269. callback(error);
  270. });
  271. }
  272. }
  273. function getCallback(..._args) {
  274. if (arguments.length && typeof arguments[arguments.length - 1] === 'function') {
  275. return arguments[arguments.length - 1];
  276. }
  277. }
  278. //tslint:disable-next-line:no-ignored-initial-value
  279. function dropInstanceCommon(options, callback) {
  280. callback = getCallback.apply(this, arguments);
  281. options = (typeof options !== 'function' && options) || {};
  282. if (!options.name) {
  283. const currentConfig = this.config();
  284. options.name = options.name || currentConfig.name;
  285. options.storeName = options.storeName || currentConfig.storeName;
  286. }
  287. let promise;
  288. if (!options.name) {
  289. promise = Promise.reject('Invalid arguments');
  290. }
  291. else {
  292. promise = new Promise(resolve => {
  293. if (!options.storeName) {
  294. resolve(`${options.name}/`);
  295. }
  296. else {
  297. resolve(getKeyPrefix(options, this._defaultConfig));
  298. }
  299. });
  300. }
  301. return { promise, callback };
  302. }
  303. function normaliseKey(key) {
  304. // Cast the key to a string, as that's all we can set as a key.
  305. if (typeof key !== 'string') {
  306. console.warn(`${key} used as a key, but it is not a string.`);
  307. key = String(key);
  308. }
  309. return key;
  310. }
  311. const serialiser = {
  312. bufferToString,
  313. deserialize,
  314. serialize,
  315. stringToBuffer
  316. };
  317. export { serialiser, clone, getKeyPrefix, executeCallback, getCallback, dropInstanceCommon, normaliseKey };
  318. //# sourceMappingURL=fesm2015.js.map