index.mjs 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. const suspectProtoRx = /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/;
  2. const suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
  3. const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;
  4. function jsonParseTransform(key, value) {
  5. if (key === "__proto__" || key === "constructor" && value && typeof value === "object" && "prototype" in value) {
  6. warnKeyDropped(key);
  7. return;
  8. }
  9. return value;
  10. }
  11. function warnKeyDropped(key) {
  12. console.warn(`[destr] Dropping "${key}" key to prevent prototype pollution.`);
  13. }
  14. function destr(value, options = {}) {
  15. if (typeof value !== "string") {
  16. return value;
  17. }
  18. if (value[0] === '"' && value[value.length - 1] === '"' && value.indexOf("\\") === -1) {
  19. return value.slice(1, -1);
  20. }
  21. const _value = value.trim();
  22. if (_value.length <= 9) {
  23. switch (_value.toLowerCase()) {
  24. case "true": {
  25. return true;
  26. }
  27. case "false": {
  28. return false;
  29. }
  30. case "undefined": {
  31. return void 0;
  32. }
  33. case "null": {
  34. return null;
  35. }
  36. case "nan": {
  37. return Number.NaN;
  38. }
  39. case "infinity": {
  40. return Number.POSITIVE_INFINITY;
  41. }
  42. case "-infinity": {
  43. return Number.NEGATIVE_INFINITY;
  44. }
  45. }
  46. }
  47. if (!JsonSigRx.test(value)) {
  48. if (options.strict) {
  49. throw new SyntaxError("[destr] Invalid JSON");
  50. }
  51. return value;
  52. }
  53. try {
  54. if (suspectProtoRx.test(value) || suspectConstructorRx.test(value)) {
  55. if (options.strict) {
  56. throw new Error("[destr] Possible prototype pollution");
  57. }
  58. return JSON.parse(value, jsonParseTransform);
  59. }
  60. return JSON.parse(value);
  61. } catch (error) {
  62. if (options.strict) {
  63. throw error;
  64. }
  65. return value;
  66. }
  67. }
  68. function safeDestr(value, options = {}) {
  69. return destr(value, { ...options, strict: true });
  70. }
  71. export { destr as default, destr, safeDestr };