joiner

package
v1.28.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 16, 2025 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package joiner provides joining for multiple OpenAPI Specification documents.

The joiner merges multiple OAS documents of the same major version into a single document. It supports OAS 2.0 documents with other 2.0 documents, and all OAS 3.x versions together (3.0.x, 3.1.x, 3.2.x). It uses the version and format (JSON or YAML) from the first document as the result version and format, ensuring format consistency when writing output with WriteResult.

Quick Start

Join files using functional options:

result, err := joiner.JoinWithOptions(
	joiner.WithFilePaths([]string{"base.yaml", "ext.yaml"}),
	joiner.WithPathStrategy(joiner.StrategyAcceptLeft),
)
if err != nil {
	log.Fatal(err)
}
_ = joiner.WriteResult(result, "merged.yaml")

Or use a full config with options:

config := joiner.DefaultConfig()
config.PathStrategy = joiner.StrategyAcceptLeft
result, err := joiner.JoinWithOptions(
	joiner.WithFilePaths([]string{"base.yaml", "ext.yaml"}),
	joiner.WithConfig(config),
)

Or create a reusable Joiner instance:

j := joiner.New(joiner.DefaultConfig())
result1, _ := j.Join([]string{"api1-base.yaml", "api1-ext.yaml"})
result2, _ := j.Join([]string{"api2-base.yaml", "api2-ext.yaml"})
j.WriteResult(result1, "merged1.yaml")
j.WriteResult(result2, "merged2.yaml")

Collision Strategies

Control how collisions between documents are handled:

  • StrategyFailOnCollision: Fail on any collision (default)
  • StrategyAcceptLeft: Keep value from first document
  • StrategyAcceptRight: Keep value from last document
  • StrategyFailOnPaths: Fail only on path collisions, allow schema merging
  • StrategyRenameLeft: Rename left schema, keep right under original name
  • StrategyRenameRight: Rename right schema, keep left under original name
  • StrategyDeduplicateEquivalent: Merge structurally identical schemas

Set strategies globally (DefaultStrategy) or per component type (PathStrategy, SchemaStrategy, ComponentStrategy). The rename and deduplicate strategies provide advanced collision handling with automatic reference rewriting.

Advanced Collision Handling

The rename strategies preserve both colliding schemas by renaming one and automatically updating all references throughout the merged document:

config := joiner.DefaultConfig()
config.SchemaStrategy = joiner.StrategyRenameRight
config.RenameTemplate = "{{.Name}}_{{.Source}}"
result, err := joiner.JoinWithOptions(
	joiner.WithFilePaths([]string{"users-api.yaml", "billing-api.yaml"}),
	joiner.WithConfig(config),
)

The deduplicate strategy uses semantic equivalence detection to merge structurally identical schemas while failing on true structural conflicts:

config := joiner.DefaultConfig()
config.SchemaStrategy = joiner.StrategyDeduplicateEquivalent
config.EquivalenceMode = "deep"
result, err := joiner.JoinWithOptions(
	joiner.WithFilePaths([]string{"base.yaml", "ext.yaml"}),
	joiner.WithConfig(config),
)

See the examples in example_test.go for more configuration patterns.

Overlay Integration

Apply overlays during the join process for pre-processing inputs or post-processing results:

result, err := joiner.JoinWithOptions(
    joiner.WithFilePaths([]string{"base.yaml", "ext.yaml"}),
    joiner.WithPreJoinOverlayFile("normalize.yaml"),   // Applied to each input
    joiner.WithPostJoinOverlayFile("enhance.yaml"),    // Applied to merged result
)

Pre-join overlays are applied to each input document before merging. Post-join overlays are applied to the final merged result.

Semantic Schema Deduplication

After merging, the joiner can automatically identify and consolidate structurally identical schemas across all input documents. This reduces document size when multiple APIs happen to define equivalent types with different names.

Enable via option:

result, err := joiner.JoinWithOptions(
    joiner.WithFilePaths([]string{"users-api.yaml", "orders-api.yaml"}),
    joiner.WithSemanticDeduplication(true),
)

Or via config:

config := joiner.DefaultConfig()
config.SemanticDeduplication = true
j := joiner.New(config)
result, _ := j.Join([]string{"api1.yaml", "api2.yaml"})

When schemas from different documents are structurally equivalent (same type, properties, constraints), they are consolidated into a single canonical schema (alphabetically first name). All $ref references throughout the merged document are automatically rewritten.

This differs from the StrategyDeduplicateEquivalent collision strategy which only handles same-named collisions. Semantic deduplication works across all schemas regardless of their original names.

Features and Limitations

The joiner validates all input documents, prevents output file overwrites with restrictive 0600 permissions, deduplicates tags, and optionally merges arrays (servers, security, tags). It uses the info object from the first document; subsequent info sections are ignored.

External References

The joiner preserves external $ref values but does NOT resolve or merge them. This is intentional to avoid ambiguity and maintain document structure.

If your documents contain external references, you have two options:

  1. Resolve references before joining: Use parser.ParseWithOptions(parser.WithResolveRefs(true)) before joining

  2. Keep external references and resolve after joining: Join the documents, then parse the result with WithResolveRefs(true)

Example with external references:

// Document 1: base.yaml
// paths:
//   /users:
//     get:
//       responses:
//         200:
//           schema:
//             $ref: "./schemas/user.yaml#/User"
//
// Document 2: extension.yaml
// paths:
//   /posts:
//     get:
//       responses:
//         200:
//           schema:
//             $ref: "./schemas/post.yaml#/Post"
//
// After joining, both $ref values are preserved in the merged document.
// Use parser.WithResolveRefs(true) to resolve them if needed.

The joiner integrates with other oastools packages:

Example

Example demonstrates basic usage of the joiner to combine two OpenAPI specifications.

package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/erraggy/oastools/joiner"
)

func main() {
	outputPath := filepath.Join(os.TempDir(), "joined-example.yaml")
	defer func() { _ = os.Remove(outputPath) }()
	config := joiner.DefaultConfig()
	j := joiner.New(config)
	result, err := j.Join([]string{
		"../testdata/join-base-3.0.yaml",
		"../testdata/join-extension-3.0.yaml",
	})
	if err != nil {
		log.Fatalf("failed to join: %v", err)
	}
	err = j.WriteResult(result, outputPath)
	if err != nil {
		log.Fatalf("failed to write result: %v", err)
	}
	fmt.Printf("Version: %s\n", result.Version)
	fmt.Printf("Warnings: %d\n", len(result.Warnings))
}
Output:

Version: 3.0.3
Warnings: 0
Example (CustomStrategies)

Example_customStrategies demonstrates using custom collision strategies for different component types.

package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/erraggy/oastools/joiner"
)

func main() {
	outputPath := filepath.Join(os.TempDir(), "joined-custom.yaml")
	defer func() { _ = os.Remove(outputPath) }()
	config := joiner.JoinerConfig{
		DefaultStrategy:   joiner.StrategyFailOnCollision,
		PathStrategy:      joiner.StrategyFailOnPaths,
		SchemaStrategy:    joiner.StrategyAcceptLeft,
		ComponentStrategy: joiner.StrategyAcceptRight,
		DeduplicateTags:   true,
		MergeArrays:       true,
	}
	j := joiner.New(config)
	result, err := j.Join([]string{
		"../testdata/join-base-3.0.yaml",
		"../testdata/join-extension-3.0.yaml",
	})
	if err != nil {
		log.Fatalf("failed to join: %v", err)
	}
	err = j.WriteResult(result, outputPath)
	if err != nil {
		log.Fatalf("failed to write result: %v", err)
	}
	fmt.Printf("Joined successfully\n")
	fmt.Printf("Collisions resolved: %d\n", result.CollisionCount)
}
Output:

Joined successfully
Collisions resolved: 0
Example (SemanticDeduplication)

Example_semanticDeduplication demonstrates automatic consolidation of identical schemas across multiple OpenAPI documents. When documents share structurally identical schemas (even if named differently), semantic deduplication identifies these duplicates and consolidates them to a single canonical schema.

package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/erraggy/oastools/joiner"
)

func main() {
	outputPath := filepath.Join(os.TempDir(), "joined-dedup.yaml")
	defer func() { _ = os.Remove(outputPath) }()

	// Enable semantic deduplication in the joiner configuration
	config := joiner.JoinerConfig{
		DefaultStrategy:       joiner.StrategyAcceptLeft,
		SemanticDeduplication: true,   // Enable schema deduplication
		EquivalenceMode:       "deep", // Use deep structural comparison
		DeduplicateTags:       true,
		MergeArrays:           true,
	}

	j := joiner.New(config)
	result, err := j.Join([]string{
		"../testdata/join-base-3.0.yaml",
		"../testdata/join-extension-3.0.yaml",
	})
	if err != nil {
		log.Fatalf("failed to join: %v", err)
	}

	err = j.WriteResult(result, outputPath)
	if err != nil {
		log.Fatalf("failed to write result: %v", err)
	}

	// Semantic deduplication identifies structurally equivalent schemas
	// across documents and consolidates them, reducing duplication in the
	// merged output. The alphabetically-first name becomes canonical.
	fmt.Printf("Joined successfully\n")
	fmt.Printf("Version: %s\n", result.Version)
}
Output:

Joined successfully
Version: 3.0.3

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsValidEquivalenceMode added in v1.23.0

func IsValidEquivalenceMode(mode string) bool

IsValidEquivalenceMode checks if an equivalence mode string is valid

func IsValidStrategy

func IsValidStrategy(strategy string) bool

IsValidStrategy checks if a strategy string is valid

func ValidEquivalenceModes added in v1.23.0

func ValidEquivalenceModes() []string

ValidEquivalenceModes returns all valid equivalence mode strings

func ValidStrategies

func ValidStrategies() []string

ValidStrategies returns all valid collision strategy strings

Types

type CollisionError

type CollisionError struct {
	Section      string
	Key          string
	FirstFile    string
	FirstPath    string
	FirstLine    int // 1-based line number in first file (0 if unknown)
	FirstColumn  int // 1-based column number in first file (0 if unknown)
	SecondFile   string
	SecondPath   string
	SecondLine   int // 1-based line number in second file (0 if unknown)
	SecondColumn int // 1-based column number in second file (0 if unknown)
	Strategy     CollisionStrategy
}

CollisionError provides detailed information about a collision

func (*CollisionError) Error

func (e *CollisionError) Error() string

type CollisionEvent added in v1.23.0

type CollisionEvent struct {
	SchemaName  string
	LeftSource  string
	LeftLine    int // 1-based line number in left source (0 if unknown)
	LeftColumn  int // 1-based column number in left source (0 if unknown)
	RightSource string
	RightLine   int // 1-based line number in right source (0 if unknown)
	RightColumn int // 1-based column number in right source (0 if unknown)
	Strategy    CollisionStrategy
	Resolution  string // "renamed", "deduplicated", "kept-left", "kept-right", "failed"
	NewName     string // For rename resolutions
	Differences []SchemaDifference
	Severity    severity.Severity
}

CollisionEvent represents a single collision occurrence with resolution details

type CollisionReport added in v1.23.0

type CollisionReport struct {
	TotalCollisions  int
	ResolvedByRename int
	ResolvedByDedup  int
	ResolvedByAccept int
	FailedCollisions int
	Events           []CollisionEvent
}

CollisionReport provides detailed analysis of collisions encountered during join operations

func NewCollisionReport added in v1.23.0

func NewCollisionReport() *CollisionReport

NewCollisionReport creates an empty collision report

func (*CollisionReport) AddEvent added in v1.23.0

func (r *CollisionReport) AddEvent(event CollisionEvent)

AddEvent adds a collision event to the report and updates counters

func (*CollisionReport) GetByResolution added in v1.23.0

func (r *CollisionReport) GetByResolution(resolution string) []CollisionEvent

GetByResolution returns events with a specific resolution type

func (*CollisionReport) GetCriticalEvents added in v1.23.0

func (r *CollisionReport) GetCriticalEvents() []CollisionEvent

GetCriticalEvents returns events with Critical severity

func (*CollisionReport) HasFailures added in v1.23.0

func (r *CollisionReport) HasFailures() bool

HasFailures returns true if any collisions failed to resolve

type CollisionStrategy

type CollisionStrategy string

CollisionStrategy defines how to handle collisions when merging documents

const (
	// StrategyAcceptLeft keeps values from the first document when collisions occur
	StrategyAcceptLeft CollisionStrategy = "accept-left"
	// StrategyAcceptRight keeps values from the last document when collisions occur (overwrites)
	StrategyAcceptRight CollisionStrategy = "accept-right"
	// StrategyFailOnCollision returns an error if any collision is detected
	StrategyFailOnCollision CollisionStrategy = "fail"
	// StrategyFailOnPaths fails only on path collisions, allows schema/component collisions
	StrategyFailOnPaths CollisionStrategy = "fail-on-paths"
	// StrategyRenameLeft keeps the right-side schema and renames the left-side schema
	StrategyRenameLeft CollisionStrategy = "rename-left"
	// StrategyRenameRight keeps the left-side schema and renames the right-side schema
	StrategyRenameRight CollisionStrategy = "rename-right"
	// StrategyDeduplicateEquivalent uses semantic comparison to deduplicate structurally identical schemas
	StrategyDeduplicateEquivalent CollisionStrategy = "deduplicate"
)

type EquivalenceMode added in v1.23.0

type EquivalenceMode string

EquivalenceMode defines how deeply to compare schemas

const (
	// EquivalenceModeNone disables equivalence detection
	EquivalenceModeNone EquivalenceMode = "none"
	// EquivalenceModeShallow compares only top-level schema properties
	EquivalenceModeShallow EquivalenceMode = "shallow"
	// EquivalenceModeDeep recursively compares all nested schemas
	EquivalenceModeDeep EquivalenceMode = "deep"
)

type EquivalenceResult added in v1.23.0

type EquivalenceResult struct {
	Equivalent  bool
	Differences []SchemaDifference
}

EquivalenceResult contains the outcome of schema comparison

func CompareSchemas added in v1.23.0

func CompareSchemas(left, right *parser.Schema, mode EquivalenceMode) EquivalenceResult

CompareSchemas compares two schemas for structural equivalence Ignores: description, title, example, deprecated, and extension fields (x-*)

type JoinResult

type JoinResult struct {
	// Document contains the joined document (*parser.OAS2Document or *parser.OAS3Document)
	Document any
	// Version is the OpenAPI version of the joined document
	Version string
	// OASVersion is the enumerated version
	OASVersion parser.OASVersion
	// SourceFormat is the format of the first source file (JSON or YAML)
	SourceFormat parser.SourceFormat
	// Warnings contains non-fatal issues encountered during joining
	Warnings []string
	// CollisionCount tracks the number of collisions resolved
	CollisionCount int
	// Stats contains statistical information about the joined document
	Stats parser.DocumentStats
	// CollisionDetails contains detailed collision analysis (when CollisionReport is enabled)
	CollisionDetails *CollisionReport
	// contains filtered or unexported fields
}

JoinResult contains the joined OpenAPI specification and metadata

func JoinWithOptions added in v1.11.0

func JoinWithOptions(opts ...Option) (*JoinResult, error)

JoinWithOptions joins multiple OpenAPI specifications using functional options. This provides a flexible, extensible API that combines input source selection and configuration in a single function call.

When overlay options are provided, the join process follows these steps:

  1. Parse all input specifications
  2. Apply pre-join overlays to all specs (in order specified)
  3. Apply per-spec overlays to their respective specs
  4. Perform the join operation
  5. Apply post-join overlay to the merged result

Example:

result, err := joiner.JoinWithOptions(
    joiner.WithFilePaths("api1.yaml", "api2.yaml"),
    joiner.WithPathStrategy(joiner.StrategyAcceptLeft),
    joiner.WithPreJoinOverlayFile("normalize.yaml"),
    joiner.WithPostJoinOverlayFile("enhance.yaml"),
)

type Joiner

type Joiner struct {

	// SourceMaps maps source file paths to their SourceMaps for location lookup.
	// When populated, collision errors and events include line/column information.
	SourceMaps map[string]*parser.SourceMap
	// contains filtered or unexported fields
}

Joiner handles joining of multiple OpenAPI specifications.

Concurrency: Joiner instances are not safe for concurrent use. Create separate Joiner instances for concurrent operations.

func New

func New(config JoinerConfig) *Joiner

New creates a new Joiner instance with the provided configuration

func (*Joiner) Join

func (j *Joiner) Join(specPaths []string) (*JoinResult, error)

Join joins multiple OpenAPI specifications into a single document

func (*Joiner) JoinParsed added in v1.3.1

func (j *Joiner) JoinParsed(parsedDocs []parser.ParseResult) (*JoinResult, error)

func (*Joiner) WriteResult

func (j *Joiner) WriteResult(result *JoinResult, outputPath string) error

WriteResult writes a join result to a file in YAML or JSON format (matching the source format)

The output file is written with restrictive permissions (0600 - owner read/write only) to protect potentially sensitive API specifications. If the file already exists, its permissions will be explicitly set to 0600 after writing.

type JoinerConfig

type JoinerConfig struct {
	// DefaultStrategy is the global strategy for all collisions
	DefaultStrategy CollisionStrategy
	// PathStrategy defines strategy specifically for path collisions
	PathStrategy CollisionStrategy
	// SchemaStrategy defines strategy specifically for schema/definition collisions
	SchemaStrategy CollisionStrategy
	// ComponentStrategy defines strategy for other component collisions (parameters, responses, etc.)
	ComponentStrategy CollisionStrategy
	// DeduplicateTags removes duplicate tags by name
	DeduplicateTags bool
	// MergeArrays determines whether to merge array fields (servers, security, etc.)
	MergeArrays bool

	// Advanced collision strategies configuration
	// RenameTemplate is a Go template for renamed schema names (default: "{{.Name}}_{{.Source}}")
	// Available variables: {{.Name}} (original name), {{.Source}} (source file), {{.Index}} (doc index)
	RenameTemplate string
	// NamespacePrefix maps source file paths to namespace prefixes for schema names
	// Example: {"users-api.yaml": "Users", "billing-api.yaml": "Billing"}
	// When a prefix is configured, schemas from that source get prefixed: User -> Users_User
	NamespacePrefix map[string]string
	// AlwaysApplyPrefix when true applies namespace prefix to all schemas from a source,
	// not just those that collide. When false (default), prefix is only applied on collision.
	AlwaysApplyPrefix bool
	// EquivalenceMode controls depth of schema comparison: "none", "shallow", or "deep"
	EquivalenceMode string
	// CollisionReport enables detailed collision analysis reporting
	CollisionReport bool
	// SemanticDeduplication enables cross-document schema deduplication after merging.
	// When enabled, semantically identical schemas are consolidated to a single
	// canonical schema (alphabetically first), and all references are rewritten.
	SemanticDeduplication bool
}

JoinerConfig configures how documents are joined

func DefaultConfig

func DefaultConfig() JoinerConfig

DefaultConfig returns a sensible default configuration

type Option added in v1.11.0

type Option func(*joinConfig) error

Option is a function that configures a join operation

func WithAlwaysApplyPrefix added in v1.23.0

func WithAlwaysApplyPrefix(enabled bool) Option

WithAlwaysApplyPrefix enables or disables applying namespace prefix to all schemas, not just those that collide. When false (default), prefix is only applied on collision.

func WithCollisionReport added in v1.23.0

func WithCollisionReport(enabled bool) Option

WithCollisionReport enables or disables detailed collision reporting Default: false

func WithComponentStrategy added in v1.11.0

func WithComponentStrategy(strategy CollisionStrategy) Option

WithComponentStrategy sets the collision strategy for components

func WithConfig added in v1.11.0

func WithConfig(config JoinerConfig) Option

WithConfig applies an entire JoinerConfig struct This is useful for reusing existing configurations or loading from files

func WithDeduplicateTags added in v1.11.0

func WithDeduplicateTags(enabled bool) Option

WithDeduplicateTags enables or disables tag deduplication Default: true

func WithDefaultStrategy added in v1.11.0

func WithDefaultStrategy(strategy CollisionStrategy) Option

WithDefaultStrategy sets the global collision strategy

func WithEquivalenceMode added in v1.23.0

func WithEquivalenceMode(mode string) Option

WithEquivalenceMode sets the schema comparison mode for deduplication Valid values: "none", "shallow", "deep" Default: "none"

func WithFilePaths added in v1.11.0

func WithFilePaths(paths ...string) Option

WithFilePaths specifies file paths as input sources

func WithMergeArrays added in v1.11.0

func WithMergeArrays(enabled bool) Option

WithMergeArrays enables or disables array merging (servers, security, etc.) Default: true

func WithNamespacePrefix added in v1.23.0

func WithNamespacePrefix(sourcePath, prefix string) Option

WithNamespacePrefix adds a namespace prefix mapping for a source file. When schemas from a source file collide (or when AlwaysApplyPrefix is true), the prefix is applied to schema names: e.g., "User" -> "Users_User" Can be called multiple times to add multiple mappings.

func WithParsed added in v1.11.0

func WithParsed(docs ...parser.ParseResult) Option

WithParsed specifies parsed ParseResults as input sources

func WithPathStrategy added in v1.11.0

func WithPathStrategy(strategy CollisionStrategy) Option

WithPathStrategy sets the collision strategy for paths

func WithPostJoinOverlay added in v1.24.0

func WithPostJoinOverlay(o *overlay.Overlay) Option

WithPostJoinOverlay sets an overlay to be applied after joining is complete.

Only one post-join overlay can be specified (last one wins). This is useful for adding unified metadata, removing internal extensions, or applying final transformations to the merged document.

Example:

result, err := joiner.JoinWithOptions(
    joiner.WithFilePaths("api1.yaml", "api2.yaml"),
    joiner.WithPostJoinOverlay(enhanceOverlay),
)

func WithPostJoinOverlayFile added in v1.24.0

func WithPostJoinOverlayFile(path string) Option

WithPostJoinOverlayFile sets an overlay file to be applied after joining is complete.

This is a convenience wrapper around WithPostJoinOverlay that parses the overlay file. Only one post-join overlay file can be specified (last one wins).

Example:

result, err := joiner.JoinWithOptions(
    joiner.WithFilePaths("api1.yaml", "api2.yaml"),
    joiner.WithPostJoinOverlayFile("enhance.yaml"),
)

func WithPreJoinOverlay added in v1.24.0

func WithPreJoinOverlay(o *overlay.Overlay) Option

WithPreJoinOverlay adds an overlay to be applied to all input specs before joining.

Multiple pre-join overlays can be specified and are applied in order. This is useful for normalizing specs before merge (e.g., adding required fields, standardizing naming conventions).

Example:

result, err := joiner.JoinWithOptions(
    joiner.WithFilePaths("api1.yaml", "api2.yaml"),
    joiner.WithPreJoinOverlay(normalizeOverlay),
)

func WithPreJoinOverlayFile added in v1.24.0

func WithPreJoinOverlayFile(path string) Option

WithPreJoinOverlayFile adds an overlay file to be applied to all input specs before joining.

This is a convenience wrapper around WithPreJoinOverlay that parses the overlay file. Multiple pre-join overlay files can be specified.

Example:

result, err := joiner.JoinWithOptions(
    joiner.WithFilePaths("api1.yaml", "api2.yaml"),
    joiner.WithPreJoinOverlayFile("normalize.yaml"),
)

func WithRenameTemplate added in v1.23.0

func WithRenameTemplate(template string) Option

WithRenameTemplate sets the Go template for renamed schema names Default: "{{.Name}}_{{.Source}}" Available variables: {{.Name}}, {{.Source}}, {{.Index}}, {{.Suffix}}

func WithSchemaStrategy added in v1.11.0

func WithSchemaStrategy(strategy CollisionStrategy) Option

WithSchemaStrategy sets the collision strategy for schemas/definitions

func WithSemanticDeduplication added in v1.26.0

func WithSemanticDeduplication(enabled bool) Option

WithSemanticDeduplication enables or disables semantic schema deduplication. When enabled, after merging all documents, the joiner identifies semantically identical schemas and consolidates them to a single canonical schema. The canonical name is selected alphabetically (e.g., "Address" beats "Location"). All references to duplicate schemas are rewritten to the canonical name. Default: false

func WithSourceMaps added in v1.27.0

func WithSourceMaps(maps map[string]*parser.SourceMap) Option

WithSourceMaps provides SourceMaps for all input documents. The map keys should match the file paths used when parsing (e.g., ParseResult.SourcePath). When provided, collision errors and events include line/column information for both sides of the collision, enabling precise error reporting.

func WithSpecOverlay added in v1.24.0

func WithSpecOverlay(specIdentifier string, o *overlay.Overlay) Option

WithSpecOverlay maps a specific overlay to a specific input spec.

The specIdentifier should match either:

  • A file path from WithFilePaths (e.g., "api1.yaml")
  • An index like "0", "1", etc. for WithParsed documents

This allows applying different transformations to different input specs.

Example:

result, err := joiner.JoinWithOptions(
    joiner.WithFilePaths("users-api.yaml", "billing-api.yaml"),
    joiner.WithSpecOverlay("users-api.yaml", usersOverlay),
    joiner.WithSpecOverlay("billing-api.yaml", billingOverlay),
)

func WithSpecOverlayFile added in v1.24.0

func WithSpecOverlayFile(specIdentifier, overlayPath string) Option

WithSpecOverlayFile maps a specific overlay file to a specific input spec.

This is a convenience wrapper around WithSpecOverlay that parses the overlay file.

Example:

result, err := joiner.JoinWithOptions(
    joiner.WithFilePaths("users-api.yaml", "billing-api.yaml"),
    joiner.WithSpecOverlayFile("users-api.yaml", "users-overlay.yaml"),
)

type SchemaDifference added in v1.23.0

type SchemaDifference struct {
	Path        string // JSON path to differing element (e.g., "properties.name.type")
	LeftValue   any
	LeftLine    int // 1-based line number for left value (0 if unknown)
	LeftColumn  int // 1-based column number for left value (0 if unknown)
	RightValue  any
	RightLine   int // 1-based line number for right value (0 if unknown)
	RightColumn int // 1-based column number for right value (0 if unknown)
	Description string
}

SchemaDifference describes a structural difference between two schemas

type SchemaRewriter added in v1.23.0

type SchemaRewriter struct {
	// contains filtered or unexported fields
}

SchemaRewriter handles rewriting of schema references throughout an OpenAPI document

func NewSchemaRewriter added in v1.23.0

func NewSchemaRewriter() *SchemaRewriter

NewSchemaRewriter creates a new rewriter instance

func (*SchemaRewriter) RegisterRename added in v1.23.0

func (r *SchemaRewriter) RegisterRename(oldName, newName string, version parser.OASVersion)

RegisterRename registers a schema rename operation

func (*SchemaRewriter) RewriteDocument added in v1.23.0

func (r *SchemaRewriter) RewriteDocument(doc any) error

RewriteDocument traverses and rewrites all references in the document

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL