func (k *Kazaam) Transform(data []byte) ([]byte, error) {
	d := make([]byte, len(data))
	copy(d, data)
	d, err := k.TransformInPlace(d)
	return d, err
}
Transform makes a copy of the byte slice `data`, transforms it according
to the loaded spec, and returns the new, modified byte slice.
package kazaam
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"github.com/qntfy/jsonparser"
	"github.com/qntfy/kazaam/v4/transform"
)
type TransformFunc func(spec *transform.Config, data []byte) ([]byte, error)
var validSpecTypes map[string]TransformFunc
func init() {
	validSpecTypes = map[string]TransformFunc{
		"pass":      transform.Pass,
		"shift":     transform.Shift,
		"extract":   transform.Extract,
		"default":   transform.Default,
		"delete":    transform.Delete,
		"concat":    transform.Concat,
		"coalesce":  transform.Coalesce,
		"timestamp": transform.Timestamp,
		"uuid":      transform.UUID,
	}
}
type Error struct {
	ErrMsg  string
	ErrType int
}
const (
	ParseError = iota
	RequireError
	SpecError
)
func (e *Error) Error() string {
	switch e.ErrType {
	case ParseError:
		return fmt.Sprintf("ParseError - %s", e.ErrMsg)
	case RequireError:
		return fmt.Sprintf("RequiredError - %s", e.ErrMsg)
	default:
		return fmt.Sprintf("SpecError - %s", e.ErrMsg)
	}
}
type Config struct {
	transforms map[string]TransformFunc
}
func NewDefaultConfig() Config {
	specTypes := make(map[string]TransformFunc)
	for k, v := range validSpecTypes {
		specTypes[k] = v
	}
	return Config{transforms: specTypes}
}
func (c *Config) RegisterTransform(name string, function TransformFunc) error {
	_, ok := c.transforms[name]
	if ok {
		return errors.New("Transform with that name already registered")
	}
	c.transforms[name] = function
	return nil
}
type Kazaam struct {
	spec     string
	specJSON specs
	config   Config
}
func NewKazaam(specString string) (*Kazaam, error) {
	return New(specString, NewDefaultConfig())
}
func New(specString string, config Config) (*Kazaam, error) {
	if len(specString) == 0 {
		specString = `[{"operation":"pass"}]`
	}
	var specElements specs
	if err := json.Unmarshal([]byte(specString), &specElements); err != nil {
		return nil, err
	}
	for _, s := range specElements {
		if _, ok := config.transforms[*s.Operation]; !ok {
			return nil, &Error{ErrMsg: "Invalid spec operation specified", ErrType: SpecError}
		}
	}
	j := Kazaam{spec: specString, specJSON: specElements, config: config}
	return &j, nil
}
func (k *Kazaam) getTransform(s *spec) TransformFunc {
	tform, _ := k.config.transforms[*s.Operation]
	return tform
}
func transformErrorType(err error) error {
	switch err.(type) {
	case transform.ParseError:
		return &Error{ErrMsg: err.Error(), ErrType: ParseError}
	case transform.RequireError:
		return &Error{ErrMsg: err.Error(), ErrType: RequireError}
	case transform.SpecError:
		return &Error{ErrMsg: err.Error(), ErrType: SpecError}
	default:
		return err
	}
}