function expandTokens(tokenMap, opts, platform) {
  const uses$ = opts.usesDtcg;
  // create a copy in which we will do mutations
  const copy = structuredClone(tokenMap);
  // create another copy which has resolved refs
  const copyResolved = structuredClone(tokenMap);
  try {
    // @ts-expect-error in this instance it is acceptable to pass DesignTokens before transform step
    resolveMap(copyResolved, { usesDtcg: uses$, objectsOnly: true });
  } catch (_e) {
    console.error(_e);
    // do nothing, references may be broken but now is not the time to
    // complain about it, as we're just doing this here so we can expand
    // tokens that reference object-value tokens that need to be expanded
  }

  Array.from(copyResolved).forEach(([, token]) => {
    let value = uses$ ? token.$value : token.value;
    if (
      isPlainObject(value) ||
      // support multi-value arrays where each item is an object, e.g. shadow tokens
      (Array.isArray(value) && value.every((sub) => isPlainObject(sub)))
    ) {
      if (shouldExpand(token, opts, platform)) {
        expandTokenInMap(token, copy, opts, platform);
      }
    }
  });

  return copy;
}
@param {Map<string, DesignToken>} tokenMap
@param {Config} opts
@param {PlatformConfig} [platform]