code/go/internal/specschema/folder_item_spec.go (138 lines of code) (raw):

// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one // or more contributor license agreements. Licensed under the Elastic License; // you may not use this file except in compliance with the Elastic License. package specschema import ( "fmt" "io/fs" "reflect" "github.com/creasty/defaults" "github.com/elastic/package-spec/v3/code/go/internal/spectypes" "github.com/elastic/package-spec/v3/code/go/pkg/specerrors" ) const ( visibilityTypePublic = "public" visibilityTypePrivate = "private" ) // ItemSpec implements the `spectype.ItemSpec` interface for a folder item spec. type ItemSpec struct { itemSpec *folderItemSpec } // MaxTotalContents is the maximum number of files and directories // inside a directory and its children directories. func (s *ItemSpec) MaxTotalContents() int { return s.itemSpec.SpecLimits.TotalContentsLimit } // MaxTotalSize is the maximum size of a file, or all the files and // directories inside a directory. func (s *ItemSpec) MaxTotalSize() spectypes.FileSize { return s.itemSpec.SpecLimits.TotalSizeLimit } // MaxFileSize is the maximum size of an individual file. func (s *ItemSpec) MaxFileSize() spectypes.FileSize { return s.itemSpec.SpecLimits.SizeLimit } // MaxConfigurationSize is the maximum size of a configuration file. func (s *ItemSpec) MaxConfigurationSize() spectypes.FileSize { return s.itemSpec.SpecLimits.ConfigurationSizeLimit } // MaxRelativePathSize is the maximum size of a file indicated with a relative path. func (s *ItemSpec) MaxRelativePathSize() spectypes.FileSize { return s.itemSpec.SpecLimits.RelativePathSizeLimit } // MaxFieldsPerDataStream is the maxumum number of fields that each data stream can define. func (s *ItemSpec) MaxFieldsPerDataStream() int { return s.itemSpec.SpecLimits.FieldsPerDataStreamLimit } // AdditionalContents returns true if the item can contain contents not defined in the spec. func (s *ItemSpec) AdditionalContents() bool { return s.itemSpec.AdditionalContents } // ContentMediaType returns the expected content type of a file. func (s *ItemSpec) ContentMediaType() *spectypes.ContentType { return s.itemSpec.ContentMediaType } // Contents returns the definitions of the children elements of this item. func (s *ItemSpec) Contents() []spectypes.ItemSpec { result := make([]spectypes.ItemSpec, len(s.itemSpec.Contents)) for i := range s.itemSpec.Contents { result[i] = &ItemSpec{s.itemSpec.Contents[i]} } return result } // DevelopmentFolder returns true if the item is inside a development folder. func (s *ItemSpec) DevelopmentFolder() bool { return s.itemSpec.DevelopmentFolder } // AllowLink returns true if the item allows links. func (s *ItemSpec) AllowLink() bool { return s.itemSpec.AllowLink } // ForbiddenPatterns returns the list of forbidden patterns for the name of this item. func (s *ItemSpec) ForbiddenPatterns() []string { return s.itemSpec.ForbiddenPatterns } // IsDir returns true if the item is a directory. func (s *ItemSpec) IsDir() bool { return s.itemSpec.ItemType == spectypes.ItemTypeFolder } // Name returns the name of the item inside its parent. func (s *ItemSpec) Name() string { return s.itemSpec.Name } // Pattern returns the allowed pattern for the name of this item. func (s *ItemSpec) Pattern() string { return s.itemSpec.Pattern } // Release returns 'beta' if the item definition is in beta stage. func (s *ItemSpec) Release() string { return s.itemSpec.Release } // Required returns true if this item must be defined. func (s *ItemSpec) Required() bool { return s.itemSpec.Required } // Type returns the type of file ('file' or 'folder'). func (s *ItemSpec) Type() string { return s.itemSpec.ItemType } // ValidateSchema validates if the indicated file complies with the schema of the item. func (s *ItemSpec) ValidateSchema(fsys fs.FS, itemPath string) specerrors.ValidationErrors { return s.itemSpec.ValidateSchema(fsys, itemPath) } type folderItemSpec struct { Description string `json:"description" yaml:"description"` ItemType string `json:"type" yaml:"type"` ContentMediaType *spectypes.ContentType `json:"contentMediaType" yaml:"contentMediaType"` ForbiddenPatterns []string `json:"forbiddenPatterns" yaml:"forbiddenPatterns"` Name string `json:"name" yaml:"name"` Pattern string `json:"pattern" yaml:"pattern"` Required bool `json:"required" yaml:"required"` Ref string `json:"$ref" yaml:"$ref"` Visibility string `json:"visibility" yaml:"visibility" default:"public"` AdditionalContents bool `json:"additionalContents" yaml:"additionalContents"` Contents []*folderItemSpec `json:"contents" yaml:"contents"` DevelopmentFolder bool `json:"developmentFolder" yaml:"developmentFolder"` AllowLink bool `json:"allowLink" yaml:"allowLink"` // As it is required to be inline both in yaml and json, this struct must be public embedded field SpecLimits `yaml:",inline"` // Release type of the spec: beta, ga. // Packages using beta features won't be able to go GA. // Default release: ga Release string `json:"release" yaml:"release"` schema spectypes.FileSchema } func (s *folderItemSpec) setDefaultValues() error { err := defaults.Set(s) if err != nil { return fmt.Errorf("could not set default values: %w", err) } for _, content := range s.Contents { err = content.setDefaultValues() if err != nil { return err } } return nil } func (s *folderItemSpec) propagateContentLimits() { for _, content := range s.Contents { content.SpecLimits.update(s.SpecLimits) content.propagateContentLimits() } } // SpecLimits represents limits related to an item type SpecLimits struct { // Limit to the total number of elements in a directory. TotalContentsLimit int `json:"totalContentsLimit" yaml:"totalContentsLimit"` // Limit to the total size of files in a directory. TotalSizeLimit spectypes.FileSize `json:"totalSizeLimit" yaml:"totalSizeLimit"` // Limit to individual files. SizeLimit spectypes.FileSize `json:"sizeLimit" yaml:"sizeLimit"` // Limit to individual configuration files (yaml files). ConfigurationSizeLimit spectypes.FileSize `json:"configurationSizeLimit" yaml:"configurationSizeLimit"` // Limit to files referenced as relative paths (images). RelativePathSizeLimit spectypes.FileSize `json:"relativePathSizeLimit" yaml:"relativePathSizeLimit"` // Maximum number of fields per data stream, can only be set at the root level spec. FieldsPerDataStreamLimit int `json:"fieldsPerDataStreamLimit" yaml:"fieldsPerDataStreamLimit"` } func (l *SpecLimits) update(o SpecLimits) { target := reflect.ValueOf(l).Elem() source := reflect.ValueOf(&o).Elem() for i := 0; i < target.NumField(); i++ { field := target.Field(i) if field.IsZero() { field.Set(source.Field(i)) } } } func (s *folderItemSpec) ValidateSchema(fsys fs.FS, itemPath string) specerrors.ValidationErrors { if s.schema == nil { return nil } return s.schema.Validate(fsys, itemPath) }