is-serializable-props.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.isSerializableProps = isSerializableProps;
  6. var _isPlainObject = require("../shared/lib/is-plain-object");
  7. const regexpPlainIdentifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
  8. class SerializableError extends Error {
  9. constructor(page, method, path, message){
  10. super(path ? `Error serializing \`${path}\` returned from \`${method}\` in "${page}".\nReason: ${message}` : `Error serializing props returned from \`${method}\` in "${page}".\nReason: ${message}`);
  11. }
  12. }
  13. exports.SerializableError = SerializableError;
  14. function isSerializableProps(page, method, input) {
  15. if (!(0, _isPlainObject).isPlainObject(input)) {
  16. throw new SerializableError(page, method, "", `Props must be returned as a plain object from ${method}: \`{ props: { ... } }\` (received: \`${(0, _isPlainObject).getObjectClassLabel(input)}\`).`);
  17. }
  18. function visit(visited, value, path) {
  19. if (visited.has(value)) {
  20. throw new SerializableError(page, method, path, `Circular references cannot be expressed in JSON (references: \`${visited.get(value) || "(self)"}\`).`);
  21. }
  22. visited.set(value, path);
  23. }
  24. function isSerializable(refs, value, path) {
  25. const type = typeof value;
  26. if (// `null` can be serialized, but not `undefined`.
  27. value === null || // n.b. `bigint`, `function`, `symbol`, and `undefined` cannot be
  28. // serialized.
  29. //
  30. // `object` is special-cased below, as it may represent `null`, an Array,
  31. // a plain object, a class, et al.
  32. type === "boolean" || type === "number" || type === "string") {
  33. return true;
  34. }
  35. if (type === "undefined") {
  36. throw new SerializableError(page, method, path, "`undefined` cannot be serialized as JSON. Please use `null` or omit this value.");
  37. }
  38. if ((0, _isPlainObject).isPlainObject(value)) {
  39. visit(refs, value, path);
  40. if (Object.entries(value).every(([key, nestedValue])=>{
  41. const nextPath = regexpPlainIdentifier.test(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`;
  42. const newRefs = new Map(refs);
  43. return isSerializable(newRefs, key, nextPath) && isSerializable(newRefs, nestedValue, nextPath);
  44. })) {
  45. return true;
  46. }
  47. throw new SerializableError(page, method, path, `invariant: Unknown error encountered in Object.`);
  48. }
  49. if (Array.isArray(value)) {
  50. visit(refs, value, path);
  51. if (value.every((nestedValue, index)=>{
  52. const newRefs = new Map(refs);
  53. return isSerializable(newRefs, nestedValue, `${path}[${index}]`);
  54. })) {
  55. return true;
  56. }
  57. throw new SerializableError(page, method, path, `invariant: Unknown error encountered in Array.`);
  58. }
  59. // None of these can be expressed as JSON:
  60. // const type: "bigint" | "symbol" | "object" | "function"
  61. throw new SerializableError(page, method, path, "`" + type + "`" + (type === "object" ? ` ("${Object.prototype.toString.call(value)}")` : "") + " cannot be serialized as JSON. Please only return JSON serializable data types.");
  62. }
  63. return isSerializable(new Map(), input, "");
  64. }
  65. //# sourceMappingURL=is-serializable-props.js.map