{"version":3,"sources":["/Users/erunion/code/readme/oas/packages/oas/dist/analyzer/index.cjs","../../src/analyzer/dereference.ts","../../src/analyzer/query-cache.ts","../../src/analyzer/scope.ts","../../src/analyzer/queries/openapi.ts","../../src/analyzer/index.ts"],"names":["webhooks","query","additionalProperties","callbacks","commonParameters","discriminators","links","parameterSerialization","polymorphism","references","serverVariables","xmlRequests","xmlResponses","xmlSchemas"],"mappings":"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","file":"/Users/erunion/code/readme/oas/packages/oas/dist/analyzer/index.cjs","sourcesContent":[null,"import type { OASDocument } from '../types.js';\nimport type { ParserOptions } from '@readme/openapi-parser';\n\nimport { dereference } from '@readme/openapi-parser';\n\n/**\n * Retrive our dereferencing configuration for `@readme/openapi-parser`.\n *\n */\nfunction getDereferencingOptions(circularRefs: Set<string>): Pick<ParserOptions, 'resolve' | 'dereference'> {\n  return {\n    resolve: {\n      // We shouldn't be resolving external pointers at this point so just ignore them.\n      external: false,\n    },\n    dereference: {\n      // If circular `$refs` are ignored they'll remain in the schema as `$ref: String`, otherwise\n      // `$ref` just won't exist. This, in tandem with `onCircular`, allows us to do easy and\n      // accumulate a list of circular references.\n      circular: 'ignore',\n\n      onCircular: (path: string) => {\n        // The circular references that are coming out of `json-schema-ref-parser` are prefixed\n        // with the schema path (file path, URL, whatever) that the schema exists in. Because we\n        // don't care about this information for this reporting mechanism, and only the `$ref`\n        // pointer, we're removing it.\n        circularRefs.add(`#${path.split('#')[1]}`);\n      },\n    },\n  };\n}\n\ninterface DereferenceOasResult {\n  api: OASDocument;\n  circularRefs: string[];\n}\n\ninterface DereferenceOasState {\n  circularRefs: string[];\n  complete: boolean;\n  processing: boolean;\n  promises: {\n    reject: (err: unknown) => void;\n    resolve: (result: DereferenceOasResult) => void;\n  }[];\n  result?: DereferenceOasResult;\n}\n\nconst dereferenceStates = new WeakMap<OASDocument, DereferenceOasState>();\n\nfunction getDereferenceState(definition: OASDocument): DereferenceOasState {\n  let state = dereferenceStates.get(definition);\n  if (!state) {\n    state = {\n      processing: false,\n      complete: false,\n      circularRefs: [],\n      promises: [],\n    };\n    dereferenceStates.set(definition, state);\n  }\n\n  return state;\n}\n\n/**\n * Dereference a given OpenAPI definition so it can be parsed free from the hassle of resolving\n * `$ref` schemas and circular structures.\n *\n */\nexport async function dereferenceOas(\n  definition: OASDocument,\n  opts?: {\n    /**\n     * A callback method can be supplied to be called when dereferencing is complete. Used for\n     * debugging that the multi-promise handling within this method works.\n     *\n     * @private\n     */\n    cb?: () => void;\n  },\n): Promise<DereferenceOasResult> {\n  const state = getDereferenceState(definition);\n\n  if (state.complete && state.result) {\n    return state.result;\n  }\n\n  if (state.processing) {\n    return new Promise((resolve, reject) => {\n      state.promises.push({ resolve, reject });\n    });\n  }\n\n  state.processing = true;\n\n  const circularRefs: Set<string> = new Set();\n  const dereferencingOptions = getDereferencingOptions(circularRefs);\n  const { promises } = state;\n\n  return dereference<OASDocument>(definition, dereferencingOptions)\n    .then((dereferenced: OASDocument) => {\n      const result: DereferenceOasResult = {\n        api: dereferenced,\n        circularRefs: [...circularRefs],\n      };\n\n      state.result = result;\n      state.circularRefs = result.circularRefs;\n      state.processing = false;\n      state.complete = true;\n\n      // Used for debugging that dereferencing promise awaiting works.\n      if (opts?.cb) {\n        opts.cb();\n      }\n\n      return result;\n    })\n    .then(result => {\n      promises.forEach(deferred => deferred.resolve(result));\n      state.promises = [];\n      return result;\n    })\n    .catch(err => {\n      state.processing = false;\n      promises.forEach(deferred => deferred.reject(err));\n      state.promises = [];\n      throw err;\n    });\n}\n\n/**\n * `dereferenceOas()` caches its result against whatever object reference it's given, but callers\n * that care about not mutating their original definition (like the analyzer) have historically had\n * to pass in a fresh `structuredClone()` on every call — which means that cache is only ever a hit\n * within a single call, never across separate analyses of the same definition.\n *\n * This wraps that up: it clones the given definition exactly once and reuses that same clone (and\n * therefore `dereferenceOas()`'s cached result for it) for every subsequent call with the same\n * original definition reference. This is what lets the analyzer dereference a large API definition\n * a single time and reuse that work across an analysis of every operation within it, instead of\n * re-dereferencing the whole thing per-operation.\n *\n * @param definition An OpenAPI definition to dereference.\n */\nexport function dereferenceOasShared(definition: OASDocument): Promise<DereferenceOasResult> {\n  let clone = sharedClones.get(definition);\n  if (!clone) {\n    clone = structuredClone(definition);\n    sharedClones.set(definition, clone);\n  }\n\n  return dereferenceOas(clone);\n}\n\nconst sharedClones = new WeakMap<OASDocument, OASDocument>();\n","import type { JSONPathResult } from './util.js';\n\nimport { query } from './util.js';\n\nconst cache = new WeakMap<object, Map<string, JSONPathResult[]>>();\n\n/**\n * Every analyzer query in `queries/openapi.ts` runs one or more `$..`-style JSONPath scans across\n * the *entire* API definition, regardless of which operation (if any) we're ultimately interested\n * in. When analyzing a single operation that's cheap to do once, but when analyzing hundreds of\n * operations out of the same definition — which is the whole point of being able to scope analysis\n * to an operation instead of reducing the definition down first — re-running those same full-document\n * scans for every single operation throws away all of that shared work.\n *\n * This cache runs each unique set of JSONPath queries against a given definition exactly once and\n * hands back the same result array on every subsequent call, so callers can cheaply filter it down\n * per-operation instead of re-scanning the whole document each time.\n *\n * Cache entries are keyed by object identity (via `WeakMap`), so this is only effective when\n * callers reuse the same `definition` reference across calls — if you're handed a fresh clone every\n * time there's nothing to reuse. It also means definitions are never manually evicted from the\n * cache; they simply fall out of it once nothing else references them.\n *\n * @param queries JSONPath queries to run.\n * @param definition The object to run them against.\n */\nexport function queryCached(queries: string[], definition: object): JSONPathResult[] {\n  let byQuery = cache.get(definition);\n  if (!byQuery) {\n    byQuery = new Map();\n    cache.set(definition, byQuery);\n  }\n\n  // A space can't appear within a JSONPath query, so it's a safe delimiter to join on for a cache key.\n  const cacheKey = queries.join(' ');\n\n  let results = byQuery.get(cacheKey);\n  if (!results) {\n    results = query(queries, definition);\n    byQuery.set(cacheKey, results);\n  }\n\n  return results;\n}\n","import type { OAS31Document, OASDocument } from '../types.js';\n\nimport jsonPointer from 'jsonpointer';\n\nimport { collectRefsInSchema, encodePointer, toPointer } from '../lib/refs.js';\nimport { supportedMethods } from '../utils.js';\n\n/**\n * The set of JSON pointers (in plain `/foo/bar` form, without the leading `#`) that describe\n * everything an operation or webhook touches: itself, any path-level (or webhook-level) common\n * parameters, and every `$ref` pointer that's reachable from either of those.\n *\n * This is what allows the analyzer to be run against a full, undreduced API definition and still\n * only report on what a single operation actually uses.\n */\nexport interface OperationScope {\n  /**\n   * `anchors`, each with a trailing `/` appended, precomputed once so `isPointerInScope()` isn't\n   * concatenating a new string per anchor on every single pointer it checks. Analyzing an\n   * operation can mean checking thousands of result pointers against this list, so avoiding a\n   * string allocation per comparison meaningfully adds up.\n   */\n  anchorPrefixes: string[];\n\n  /**\n   * A flattened, precomputed list of every pointer prefix that's considered \"in scope\". This is\n   * derived from `rootPointer`, `extraPointers`, and `reachableRefs` and exists purely so we don't\n   * have to rebuild it for every pointer comparison we do.\n   */\n  anchors: string[];\n\n  /**\n   * Pointers, beyond `rootPointer`, that should be treated as belonging to this operation (e.g. a\n   * path item's common `parameters`).\n   */\n  extraPointers: string[];\n\n  /**\n   * Every `$ref` pointer (in `#/...` form) that's transitively reachable from this operation.\n   */\n  reachableRefs: Set<string>;\n\n  /**\n   * The pointer to the operation (or webhook operation) itself, e.g. `/paths/~1pet/get` or\n   * `/webhooks/newBooking/post`.\n   */\n  rootPointer: string;\n}\n\n/**\n * Case-insensitively find the real key for a given target within a list of keys. OpenAPI paths and\n * HTTP methods aren't case-sensitive as far as most tooling (including this) is concerned, but the\n * pointers we build need to match the casing that's actually in the document.\n *\n */\nfunction resolveKey(keys: string[], target: string): string | undefined {\n  return keys.find(key => key === target) || keys.find(key => key.toLowerCase() === target.toLowerCase());\n}\n\n/**\n * Starting from a seed set of `$ref` pointers, recursively follow every `$ref` that they, or\n * anything they point to, contain and return the full set of pointers that are reachable.\n *\n * This intentionally mirrors the ref-walking that `OpenAPIReducer` does, but is read-only (no\n * cloning, no mutation) and resolves each `$ref` lazily against the original definition instead of\n * requiring a prebuilt map of every possible reference.\n *\n */\nfunction accumulateReachableRefs(definition: OASDocument, seeds: Iterable<string>): Set<string> {\n  const reachable = new Set<string>();\n  const queue = [...seeds];\n\n  while (queue.length) {\n    const ref = queue.shift() as string;\n    if (reachable.has(ref)) {\n      continue;\n    }\n\n    reachable.add(ref);\n\n    let resolved: unknown;\n    try {\n      resolved = jsonPointer.get(definition, toPointer(ref));\n    } catch {\n      // If the `$ref` doesn't resolve to anything (a malformed pointer, an external ref we didn't\n      // bundle, etc.) there's nothing further to walk from it.\n      continue;\n    }\n\n    if (resolved === undefined) {\n      continue;\n    }\n\n    collectRefsInSchema(resolved).forEach(nestedRef => {\n      if (!reachable.has(nestedRef)) {\n        queue.push(nestedRef);\n      }\n    });\n  }\n\n  return reachable;\n}\n\nfunction buildAnchors(\n  rootPointer: string,\n  extraPointers: string[],\n  reachableRefs: Set<string>,\n): Pick<OperationScope, 'anchorPrefixes' | 'anchors'> {\n  const anchors = [rootPointer, ...extraPointers];\n  reachableRefs.forEach(ref => anchors.push(toPointer(ref)));\n\n  return { anchors, anchorPrefixes: anchors.map(anchor => `${anchor}/`) };\n}\n\n/**\n * Accumulate the `#/components/securitySchemes/*` refs that a given set of security requirements\n * make use of.\n *\n */\nfunction collectSecuritySchemeRefs(security: unknown): string[] {\n  if (!Array.isArray(security)) {\n    return [];\n  }\n\n  const refs: string[] = [];\n  security.forEach(requirement => {\n    if (requirement && typeof requirement === 'object') {\n      Object.keys(requirement).forEach(scheme => {\n        refs.push(`#/components/securitySchemes/${scheme}`);\n      });\n    }\n  });\n\n  return refs;\n}\n\n/**\n * Compute the `OperationScope` for a single operation within an API definition, so that the\n * analyzer can report only on what that operation (and anything it references) actually uses,\n * without requiring the definition to be reduced down first.\n *\n */\nexport function computeOperationScope(definition: OASDocument, path: string, method: string): OperationScope {\n  const pathKey = resolveKey(Object.keys(definition.paths || {}), path);\n  if (!pathKey) {\n    throw new Error(`Path \\`${path}\\` not found.`);\n  }\n\n  const pathItem = (definition.paths as Record<string, any>)[pathKey] || {};\n  const methodKey = resolveKey(Object.keys(pathItem), method);\n  if (!methodKey || !supportedMethods.includes(methodKey.toLowerCase() as (typeof supportedMethods)[number])) {\n    throw new Error(`Operation \\`${method} ${path}\\` not found.`);\n  }\n\n  const operation = pathItem[methodKey];\n  const rootPointer = `/paths/${encodePointer(pathKey)}/${methodKey}`;\n  const extraPointers: string[] = [];\n  const seeds = new Set<string>(collectRefsInSchema(operation));\n\n  if (pathItem.parameters) {\n    extraPointers.push(`/paths/${encodePointer(pathKey)}/parameters`);\n    collectRefsInSchema(pathItem.parameters).forEach(ref => seeds.add(ref));\n  }\n\n  const security = 'security' in operation ? operation.security : definition.security;\n  collectSecuritySchemeRefs(security).forEach(ref => seeds.add(ref));\n\n  const reachableRefs = accumulateReachableRefs(definition, seeds);\n\n  return { rootPointer, extraPointers, reachableRefs, ...buildAnchors(rootPointer, extraPointers, reachableRefs) };\n}\n\n/**\n * Compute the `OperationScope` for a single webhook operation within an OpenAPI 3.1 definition.\n *\n */\nexport function computeWebhookScope(definition: OAS31Document, webhookName: string, method: string): OperationScope {\n  const webhooks = ('webhooks' in definition ? definition.webhooks : {}) as NonNullable<OAS31Document['webhooks']>;\n  const webhookKey = resolveKey(Object.keys(webhooks || {}), webhookName);\n  if (!webhookKey) {\n    throw new Error(`Webhook \\`${webhookName}\\` not found.`);\n  }\n\n  const webhook = (webhooks as Record<string, any>)[webhookKey] || {};\n  const methodKey = resolveKey(Object.keys(webhook), method);\n  if (!methodKey || !supportedMethods.includes(methodKey.toLowerCase() as (typeof supportedMethods)[number])) {\n    throw new Error(`Webhook operation \\`${method} ${webhookName}\\` not found.`);\n  }\n\n  const operation = webhook[methodKey];\n  const rootPointer = `/webhooks/${encodePointer(webhookKey)}/${methodKey}`;\n  const extraPointers: string[] = [];\n  const seeds = new Set<string>(collectRefsInSchema(operation));\n\n  if (webhook.parameters) {\n    extraPointers.push(`/webhooks/${encodePointer(webhookKey)}/parameters`);\n    collectRefsInSchema(webhook.parameters).forEach(ref => seeds.add(ref));\n  }\n\n  const security = 'security' in operation ? operation.security : definition.security;\n  collectSecuritySchemeRefs(security).forEach(ref => seeds.add(ref));\n\n  const reachableRefs = accumulateReachableRefs(definition, seeds);\n\n  return { rootPointer, extraPointers, reachableRefs, ...buildAnchors(rootPointer, extraPointers, reachableRefs) };\n}\n\n/**\n * Determine if a given JSON pointer (as returned by `jsonpath-plus`, without a leading `#`) falls\n * within a given `OperationScope`.\n *\n */\nexport function isPointerInScope(pointer: string, scope: OperationScope): boolean {\n  const { anchors, anchorPrefixes } = scope;\n  for (let i = 0; i < anchors.length; i += 1) {\n    if (pointer === anchors[i] || pointer.startsWith(anchorPrefixes[i])) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\n/**\n * Determine if a given `OperationScope`'s root is nested *within* a given pointer. This is the\n * inverse of `isPointerInScope()` and exists for the handful of queries (like our `webhooks` one)\n * that report on a coarser pointer than the specific operation we're scoped to, e.g. reporting on\n * `/webhooks/newBooking` as a whole when we're scoped to `/webhooks/newBooking/post`.\n *\n */\nexport function isAncestorOfScope(pointer: string, scope: OperationScope): boolean {\n  return scope.rootPointer === pointer || scope.rootPointer.startsWith(`${pointer}/`);\n}\n","import type { OASDocument } from '../../types.js';\nimport type { OperationScope } from '../scope.js';\nimport type { JSONPathResult } from '../util.js';\n\nimport { toPointer } from '../../lib/refs.js';\nimport { dereferenceOas } from '../dereference.js';\nimport { queryCached } from '../query-cache.js';\nimport { isAncestorOfScope, isPointerInScope } from '../scope.js';\nimport { refizePointer } from '../util.js';\n\n/**\n * Narrow a set of JSONPath results down to only the ones that fall within a given operation's\n * scope. When no scope is supplied every result is considered in scope, which preserves the\n * whole-document behavior these queries have always had.\n *\n */\nfunction filterByScope(results: JSONPathResult[], scope?: OperationScope): JSONPathResult[] {\n  if (!scope) {\n    return results;\n  }\n\n  return results.filter(res => isPointerInScope(res.pointer, scope));\n}\n\n/**\n * Determine if a given API definition uses the `additionalProperties` schema property.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#schema-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object}\n */\nexport function additionalProperties(definition: OASDocument, scope?: OperationScope): string[] {\n  return filterByScope(queryCached(['$..additionalProperties'], definition), scope).map(res =>\n    refizePointer(res.pointer),\n  );\n}\n\n/**\n * Determine if a given API definition utilizes `callbacks`.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#callback-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#callback-object}\n */\nexport function callbacks(definition: OASDocument, scope?: OperationScope): string[] {\n  return filterByScope(\n    queryCached(['$.components.callbacks', '$.paths.*[?(@.callbacks)].callbacks'], definition),\n    scope,\n  ).map(res => refizePointer(res.pointer));\n}\n\n/**\n * Determine if a given API definition has circular refs.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#schema-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object}\n */\nexport async function circularRefs(definition: OASDocument, scope?: OperationScope): Promise<string[]> {\n  // Dereferencing will update the passed in variable, which we don't want to do, so we\n  // instantiated `Oas` with a clone.\n  const { circularRefs: refs } = await dereferenceOas(structuredClone(definition));\n\n  const results = scope ? refs.filter(ref => isPointerInScope(toPointer(ref), scope)) : [...refs];\n  results.sort();\n  return results;\n}\n\n/**\n * Determine if a given API definition utilizes common parameters.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#path-item-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#path-item-object}\n */\nexport function commonParameters(definition: OASDocument, scope?: OperationScope): string[] {\n  return filterByScope(queryCached(['$..paths[*].parameters'], definition), scope).map(res =>\n    refizePointer(res.pointer),\n  );\n}\n\n/**\n * Determine if a given API definition utilizes discriminators.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#discriminator-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#discriminator-object}\n */\nexport function discriminators(definition: OASDocument, scope?: OperationScope): string[] {\n  return filterByScope(queryCached(['$..discriminator'], definition), scope).map(res => refizePointer(res.pointer));\n}\n\n/**\n * Determine if a given API definition utilizes `links`.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#link-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#link-object}\n */\nexport function links(definition: OASDocument, scope?: OperationScope): string[] {\n  return filterByScope(queryCached(['$.components.links', '$.paths..responses.*.links'], definition), scope).map(res =>\n    refizePointer(res.pointer),\n  );\n}\n\n/**\n * Determine all of the available media types used within an API definition.\n *\n * @todo This query currently picks up false positives if there is an object named `content`.\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#request-body-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#request-body-object}\n */\nexport function mediaTypes(definition: OASDocument, scope?: OperationScope): string[] {\n  const results = Array.from(\n    new Set(\n      filterByScope(\n        queryCached(\n          [\n            '$..paths..content',\n            '$.components.requestBodies..content',\n            '$.components.responses..content',\n            '$.webhooks..content',\n          ],\n          definition,\n        ),\n        scope,\n      ).flatMap(res => {\n        // This'll transform `results`, which looks like `[['application/json'], ['text/xml']]`\n        // into `['application/json', 'text/xml']`.\n        return Object.keys(res.value);\n      }),\n    ),\n  );\n\n  results.sort();\n  return results;\n}\n\n/**\n * Determine if a given API definition uses parameter serialization.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#parameter-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object}\n */\nexport function parameterSerialization(definition: OASDocument, scope?: OperationScope): string[] {\n  return filterByScope(queryCached(['$..parameters[*].style^'], definition), scope).map(res =>\n    refizePointer(res.pointer),\n  );\n}\n\n/**\n * Determine if a given API definition utilizes schema polymorphism and/of interitance.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#schema-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object}\n */\nexport function polymorphism(definition: OASDocument, scope?: OperationScope): string[] {\n  const results = Array.from(\n    new Set(\n      filterByScope(queryCached(['$..allOf^', '$..anyOf^', '$..oneOf^'], definition), scope).map(res =>\n        refizePointer(res.pointer),\n      ),\n    ),\n  );\n\n  results.sort();\n  return results;\n}\n\n/**\n * Determine if a given API definition utilizes `$ref` pointers.\n *\n */\nexport function references(definition: OASDocument, scope?: OperationScope): string[] {\n  return filterByScope(queryCached(['$..$ref^'], definition), scope).map(res => refizePointer(res.pointer));\n}\n\n/**\n * Determine every kind of security type that a given API definition has documented.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-scheme-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#security-scheme-object}\n */\nexport function securityTypes(definition: OASDocument, scope?: OperationScope): string[] {\n  return Array.from(\n    new Set(\n      filterByScope(queryCached(['$.components.securitySchemes..type'], definition), scope).map(\n        res => res.value as string,\n      ),\n    ),\n  );\n}\n\n/**\n * Determine if a given API definition utilizes server variables.\n *\n * Root-level `servers` apply to every operation unless a path or operation overrides them, so\n * these are always considered in scope regardless of which operation is being analyzed.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#server-variable-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#server-variable-object}\n */\nexport function serverVariables(definition: OASDocument): string[] {\n  return queryCached(['$.servers..variables^'], definition).map(res => refizePointer(res.pointer));\n}\n\n/**\n * Determine how many operations are defined in a given API definition.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#operation-object}\n */\nexport function totalOperations(definition: OASDocument): number {\n  return queryCached(['$..paths[*]'], definition).flatMap(res => Object.keys(res.value)).length;\n}\n\n/**\n * Determine if a given API definition utilizes `webhooks` support in OpenAPI 3.1.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#oasWebhooks}\n */\nexport function webhooks(definition: OASDocument, scope?: OperationScope): string[] {\n  const results = queryCached(['$.webhooks[*]'], definition);\n  if (!scope) {\n    return results.map(res => refizePointer(res.pointer));\n  }\n\n  // This query reports on an entire webhook (`/webhooks/newBooking`) rather than a specific\n  // method on it, so a scope's root pointer (`/webhooks/newBooking/post`) is a *descendant* of a\n  // matching result rather than the other way around. We still want to catch the normal case too,\n  // where an operation reaches into a webhook by way of a `$ref`.\n  return results\n    .filter(res => isPointerInScope(res.pointer, scope) || isAncestorOfScope(res.pointer, scope))\n    .map(res => refizePointer(res.pointer));\n}\n\n/**\n * Determine if a given API definition uses XML in a request body payload.\n *\n * @todo detect `+xml` media types\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object}\n */\nexport function xmlRequests(definition: OASDocument, scope?: OperationScope): string[] {\n  return filterByScope(\n    queryCached(\n      [\n        \"$..requestBody..['application/xml']\",\n        \"$..requestBody..['application/xml-external-parsed-entity']\",\n        \"$..requestBody..['application/xml-dtd']\",\n        \"$..requestBody..['text/xml']\",\n        \"$..requestBody..['text/xml-external-parsed-entity']\",\n        '$..requestBody.content[?(@property.match(/\\\\+xml$/i))]',\n      ],\n      definition,\n    ),\n    scope,\n  ).map(res => refizePointer(res.pointer));\n}\n\n/**\n * Determine if a given API definition uses XML in a response body.\n *\n * @todo detect `+xml` media types\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object}\n */\nexport function xmlResponses(definition: OASDocument, scope?: OperationScope): string[] {\n  return filterByScope(\n    queryCached(\n      [\n        \"$..responses..['application/xml']\",\n        \"$..responses..['application/xml-external-parsed-entity']\",\n        \"$..responses..['application/xml-dtd']\",\n        \"$..responses..['text/xml']\",\n        \"$..responses..['text/xml-external-parsed-entity']\",\n        '$..responses[*].content[?(@property.match(/\\\\+xml$/i))]',\n      ],\n      definition,\n    ),\n    scope,\n  ).map(res => refizePointer(res.pointer));\n}\n\n/**\n * Determine if a given API definition utilises the XML object for defining XML schemas.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#xml-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#xml-object}\n */\nexport function xmlSchemas(definition: OASDocument, scope?: OperationScope): string[] {\n  return filterByScope(\n    queryCached(['$.components.schemas..xml^', '$..parameters..xml^', '$..requestBody..xml^'], definition),\n    scope,\n  ).map(res => refizePointer(res.pointer));\n}\n","import type { OAS31Document, OASDocument } from '../types.js';\nimport type { OperationScope } from './scope.js';\nimport type { AnalyzerQuery, OASAnalysis } from './types.js';\n\nimport { toPointer } from '../lib/refs.js';\nimport { isOpenAPI31 } from '../types.js';\n\nimport { dereferenceOasShared } from './dereference.js';\nimport {\n  additionalProperties as analyzeAdditionalProperties,\n  callbacks as analyzeCallbacks,\n  commonParameters as analyzeCommonParameters,\n  discriminators as analyzeDiscriminators,\n  links as analyzeLinks,\n  mediaTypes as analyzeMediaTypes,\n  parameterSerialization as analyzeParameterSerialization,\n  polymorphism as analyzePolymorphism,\n  references as analyzeReferences,\n  securityTypes as analyzeSecurityTypes,\n  serverVariables as analyzeServerVariables,\n  totalOperations as analyzeTotalOperations,\n  webhooks as analyzeWebhooks,\n  xmlRequests as analyzeXMLRequests,\n  xmlResponses as analyzeXMLResponses,\n  xmlSchemas as analyzeXMLSchemas,\n} from './queries/openapi.js';\nimport { computeOperationScope, computeWebhookScope, isPointerInScope } from './scope.js';\n\n/**\n * Run every analyzer query against a definition, optionally narrowed down to a single operation or\n * webhook's `OperationScope`.\n *\n * This is the shared implementation behind `analyzer()`, `analyzeOperation()`, and\n * `analyzeWebhookOperation()`. Dereferencing (the most expensive step here) is cached against the\n * original `definition` reference via `dereferenceOasShared()`, and every JSONPath scan that the\n * individual queries run is cached against it as well, so calling this repeatedly for many\n * operations out of the same definition only pays the full-document cost once.\n *\n */\nasync function buildAnalysis(\n  definition: OASDocument,\n  query?: AnalyzerQuery[],\n  scope?: OperationScope,\n): Promise<OASAnalysis> {\n  const analysis: OASAnalysis = {};\n\n  if (!query || query.includes('mediaTypes')) {\n    analysis.mediaTypes = {\n      name: 'Media Type',\n      found: analyzeMediaTypes(definition, scope),\n    };\n  }\n\n  if (!query || query.includes('operationTotal')) {\n    analysis.operationTotal = {\n      name: 'Operation',\n      // A scoped analysis is, by definition, looking at exactly one operation.\n      found: scope ? 1 : analyzeTotalOperations(definition),\n    };\n  }\n\n  if (!query || query.includes('securityTypes')) {\n    analysis.securityTypes = {\n      name: 'Security Type',\n      found: analyzeSecurityTypes(definition, scope),\n    };\n  }\n\n  if (!query || query.includes('additionalProperties')) {\n    const additionalProperties = analyzeAdditionalProperties(definition, scope);\n    analysis.additionalProperties = {\n      present: !!additionalProperties.length,\n      locations: additionalProperties,\n    };\n  }\n\n  if (!query || query.includes('callbacks')) {\n    const callbacks = analyzeCallbacks(definition, scope);\n    analysis.callbacks = {\n      present: !!callbacks.length,\n      locations: callbacks,\n    };\n  }\n\n  if (!query || query.includes('circularRefs')) {\n    const { circularRefs: dereferencedCircularRefs } = await dereferenceOasShared(definition);\n    const circularRefs = (\n      scope\n        ? dereferencedCircularRefs.filter(ref => isPointerInScope(toPointer(ref), scope))\n        : [...dereferencedCircularRefs]\n    ).toSorted();\n\n    analysis.circularRefs = {\n      present: !!circularRefs.length,\n      locations: circularRefs,\n    };\n  }\n\n  if (!query || query.includes('commonParameters')) {\n    const commonParameters = analyzeCommonParameters(definition, scope);\n    analysis.commonParameters = {\n      present: !!commonParameters.length,\n      locations: commonParameters,\n    };\n  }\n\n  if (!query || query.includes('discriminators')) {\n    const discriminators = analyzeDiscriminators(definition, scope);\n    analysis.discriminators = {\n      present: !!discriminators.length,\n      locations: discriminators,\n    };\n  }\n\n  if (!query || query.includes('links')) {\n    const links = analyzeLinks(definition, scope);\n    analysis.links = {\n      present: !!links.length,\n      locations: links,\n    };\n  }\n\n  if (!query || query.includes('style')) {\n    const parameterSerialization = analyzeParameterSerialization(definition, scope);\n    analysis.style = {\n      present: !!parameterSerialization.length,\n      locations: parameterSerialization,\n    };\n  }\n\n  if (!query || query.includes('polymorphism')) {\n    const polymorphism = analyzePolymorphism(definition, scope);\n    analysis.polymorphism = {\n      present: !!polymorphism.length,\n      locations: polymorphism,\n    };\n  }\n\n  if (!query || query.includes('references')) {\n    const references = analyzeReferences(definition, scope);\n    analysis.references = {\n      present: !!references.length,\n      locations: references,\n    };\n  }\n\n  if (!query || query.includes('serverVariables')) {\n    const serverVariables = analyzeServerVariables(definition);\n    analysis.serverVariables = {\n      present: !!serverVariables.length,\n      locations: serverVariables,\n    };\n  }\n\n  if (!query || query.includes('xmlRequests')) {\n    const xmlRequests = analyzeXMLRequests(definition, scope);\n    analysis.xmlRequests = {\n      present: !!xmlRequests.length,\n      locations: xmlRequests,\n    };\n  }\n\n  if (!query || query.includes('xmlResponses')) {\n    const xmlResponses = analyzeXMLResponses(definition, scope);\n    analysis.xmlResponses = {\n      present: !!xmlResponses.length,\n      locations: xmlResponses,\n    };\n  }\n\n  if (!query || query.includes('xmlSchemas')) {\n    const xmlSchemas = analyzeXMLSchemas(definition, scope);\n    analysis.xmlSchemas = {\n      present: !!xmlSchemas.length,\n      locations: xmlSchemas,\n    };\n  }\n\n  if (!query || query.includes('xmlSchemas')) {\n    const webhooks = analyzeWebhooks(definition, scope);\n    analysis.webhooks = {\n      present: !!webhooks.length,\n      locations: webhooks,\n    };\n  }\n\n  return analysis;\n}\n\n/**\n * Analyze a given OpenAPI or Swagger definition for any, or a specific, OpenAPI or JSON Schema\n * feature uses it may contain or utilize.\n *\n */\nexport async function analyzer(definition: OASDocument, query?: AnalyzerQuery[]): Promise<OASAnalysis> {\n  return buildAnalysis(definition, query);\n}\n\n/**\n * Analyze a single operation within a given OpenAPI definition for any, or a specific, OpenAPI or\n * JSON Schema feature uses that it, or anything it references, may contain or utilize.\n *\n * When analyzing many operations out of the same definition, pass the *same* `definition`\n * reference to every call — the expensive dereferencing and document-wide JSONPath scans that this\n * relies on are cached against that reference, so only the first call pays for them.\n *\n */\nexport async function analyzeOperation(\n  definition: OASDocument,\n  {\n    path,\n    method,\n    query,\n  }: {\n    path: string;\n    method: string;\n    query?: AnalyzerQuery[];\n  },\n): Promise<OASAnalysis> {\n  const scope = computeOperationScope(definition, path, method);\n  return buildAnalysis(definition, query, scope);\n}\n\n/**\n * Analyze a single webhook operation within a given OpenAPI 3.1 definition for any, or a specific,\n * OpenAPI or JSON Schema feature uses that it, or anything it references, may contain or utilize.\n *\n * @see {@link analyzeOperation}\n */\nexport async function analyzeWebhookOperation(\n  definition: OASDocument,\n  {\n    webhookName,\n    method,\n    query,\n  }: {\n    webhookName: string;\n    method: string;\n    query?: AnalyzerQuery[];\n  },\n): Promise<OASAnalysis> {\n  if (!isOpenAPI31(definition)) {\n    throw new TypeError('The supplied definition is not a OpenAPI 3.1 definition.');\n  }\n\n  const scope = computeWebhookScope(definition satisfies OAS31Document, webhookName, method);\n  return buildAnalysis(definition, query, scope);\n}\n"]}