function inspectGlobals(
  source,
  {
    ignoredRefs = [],
    globalRefs = [],
    globalPropertyNames = defaultGlobalPropertyNames,
    languageRefs = defaultLanguageRefs,
  } = {}
) {
  const ast = typeof source === 'object' ? source : parse(source)
  const detectedGlobals = findGlobals(ast)

  const globalsConfig = new Map()
  // check for global refs with member expressions
  ;[...detectedGlobals.entries()].forEach(([name, paths]) =>
    inspectDetectedGlobalVariables(name, paths)
  )
  // reduce to remove more deep results that overlap with broader results
  // e.g. [`x.y.z`, `x.y`] can be reduced to just [`x.y`]
  reduceToTopmostApiCalls(globalsConfig)

  return globalsConfig

  /**
   * @param {string} name
   * @param {import('./findGlobals').IdentifierOrThisExpressionNodePath[]} paths
   */
  function inspectDetectedGlobalVariables(name, paths) {
    // skip if module global
    if (ignoredRefs.includes(name)) {
      return
    }
    // expose API as granularly as possible
    paths.forEach((path) => {
      const parents = getParents(path)
      const {
        path: keyPath,
        identifierUse,
        parent,
      } = inspectIdentifierForDirectMembershipChain(
        name,
        path.node,
        /** @type {import('./inspectPrimordialAssignments').MemberLikeExpression[]} */ (
          parents
        )
      )
      // if nested API lookup begins with a globalRef, drop it
      if (globalRefs.includes(keyPath[0])) {
        keyPath.shift()
      }
      // inspect for destructuring
      let destructuredPaths
      if (
        parent.type === 'VariableDeclarator' &&
        ['ObjectPattern', 'ArrayPattern'].includes(parent.id.type)
      ) {
        destructuredPaths = inspectPatternElementForKeys(parent.id).map(
          (partial) => [...keyPath, ...partial]
        )
      } else {
        destructuredPaths = [keyPath]
      }

      destructuredPaths.forEach((path) => {
        // skip if global and only used for detecting presence
        if (path.length === 0) {
          return
        }
        // submit as a global usage
        const pathString = path.join('.')
        maybeAddGlobalUsage(pathString, identifierUse)
      })
    })
  }

  /**
   * @param {string} variableName
   * @param {import('@babel/types').Identifier
   *   | import('@babel/types').ThisExpression} identifierNode
   * @param {import('./inspectPrimordialAssignments').MemberLikeExpression[]} parents
   * @returns
   */
  function inspectIdentifierForDirectMembershipChain(
    variableName,
    identifierNode,
    parents
  ) {
    /** @type {import('../../core/src/schema').GlobalPolicyValue} */
    let identifierUse = 'read'
    const { memberExpressions, parentOfMembershipChain, topmostMember } =
      getMemberExpressionNesting(identifierNode, parents)
    // determine if used in an assignment expression
    // @ts-ignore - FIXME needs logic changes for type safety
    const isAssignment = parentOfMembershipChain.type === 'AssignmentExpression'
    // @ts-ignore - FIXME needs logic changes for type safety
    const isAssignmentTarget = parentOfMembershipChain.left === topmostMember
    if (isAssignment && isAssignmentTarget) {
      // this membership chain is being assigned to
      identifierUse = 'write'
    }
    // if not used in any member expressions AND is not a global ref, expose as is
    if (!memberExpressions.length) {
      return {
        identifierUse,
        path: [variableName],
        parent: parentOfMembershipChain,
      }
    }
    const path = [
      variableName,
      ...getPathFromMemberExpressionChain(memberExpressions),
    ]
    return { identifierUse, path, parent: parentOfMembershipChain }
  }

  /**
   * @param {string} identifierPath
   * @param {import('../../core/src/schema').GlobalPolicyValue} identifierUse
   * @returns
   */
  function maybeAddGlobalUsage(identifierPath, identifierUse) {
    const topmostRef = identifierPath.split('.')[0]
    // skip intrinsics and other language features
    if (globalPropertyNames.includes(topmostRef)) {
      return
    }
    if (languageRefs.includes(topmostRef)) {
      return
    }
    // skip ignored globals
    if (ignoredRefs.includes(topmostRef)) {
      return
    }
    addGlobalUsage(globalsConfig, identifierPath, identifierUse)
  }
}
@param {import('../../core/src/generatePolicy').AST | string} source
@param {InspectGlobalsOpts} options
@returns