Per-input options
Each entry in MergeInput (the first argument to merge()) is a SingleMergeInput: { oas, ...options }. oas is the only required field — an in-memory OpenAPI document. Everything else is optional.
sourceIdentity
sourceIdentity?: string;An opaque identity for this input — typically the resolved absolute path or URL it was loaded from (issue #104). The library never parses or resolves this string; it only compares it for exact equality against the non-fragment portion of a $ref found elsewhere in the merge. A $ref shaped <this input's sourceIdentity>#/components/schemas/X found anywhere in the merge is treated as if it were the bare, in-document ref #/components/schemas/X as seen from this input — rewritten to wherever this input's X ended up after deduplication/renaming, exactly like any other reference into this input.
Resolving the file-path or URL portion of a cross-document $ref against this identity (e.g. deciding that ../common/Errors.yml in one input refers to the same file as another input's own path) is the caller's job — normally openapi-merge-cli, which knows about file paths and can do the async I/O this library deliberately does not do.
pathModification
pathModification?: { stripStart?: string; prepend?: string };Rewrites every path (and 3.1 webhook name) imported from this input. stripStart removes that prefix if present; prepend adds a prefix. prepend always runs after stripStart, so the two compose predictably.
duplicatePathHandling
duplicatePathHandling?: 'error' | 'skip-later' | 'prefer-later' | 'merge-operations'; // default: 'error'What to do when this input declares a path (or webhook) another input already added (issue #71):
'error'(default) — fail withduplicate-paths, the historical behaviour.'skip-later'— keep the definition already present and drop this input's.'prefer-later'— replace the definition already present with this one.'merge-operations'— combine them when their method sets are disjoint and their path-level fields agree, soGET /thingfrom one input andPOST /thingfrom another end up in one path item. Refuses withduplicate-pathswhenever a union would be a guess: overlapping methods, differing path-level fields, or a$refpath item on either side.
Per input rather than global, because what people actually want to express is "this one input wins and the rest are additive," which a single global setting can't say.
operationSelection
operationSelection?: {
includeTags?: string[];
excludeTags?: string[];
includePaths?: PathSelector[];
excludePaths?: PathSelector[];
};Filters which operations from this input are kept:
includeTags— allow-list. Only operations carrying one of these tags survive; an operation with no tags at all does not. Does not remove other tags from this input's top-leveltagsdefinition.excludeTags— deny-list. Operations carrying any of these tags are dropped, and the tags themselves are removed from this input's top-leveltagsbefore merging.includePaths/excludePaths(PathSelector[],{ path: string; method?: string | string[] }) — the same two allow/deny lists, but matched by path (with an optional*wildcard) and method instead of by tag. Matched against this input's own original path, beforepathModificationruns.methodaccepts a 3.2additionalOperationscustom verb like"PURGE", matched case-sensitively.
Precedence: exclusion always wins over inclusion. If an operation is matched by both an include and an exclude rule — of the same kind or different kinds — it's excluded. If both includeTags and includePaths are set, an operation must pass both to survive. See CLI reference → Configuration for the full precedence table (the library and the CLI share this logic exactly).
description
description?: { append: boolean; title?: { value: string; headingLevel?: number } };Controls how this input's info.description contributes to the merged info.description. append: true appends it (in input order) to the merged description; title optionally wraps it in a Markdown heading (headingLevel 1–6, default 1).
tag
tag?: { name: string; description?: string };Adds a tag to every operation from this input (issue #112). Lets a merged document distinguish which service each operation came from without anybody editing the upstream specification. Applied after operationSelection, so an injected tag cannot influence which operations survive — applying it first would make includeTags: ['billing'] match operations solely because this input injects billing, which would read as a filter doing nothing. If another input already contributed a tag of the same name, that input's description wins (first-wins, as everywhere else in this merge).
dispute
dispute?: { prefix: string; alwaysApply?: boolean } | { suffix: string; alwaysApply?: boolean };How to resolve a naming collision when two inputs define a component with the same name but different content. prefix/suffix names the string to disambiguate with; alwaysApply: true applies it to every schema from this input, not just the ones actually in conflict (useful for keeping naming consistent, at the cost of possibly preventing deduplication of components that would otherwise have collapsed).
Deprecated: disputePrefix (v1 shape)
The original shape, disputePrefix?: string directly on the input (instead of dispute: { prefix }), still works and is exercised by existing configurations, but is deprecated in favour of dispute. New code should use dispute.
Full example
const input: SingleMergeInput = {
oas: confluenceSpec,
sourceIdentity: './confluence.swagger.yaml',
pathModification: { stripStart: '/rest', prepend: '/confluence' },
duplicatePathHandling: 'merge-operations',
operationSelection: { excludeTags: ['internal'] },
description: { append: true, title: { value: 'Confluence', headingLevel: 2 } },
tag: { name: 'confluence', description: 'Operations from the Confluence service' },
dispute: { prefix: 'Confluence', alwaysApply: false },
};