interceptor.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // Warning: The concept of "interceptors" in Alpine is not public API and is subject to change
  2. // without tagging a major release.
  3. export function initInterceptors(data) {
  4. let isObject = val => typeof val === 'object' && !Array.isArray(val) && val !== null
  5. let recurse = (obj, basePath = '') => {
  6. Object.entries(Object.getOwnPropertyDescriptors(obj)).forEach(([key, { value, enumerable }]) => {
  7. // Skip getters.
  8. if (enumerable === false || value === undefined) return
  9. let path = basePath === '' ? key : `${basePath}.${key}`
  10. if (typeof value === 'object' && value !== null && value._x_interceptor) {
  11. obj[key] = value.initialize(data, path, key)
  12. } else {
  13. if (isObject(value) && value !== obj && ! (value instanceof Element)) {
  14. recurse(value, path)
  15. }
  16. }
  17. })
  18. }
  19. return recurse(data)
  20. }
  21. export function interceptor(callback, mutateObj = () => {}) {
  22. let obj = {
  23. initialValue: undefined,
  24. _x_interceptor: true,
  25. initialize(data, path, key) {
  26. return callback(this.initialValue, () => get(data, path), (value) => set(data, path, value), path, key)
  27. }
  28. }
  29. mutateObj(obj)
  30. return initialValue => {
  31. if (typeof initialValue === 'object' && initialValue !== null && initialValue._x_interceptor) {
  32. // Support nesting interceptors.
  33. let initialize = obj.initialize.bind(obj)
  34. obj.initialize = (data, path, key) => {
  35. let innerValue = initialValue.initialize(data, path, key)
  36. obj.initialValue = innerValue
  37. return initialize(data, path, key)
  38. }
  39. } else {
  40. obj.initialValue = initialValue
  41. }
  42. return obj
  43. }
  44. }
  45. function get(obj, path) {
  46. return path.split('.').reduce((carry, segment) => carry[segment], obj)
  47. }
  48. function set(obj, path, value) {
  49. if (typeof path === 'string') path = path.split('.')
  50. if (path.length === 1) obj[path[0]] = value;
  51. else if (path.length === 0) throw error;
  52. else {
  53. if (obj[path[0]])
  54. return set(obj[path[0]], path.slice(1), value);
  55. else {
  56. obj[path[0]] = {};
  57. return set(obj[path[0]], path.slice(1), value);
  58. }
  59. }
  60. }