func MergeWithTables(spec1, spec2 *Spec, specExtraNote string, mergeOpts *MergeOptions) (*Spec, []*table.Table, error) {
	tbls := []*table.Table{}
	sm1 := SpecMore{Spec: spec1}
	sm2 := SpecMore{Spec: spec2}
	tbls1, err := sm1.OperationsTable(mergeOpts.TableColumns, mergeOpts.TableOpFilterFunc)
	if err != nil {
		return nil, nil, err
	}
	tbls = append(tbls, tbls1)
	tbls[0].Name = "Spec1"
	tbls2, err := sm2.OperationsTable(mergeOpts.TableColumns, mergeOpts.TableOpFilterFunc)
	if err != nil {
		return nil, nil, err
	}
	tbls = append(tbls, tbls2)
	tbls[1].Name = "Spec2"
	specf, err := Merge(spec1, spec2, specExtraNote, mergeOpts)
	if err != nil {
		return specf, tbls, err
	}
	smf := SpecMore{Spec: specf}
	tblsf, err := smf.OperationsTable(mergeOpts.TableColumns, mergeOpts.TableOpFilterFunc)
	if err != nil {
		return nil, nil, err
	}
	tbls = append(tbls, tblsf)
	tbls[2].Name = "SpecFinal"
	return specf, tbls, nil
}
MergeWithTables performs a spec merge and returns comparison
tables. This is useful to combine with github.com/grokify/gocharts/data/table
WriteXLSX() to write out comparison tables for debugging.
package openapi3
import (
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"regexp"
	"sort"
	"strings"
	oas3 "github.com/getkin/kin-openapi/openapi3"
	"github.com/grokify/gocharts/data/table"
	"github.com/grokify/simplego/os/osutil"
	"github.com/pkg/errors"
)
var jsonFileRx = regexp.MustCompile(`(?i)\.(json|yaml|yml)\s*$`)
func MergeDirectory(dir string, mergeOpts *MergeOptions) (*Spec, int, error) {
	var filenames []string
	var err error
	if mergeOpts != nil && mergeOpts.FileRx != nil {
		entries, err := osutil.ReadDirMore(dir, mergeOpts.FileRx, false, true, false)
		if err != nil {
			filenames = osutil.DirEntries(entries).Names(dir, true)
		}
	} else {
		entries, err := osutil.ReadDirMore(dir, jsonFileRx, false, true, false)
		if err != nil {
			filenames = osutil.DirEntries(entries).Names(dir, true)
		}
	}
	if err != nil {
		return nil, len(filenames), err
	}
	spec, err := MergeFiles(filenames, mergeOpts)
	return spec, len(filenames), err
}
func MergeFiles(filepaths []string, mergeOpts *MergeOptions) (*Spec, error) {
	sort.Strings(filepaths)
	validateEach := false
	validateFinal := true
	if mergeOpts != nil {
		validateEach = mergeOpts.ValidateEach
		validateFinal = mergeOpts.ValidateFinal
	}
	var specMaster *Spec
	for i, fpath := range filepaths {
		thisSpec, err := ReadFile(fpath, validateEach)
		if err != nil {
			return specMaster, errors.Wrap(err, fmt.Sprintf("ReadSpecError [%v] ValidateEach [%v]", fpath, validateEach))
		}
		if i == 0 {
			specMaster = thisSpec
		} else {
			specMaster, err = Merge(specMaster, thisSpec, fpath, mergeOpts)
			if err != nil {
				return nil, errors.Wrap(err, fmt.Sprintf("Merging [%v]", fpath))
			}
		}
	}
	if validateFinal {
		bytes, err := specMaster.MarshalJSON()
		if err != nil {
			return specMaster, err
		}
		newSpec, err := oas3.NewLoader().LoadFromData(bytes)
		if err != nil {
			return newSpec, errors.Wrap(err, "Loader.LoadSwaggerFromData (MergeFiles().ValidateFinal)")
		}
		return newSpec, nil
	}
	return specMaster, nil
}
func Merge(specMaster, specExtra *Spec, specExtraNote string, mergeOpts *MergeOptions) (*Spec, error) {
	specMaster = MergeTags(specMaster, specExtra)
	specMaster, err := MergeParameters(specMaster, specExtra, specExtraNote, mergeOpts)
	if err != nil {
		return specMaster, err
	}
	specMaster, err = MergeSchemas(specMaster, specExtra, specExtraNote, mergeOpts)
	if err != nil {
		return specMaster, err
	}
	specMaster, err = MergePaths(specMaster, specExtra)
	if err != nil {
		return specMaster, err
	}
	specMaster, err = MergeResponses(specMaster, specExtra, specExtraNote, mergeOpts)
	if err != nil {
		return specMaster, err
	}
	return MergeRequestBodies(specMaster, specExtra, specExtraNote)
}
func MergeTags(specMaster, specExtra *Spec) *Spec {
	tagsMap := map[string]int{}
	for _, tag := range specMaster.Tags {
		tagsMap[tag.Name] = 1
	}
	for _, tag := range specExtra.Tags {
		tag.Name = strings.TrimSpace(tag.Name)
		if _, ok := tagsMap[tag.Name]; !ok {
			specMaster.Tags = append(specMaster.Tags, tag)
		}
	}
	return specMaster
}