All files / packages/sds-subsystems/.storybook/addons/theme-builder/src/utilities helpers.js

0% Statements 0/44
0% Branches 0/30
0% Functions 0/7
0% Lines 0/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                                                                                                                                                                                                                                                     
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license
 
// SHIM Lodash because it caches in node_modules and generates id's that are always incrementing
const uniqueId = (() => {
  const PREFIXES = {};
  let idCounter = 0;
  const newCounter = (prefix) => {
    PREFIXES[prefix] = 0;
  };
  const incCounter = (prefix) => {
    PREFIXES[prefix] = PREFIXES[prefix] + 1;
    return PREFIXES[prefix];
  };
  const initCounterForPrefix = (prefix) => (PREFIXES[prefix] != null ? PREFIXES[prefix] : newCounter(prefix));
  const addToPrefix = (prefix) => {
    initCounterForPrefix(prefix);
    return prefix + incCounter(prefix);
  };
  return (prefix) => (prefix ? addToPrefix(prefix) : idCounter++);
})();
 
const debounce = (func, delay) => {
  let timeoutId; // This will hold the ID of the timeout
 
  return (...args) => {
    // Returns a new function (the debounced version)
    const context = this; // Preserve the 'this' context
 
    clearTimeout(timeoutId); // Clear any existing timer
 
    timeoutId = setTimeout(() => {
      // Set a new timer
      func.apply(context, args); // Execute the original function after the delay
    }, delay);
  };
};
 
/**
 * Computes the difference between two objects
 * Returns only properties that have changed from the baseline object
 * @param {Object} current - The current object to compare
 * @param {Object} baseline - The baseline object to compare against
 * @returns {Object} Object containing only the changed properties
 */
const objectDiff = (current, baseline) => {
  // If current is null/undefined, return empty object
  if (current === null || current === undefined) {
    return {};
  }
 
  // If no baseline provided, return current (all properties are considered changed)
  if (baseline === null || baseline === undefined) {
    return current;
  }
 
  const diff = {};
 
  // Iterate through all keys in the current object
  for (const key in current) {
    // Only process own properties (not from prototype chain)
    if (!Object.prototype.hasOwnProperty.call(current, key)) {
      continue;
    }
 
    const currentValue = current[key];
    const baselineValue = baseline[key];
 
    // If baseline doesn't have this key, it's a new property
    if (!Object.prototype.hasOwnProperty.call(baseline, key)) {
      diff[key] = currentValue;
      continue;
    }
 
    // Handle arrays - compare by value
    if (Array.isArray(currentValue)) {
      try {
        if (!Array.isArray(baselineValue) || JSON.stringify(currentValue) !== JSON.stringify(baselineValue)) {
          diff[key] = currentValue;
        }
      } catch (error) {
        // If JSON.stringify fails (e.g., circular reference), treat as different
        diff[key] = currentValue;
      }
      continue;
    }
 
    // Handle null values
    if (currentValue === null || baselineValue === null) {
      if (currentValue !== baselineValue) {
        diff[key] = currentValue;
      }
      continue;
    }
 
    // Compare primitive values (string, number, boolean, etc.)
    if (typeof currentValue !== 'object') {
      if (currentValue !== baselineValue) {
        diff[key] = currentValue;
      }
      continue;
    }
 
    // Recursively compare nested objects
    const nestedDiff = objectDiff(currentValue, baselineValue);
    // Only include if there are actual differences
    if (Object.keys(nestedDiff).length > 0) {
      diff[key] = nestedDiff;
    }
  }
 
  return diff;
};
 
export default {
  uniqueId,
  debounce,
  objectDiff,
};
 
// Named exports for easier importing
export { uniqueId, debounce, objectDiff };