deserializer.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.deserialize = void 0;
  4. var buffer_1 = require("buffer");
  5. var binary_1 = require("../binary");
  6. var code_1 = require("../code");
  7. var constants = require("../constants");
  8. var db_ref_1 = require("../db_ref");
  9. var decimal128_1 = require("../decimal128");
  10. var double_1 = require("../double");
  11. var int_32_1 = require("../int_32");
  12. var long_1 = require("../long");
  13. var max_key_1 = require("../max_key");
  14. var min_key_1 = require("../min_key");
  15. var objectid_1 = require("../objectid");
  16. var regexp_1 = require("../regexp");
  17. var symbol_1 = require("../symbol");
  18. var timestamp_1 = require("../timestamp");
  19. var validate_utf8_1 = require("../validate_utf8");
  20. // Internal long versions
  21. var JS_INT_MAX_LONG = long_1.Long.fromNumber(constants.JS_INT_MAX);
  22. var JS_INT_MIN_LONG = long_1.Long.fromNumber(constants.JS_INT_MIN);
  23. var functionCache = {};
  24. function deserialize(buffer, options, isArray) {
  25. options = options == null ? {} : options;
  26. var index = options && options.index ? options.index : 0;
  27. // Read the document size
  28. var size = buffer[index] |
  29. (buffer[index + 1] << 8) |
  30. (buffer[index + 2] << 16) |
  31. (buffer[index + 3] << 24);
  32. if (size < 5) {
  33. throw new Error("bson size must be >= 5, is " + size);
  34. }
  35. if (options.allowObjectSmallerThanBufferSize && buffer.length < size) {
  36. throw new Error("buffer length " + buffer.length + " must be >= bson size " + size);
  37. }
  38. if (!options.allowObjectSmallerThanBufferSize && buffer.length !== size) {
  39. throw new Error("buffer length " + buffer.length + " must === bson size " + size);
  40. }
  41. if (size + index > buffer.byteLength) {
  42. throw new Error("(bson size " + size + " + options.index " + index + " must be <= buffer length " + buffer.byteLength + ")");
  43. }
  44. // Illegal end value
  45. if (buffer[index + size - 1] !== 0) {
  46. throw new Error("One object, sized correctly, with a spot for an EOO, but the EOO isn't 0x00");
  47. }
  48. // Start deserializtion
  49. return deserializeObject(buffer, index, options, isArray);
  50. }
  51. exports.deserialize = deserialize;
  52. function deserializeObject(buffer, index, options, isArray) {
  53. if (isArray === void 0) { isArray = false; }
  54. var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions'];
  55. var cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions'];
  56. var fieldsAsRaw = options['fieldsAsRaw'] == null ? null : options['fieldsAsRaw'];
  57. // Return raw bson buffer instead of parsing it
  58. var raw = options['raw'] == null ? false : options['raw'];
  59. // Return BSONRegExp objects instead of native regular expressions
  60. var bsonRegExp = typeof options['bsonRegExp'] === 'boolean' ? options['bsonRegExp'] : false;
  61. // Controls the promotion of values vs wrapper classes
  62. var promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers'];
  63. var promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs'];
  64. var promoteValues = options['promoteValues'] == null ? true : options['promoteValues'];
  65. // Set the start index
  66. var startIndex = index;
  67. // Validate that we have at least 4 bytes of buffer
  68. if (buffer.length < 5)
  69. throw new Error('corrupt bson message < 5 bytes long');
  70. // Read the document size
  71. var size = buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
  72. // Ensure buffer is valid size
  73. if (size < 5 || size > buffer.length)
  74. throw new Error('corrupt bson message');
  75. // Create holding object
  76. var object = isArray ? [] : {};
  77. // Used for arrays to skip having to perform utf8 decoding
  78. var arrayIndex = 0;
  79. var done = false;
  80. // While we have more left data left keep parsing
  81. while (!done) {
  82. // Read the type
  83. var elementType = buffer[index++];
  84. // If we get a zero it's the last byte, exit
  85. if (elementType === 0)
  86. break;
  87. // Get the start search index
  88. var i = index;
  89. // Locate the end of the c string
  90. while (buffer[i] !== 0x00 && i < buffer.length) {
  91. i++;
  92. }
  93. // If are at the end of the buffer there is a problem with the document
  94. if (i >= buffer.byteLength)
  95. throw new Error('Bad BSON Document: illegal CString');
  96. var name = isArray ? arrayIndex++ : buffer.toString('utf8', index, i);
  97. var value = void 0;
  98. index = i + 1;
  99. if (elementType === constants.BSON_DATA_STRING) {
  100. var stringSize = buffer[index++] |
  101. (buffer[index++] << 8) |
  102. (buffer[index++] << 16) |
  103. (buffer[index++] << 24);
  104. if (stringSize <= 0 ||
  105. stringSize > buffer.length - index ||
  106. buffer[index + stringSize - 1] !== 0)
  107. throw new Error('bad string length in bson');
  108. if (!validate_utf8_1.validateUtf8(buffer, index, index + stringSize - 1)) {
  109. throw new Error('Invalid UTF-8 string in BSON document');
  110. }
  111. value = buffer.toString('utf8', index, index + stringSize - 1);
  112. index = index + stringSize;
  113. }
  114. else if (elementType === constants.BSON_DATA_OID) {
  115. var oid = buffer_1.Buffer.alloc(12);
  116. buffer.copy(oid, 0, index, index + 12);
  117. value = new objectid_1.ObjectId(oid);
  118. index = index + 12;
  119. }
  120. else if (elementType === constants.BSON_DATA_INT && promoteValues === false) {
  121. value = new int_32_1.Int32(buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24));
  122. }
  123. else if (elementType === constants.BSON_DATA_INT) {
  124. value =
  125. buffer[index++] |
  126. (buffer[index++] << 8) |
  127. (buffer[index++] << 16) |
  128. (buffer[index++] << 24);
  129. }
  130. else if (elementType === constants.BSON_DATA_NUMBER && promoteValues === false) {
  131. value = new double_1.Double(buffer.readDoubleLE(index));
  132. index = index + 8;
  133. }
  134. else if (elementType === constants.BSON_DATA_NUMBER) {
  135. value = buffer.readDoubleLE(index);
  136. index = index + 8;
  137. }
  138. else if (elementType === constants.BSON_DATA_DATE) {
  139. var lowBits = buffer[index++] |
  140. (buffer[index++] << 8) |
  141. (buffer[index++] << 16) |
  142. (buffer[index++] << 24);
  143. var highBits = buffer[index++] |
  144. (buffer[index++] << 8) |
  145. (buffer[index++] << 16) |
  146. (buffer[index++] << 24);
  147. value = new Date(new long_1.Long(lowBits, highBits).toNumber());
  148. }
  149. else if (elementType === constants.BSON_DATA_BOOLEAN) {
  150. if (buffer[index] !== 0 && buffer[index] !== 1)
  151. throw new Error('illegal boolean type value');
  152. value = buffer[index++] === 1;
  153. }
  154. else if (elementType === constants.BSON_DATA_OBJECT) {
  155. var _index = index;
  156. var objectSize = buffer[index] |
  157. (buffer[index + 1] << 8) |
  158. (buffer[index + 2] << 16) |
  159. (buffer[index + 3] << 24);
  160. if (objectSize <= 0 || objectSize > buffer.length - index)
  161. throw new Error('bad embedded document length in bson');
  162. // We have a raw value
  163. if (raw) {
  164. value = buffer.slice(index, index + objectSize);
  165. }
  166. else {
  167. value = deserializeObject(buffer, _index, options, false);
  168. }
  169. index = index + objectSize;
  170. }
  171. else if (elementType === constants.BSON_DATA_ARRAY) {
  172. var _index = index;
  173. var objectSize = buffer[index] |
  174. (buffer[index + 1] << 8) |
  175. (buffer[index + 2] << 16) |
  176. (buffer[index + 3] << 24);
  177. var arrayOptions = options;
  178. // Stop index
  179. var stopIndex = index + objectSize;
  180. // All elements of array to be returned as raw bson
  181. if (fieldsAsRaw && fieldsAsRaw[name]) {
  182. arrayOptions = {};
  183. for (var n in options) {
  184. arrayOptions[n] = options[n];
  185. }
  186. arrayOptions['raw'] = true;
  187. }
  188. value = deserializeObject(buffer, _index, arrayOptions, true);
  189. index = index + objectSize;
  190. if (buffer[index - 1] !== 0)
  191. throw new Error('invalid array terminator byte');
  192. if (index !== stopIndex)
  193. throw new Error('corrupted array bson');
  194. }
  195. else if (elementType === constants.BSON_DATA_UNDEFINED) {
  196. value = undefined;
  197. }
  198. else if (elementType === constants.BSON_DATA_NULL) {
  199. value = null;
  200. }
  201. else if (elementType === constants.BSON_DATA_LONG) {
  202. // Unpack the low and high bits
  203. var lowBits = buffer[index++] |
  204. (buffer[index++] << 8) |
  205. (buffer[index++] << 16) |
  206. (buffer[index++] << 24);
  207. var highBits = buffer[index++] |
  208. (buffer[index++] << 8) |
  209. (buffer[index++] << 16) |
  210. (buffer[index++] << 24);
  211. var long = new long_1.Long(lowBits, highBits);
  212. // Promote the long if possible
  213. if (promoteLongs && promoteValues === true) {
  214. value =
  215. long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
  216. ? long.toNumber()
  217. : long;
  218. }
  219. else {
  220. value = long;
  221. }
  222. }
  223. else if (elementType === constants.BSON_DATA_DECIMAL128) {
  224. // Buffer to contain the decimal bytes
  225. var bytes = buffer_1.Buffer.alloc(16);
  226. // Copy the next 16 bytes into the bytes buffer
  227. buffer.copy(bytes, 0, index, index + 16);
  228. // Update index
  229. index = index + 16;
  230. // Assign the new Decimal128 value
  231. var decimal128 = new decimal128_1.Decimal128(bytes);
  232. // If we have an alternative mapper use that
  233. if ('toObject' in decimal128 && typeof decimal128.toObject === 'function') {
  234. value = decimal128.toObject();
  235. }
  236. else {
  237. value = decimal128;
  238. }
  239. }
  240. else if (elementType === constants.BSON_DATA_BINARY) {
  241. var binarySize = buffer[index++] |
  242. (buffer[index++] << 8) |
  243. (buffer[index++] << 16) |
  244. (buffer[index++] << 24);
  245. var totalBinarySize = binarySize;
  246. var subType = buffer[index++];
  247. // Did we have a negative binary size, throw
  248. if (binarySize < 0)
  249. throw new Error('Negative binary type element size found');
  250. // Is the length longer than the document
  251. if (binarySize > buffer.byteLength)
  252. throw new Error('Binary type size larger than document size');
  253. // Decode as raw Buffer object if options specifies it
  254. if (buffer['slice'] != null) {
  255. // If we have subtype 2 skip the 4 bytes for the size
  256. if (subType === binary_1.Binary.SUBTYPE_BYTE_ARRAY) {
  257. binarySize =
  258. buffer[index++] |
  259. (buffer[index++] << 8) |
  260. (buffer[index++] << 16) |
  261. (buffer[index++] << 24);
  262. if (binarySize < 0)
  263. throw new Error('Negative binary type element size found for subtype 0x02');
  264. if (binarySize > totalBinarySize - 4)
  265. throw new Error('Binary type with subtype 0x02 contains too long binary size');
  266. if (binarySize < totalBinarySize - 4)
  267. throw new Error('Binary type with subtype 0x02 contains too short binary size');
  268. }
  269. if (promoteBuffers && promoteValues) {
  270. value = buffer.slice(index, index + binarySize);
  271. }
  272. else {
  273. value = new binary_1.Binary(buffer.slice(index, index + binarySize), subType);
  274. }
  275. }
  276. else {
  277. var _buffer = buffer_1.Buffer.alloc(binarySize);
  278. // If we have subtype 2 skip the 4 bytes for the size
  279. if (subType === binary_1.Binary.SUBTYPE_BYTE_ARRAY) {
  280. binarySize =
  281. buffer[index++] |
  282. (buffer[index++] << 8) |
  283. (buffer[index++] << 16) |
  284. (buffer[index++] << 24);
  285. if (binarySize < 0)
  286. throw new Error('Negative binary type element size found for subtype 0x02');
  287. if (binarySize > totalBinarySize - 4)
  288. throw new Error('Binary type with subtype 0x02 contains too long binary size');
  289. if (binarySize < totalBinarySize - 4)
  290. throw new Error('Binary type with subtype 0x02 contains too short binary size');
  291. }
  292. // Copy the data
  293. for (i = 0; i < binarySize; i++) {
  294. _buffer[i] = buffer[index + i];
  295. }
  296. if (promoteBuffers && promoteValues) {
  297. value = _buffer;
  298. }
  299. else {
  300. value = new binary_1.Binary(_buffer, subType);
  301. }
  302. }
  303. // Update the index
  304. index = index + binarySize;
  305. }
  306. else if (elementType === constants.BSON_DATA_REGEXP && bsonRegExp === false) {
  307. // Get the start search index
  308. i = index;
  309. // Locate the end of the c string
  310. while (buffer[i] !== 0x00 && i < buffer.length) {
  311. i++;
  312. }
  313. // If are at the end of the buffer there is a problem with the document
  314. if (i >= buffer.length)
  315. throw new Error('Bad BSON Document: illegal CString');
  316. // Return the C string
  317. var source = buffer.toString('utf8', index, i);
  318. // Create the regexp
  319. index = i + 1;
  320. // Get the start search index
  321. i = index;
  322. // Locate the end of the c string
  323. while (buffer[i] !== 0x00 && i < buffer.length) {
  324. i++;
  325. }
  326. // If are at the end of the buffer there is a problem with the document
  327. if (i >= buffer.length)
  328. throw new Error('Bad BSON Document: illegal CString');
  329. // Return the C string
  330. var regExpOptions = buffer.toString('utf8', index, i);
  331. index = i + 1;
  332. // For each option add the corresponding one for javascript
  333. var optionsArray = new Array(regExpOptions.length);
  334. // Parse options
  335. for (i = 0; i < regExpOptions.length; i++) {
  336. switch (regExpOptions[i]) {
  337. case 'm':
  338. optionsArray[i] = 'm';
  339. break;
  340. case 's':
  341. optionsArray[i] = 'g';
  342. break;
  343. case 'i':
  344. optionsArray[i] = 'i';
  345. break;
  346. }
  347. }
  348. value = new RegExp(source, optionsArray.join(''));
  349. }
  350. else if (elementType === constants.BSON_DATA_REGEXP && bsonRegExp === true) {
  351. // Get the start search index
  352. i = index;
  353. // Locate the end of the c string
  354. while (buffer[i] !== 0x00 && i < buffer.length) {
  355. i++;
  356. }
  357. // If are at the end of the buffer there is a problem with the document
  358. if (i >= buffer.length)
  359. throw new Error('Bad BSON Document: illegal CString');
  360. // Return the C string
  361. var source = buffer.toString('utf8', index, i);
  362. index = i + 1;
  363. // Get the start search index
  364. i = index;
  365. // Locate the end of the c string
  366. while (buffer[i] !== 0x00 && i < buffer.length) {
  367. i++;
  368. }
  369. // If are at the end of the buffer there is a problem with the document
  370. if (i >= buffer.length)
  371. throw new Error('Bad BSON Document: illegal CString');
  372. // Return the C string
  373. var regExpOptions = buffer.toString('utf8', index, i);
  374. index = i + 1;
  375. // Set the object
  376. value = new regexp_1.BSONRegExp(source, regExpOptions);
  377. }
  378. else if (elementType === constants.BSON_DATA_SYMBOL) {
  379. var stringSize = buffer[index++] |
  380. (buffer[index++] << 8) |
  381. (buffer[index++] << 16) |
  382. (buffer[index++] << 24);
  383. if (stringSize <= 0 ||
  384. stringSize > buffer.length - index ||
  385. buffer[index + stringSize - 1] !== 0)
  386. throw new Error('bad string length in bson');
  387. var symbol = buffer.toString('utf8', index, index + stringSize - 1);
  388. value = promoteValues ? symbol : new symbol_1.BSONSymbol(symbol);
  389. index = index + stringSize;
  390. }
  391. else if (elementType === constants.BSON_DATA_TIMESTAMP) {
  392. var lowBits = buffer[index++] |
  393. (buffer[index++] << 8) |
  394. (buffer[index++] << 16) |
  395. (buffer[index++] << 24);
  396. var highBits = buffer[index++] |
  397. (buffer[index++] << 8) |
  398. (buffer[index++] << 16) |
  399. (buffer[index++] << 24);
  400. value = new timestamp_1.Timestamp(lowBits, highBits);
  401. }
  402. else if (elementType === constants.BSON_DATA_MIN_KEY) {
  403. value = new min_key_1.MinKey();
  404. }
  405. else if (elementType === constants.BSON_DATA_MAX_KEY) {
  406. value = new max_key_1.MaxKey();
  407. }
  408. else if (elementType === constants.BSON_DATA_CODE) {
  409. var stringSize = buffer[index++] |
  410. (buffer[index++] << 8) |
  411. (buffer[index++] << 16) |
  412. (buffer[index++] << 24);
  413. if (stringSize <= 0 ||
  414. stringSize > buffer.length - index ||
  415. buffer[index + stringSize - 1] !== 0)
  416. throw new Error('bad string length in bson');
  417. var functionString = buffer.toString('utf8', index, index + stringSize - 1);
  418. // If we are evaluating the functions
  419. if (evalFunctions) {
  420. // If we have cache enabled let's look for the md5 of the function in the cache
  421. if (cacheFunctions) {
  422. // Got to do this to avoid V8 deoptimizing the call due to finding eval
  423. value = isolateEval(functionString, functionCache, object);
  424. }
  425. else {
  426. value = isolateEval(functionString);
  427. }
  428. }
  429. else {
  430. value = new code_1.Code(functionString);
  431. }
  432. // Update parse index position
  433. index = index + stringSize;
  434. }
  435. else if (elementType === constants.BSON_DATA_CODE_W_SCOPE) {
  436. var totalSize = buffer[index++] |
  437. (buffer[index++] << 8) |
  438. (buffer[index++] << 16) |
  439. (buffer[index++] << 24);
  440. // Element cannot be shorter than totalSize + stringSize + documentSize + terminator
  441. if (totalSize < 4 + 4 + 4 + 1) {
  442. throw new Error('code_w_scope total size shorter minimum expected length');
  443. }
  444. // Get the code string size
  445. var stringSize = buffer[index++] |
  446. (buffer[index++] << 8) |
  447. (buffer[index++] << 16) |
  448. (buffer[index++] << 24);
  449. // Check if we have a valid string
  450. if (stringSize <= 0 ||
  451. stringSize > buffer.length - index ||
  452. buffer[index + stringSize - 1] !== 0)
  453. throw new Error('bad string length in bson');
  454. // Javascript function
  455. var functionString = buffer.toString('utf8', index, index + stringSize - 1);
  456. // Update parse index position
  457. index = index + stringSize;
  458. // Parse the element
  459. var _index = index;
  460. // Decode the size of the object document
  461. var objectSize = buffer[index] |
  462. (buffer[index + 1] << 8) |
  463. (buffer[index + 2] << 16) |
  464. (buffer[index + 3] << 24);
  465. // Decode the scope object
  466. var scopeObject = deserializeObject(buffer, _index, options, false);
  467. // Adjust the index
  468. index = index + objectSize;
  469. // Check if field length is too short
  470. if (totalSize < 4 + 4 + objectSize + stringSize) {
  471. throw new Error('code_w_scope total size is too short, truncating scope');
  472. }
  473. // Check if totalSize field is too long
  474. if (totalSize > 4 + 4 + objectSize + stringSize) {
  475. throw new Error('code_w_scope total size is too long, clips outer document');
  476. }
  477. // If we are evaluating the functions
  478. if (evalFunctions) {
  479. // If we have cache enabled let's look for the md5 of the function in the cache
  480. if (cacheFunctions) {
  481. // Got to do this to avoid V8 deoptimizing the call due to finding eval
  482. value = isolateEval(functionString, functionCache, object);
  483. }
  484. else {
  485. value = isolateEval(functionString);
  486. }
  487. value.scope = scopeObject;
  488. }
  489. else {
  490. value = new code_1.Code(functionString, scopeObject);
  491. }
  492. }
  493. else if (elementType === constants.BSON_DATA_DBPOINTER) {
  494. // Get the code string size
  495. var stringSize = buffer[index++] |
  496. (buffer[index++] << 8) |
  497. (buffer[index++] << 16) |
  498. (buffer[index++] << 24);
  499. // Check if we have a valid string
  500. if (stringSize <= 0 ||
  501. stringSize > buffer.length - index ||
  502. buffer[index + stringSize - 1] !== 0)
  503. throw new Error('bad string length in bson');
  504. // Namespace
  505. if (!validate_utf8_1.validateUtf8(buffer, index, index + stringSize - 1)) {
  506. throw new Error('Invalid UTF-8 string in BSON document');
  507. }
  508. var namespace = buffer.toString('utf8', index, index + stringSize - 1);
  509. // Update parse index position
  510. index = index + stringSize;
  511. // Read the oid
  512. var oidBuffer = buffer_1.Buffer.alloc(12);
  513. buffer.copy(oidBuffer, 0, index, index + 12);
  514. var oid = new objectid_1.ObjectId(oidBuffer);
  515. // Update the index
  516. index = index + 12;
  517. // Upgrade to DBRef type
  518. value = new db_ref_1.DBRef(namespace, oid);
  519. }
  520. else {
  521. throw new Error('Detected unknown BSON type ' + elementType.toString(16) + ' for fieldname "' + name + '"');
  522. }
  523. if (name === '__proto__') {
  524. Object.defineProperty(object, name, {
  525. value: value,
  526. writable: true,
  527. enumerable: true,
  528. configurable: true
  529. });
  530. }
  531. else {
  532. object[name] = value;
  533. }
  534. }
  535. // Check if the deserialization was against a valid array/object
  536. if (size !== index - startIndex) {
  537. if (isArray)
  538. throw new Error('corrupt array bson');
  539. throw new Error('corrupt object bson');
  540. }
  541. // check if object's $ keys are those of a DBRef
  542. var dollarKeys = Object.keys(object).filter(function (k) { return k.startsWith('$'); });
  543. var valid = true;
  544. dollarKeys.forEach(function (k) {
  545. if (['$ref', '$id', '$db'].indexOf(k) === -1)
  546. valid = false;
  547. });
  548. // if a $key not in "$ref", "$id", "$db", don't make a DBRef
  549. if (!valid)
  550. return object;
  551. if (db_ref_1.isDBRefLike(object)) {
  552. var copy = Object.assign({}, object);
  553. delete copy.$ref;
  554. delete copy.$id;
  555. delete copy.$db;
  556. return new db_ref_1.DBRef(object.$ref, object.$id, object.$db, copy);
  557. }
  558. return object;
  559. }
  560. /**
  561. * Ensure eval is isolated, store the result in functionCache.
  562. *
  563. * @internal
  564. */
  565. function isolateEval(functionString, functionCache, object) {
  566. if (!functionCache)
  567. return new Function(functionString);
  568. // Check for cache hit, eval if missing and return cached function
  569. if (functionCache[functionString] == null) {
  570. functionCache[functionString] = new Function(functionString);
  571. }
  572. // Set the object
  573. return functionCache[functionString].bind(object);
  574. }
  575. //# sourceMappingURL=deserializer.js.map