function pointerAlreadyInPath(pointer, basePath, parent, specmap) {
  let refs = specmapRefs.get(specmap);
  if (!refs) {
    // Stores all resolved references of a specmap instance.
    // Schema: path -> pointer (path's $ref value).
    refs = {};
    specmapRefs.set(specmap, refs);
  }

  const parentPointer = arrayToJsonPointer(parent);
  const fullyQualifiedPointer = `${basePath || '<specmap-base>'}#${pointer}`;

  // dirty hack to strip `allof/[index]` from the path, in order to avoid cases
  // where we get false negatives because:
  // - we resolve a path, then
  // - allOf plugin collapsed `allOf/[index]` out of the path, then
  // - we try to work on a child $ref within that collapsed path.
  //
  // because of the path collapse, we lose track of it in our specmapRefs hash
  // solution: always throw the allOf constructs out of paths we store
  // TODO: solve this with a global register, or by writing more metadata in
  // either allOf or refs plugin
  const safeParentPointer = parentPointer.replace(/allOf\/\d+\/?/g, '');

  // Case 1: direct cycle, e.g. a.b.c.$ref: '/a.b'
  // Detect by checking that the parent path doesn't start with pointer.
  // This only applies if the pointer is internal, i.e. basePath === rootPath (could be null)
  const rootDoc = specmap.contextTree.get([]).baseDoc;
  if (basePath === rootDoc && pointerIsAParent(safeParentPointer, pointer)) {
    // eslint-disable-line
    return true;
  }

  // Case 2: indirect cycle
  //  ex1: a.$ref: '/b'  &  b.c.$ref: '/b/c'
  //  ex2: a.$ref: '/b/c'  &  b.c.$ref: '/b'
  // Detect by retrieving all the $refs along the path of parent
  // and checking if any starts with pointer or vice versa.
  let currPath = '';
  const hasIndirectCycle = parent.some((token) => {
    currPath = `${currPath}/${escapeJsonPointerToken(token)}`;
    return (
      refs[currPath] &&
      refs[currPath].some(
        (ref) =>
          pointerIsAParent(ref, fullyQualifiedPointer) ||
          pointerIsAParent(fullyQualifiedPointer, ref)
      )
    );
  });
  if (hasIndirectCycle) {
    return true;
  }

  // No cycle, this ref will be resolved, so stores it now for future detection.
  // No need to store if has cycle, as parent path is a dead-end and won't be checked again.

  refs[safeParentPointer] = (refs[safeParentPointer] || []).concat(fullyQualifiedPointer);

  return undefined;
}
Checks if this pointer points back to one or more pointers along the path.