github.com/oam-dev/kubevela@v1.9.11/pkg/cue/script/schema.go (about)

     1  /*
     2  Copyright 2022 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package script
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"strings"
    23  
    24  	"cuelang.org/go/cue"
    25  
    26  	"github.com/getkin/kin-openapi/openapi3"
    27  
    28  	"github.com/kubevela/workflow/pkg/cue/model/value"
    29  
    30  	"github.com/oam-dev/kubevela/pkg/appfile"
    31  	"github.com/oam-dev/kubevela/pkg/cue/process"
    32  	"github.com/oam-dev/kubevela/pkg/oam/util"
    33  	"github.com/oam-dev/kubevela/pkg/utils/common"
    34  )
    35  
    36  // ParsePropertiesToSchema parse the properties in cue script to the openapi schema
    37  // Read the template.parameter field
    38  func (c CUE) ParsePropertiesToSchema(templateFieldPath ...string) (*openapi3.Schema, error) {
    39  	val, err := c.ParseToValue()
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	var template *value.Value
    44  	if len(templateFieldPath) == 0 {
    45  		template = val
    46  	} else {
    47  		template, err = val.LookupValue(templateFieldPath...)
    48  		if err != nil {
    49  			return nil, fmt.Errorf("%w cue script: %s", err, c)
    50  		}
    51  	}
    52  	data, err := common.GenOpenAPI(template)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	schema, err := ConvertOpenAPISchema2SwaggerObject(data)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	FixOpenAPISchema("", schema)
    61  	return schema, nil
    62  }
    63  
    64  // ParsePropertiesToSchemaWithCueX parse the properties in cue script to the openapi schema
    65  // Read the template.parameter field
    66  func (c CUE) ParsePropertiesToSchemaWithCueX(templateFieldPath string) (*openapi3.Schema, error) {
    67  	val, err := c.ParseToValueWithCueX()
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	var template cue.Value
    72  	if len(templateFieldPath) == 0 {
    73  		template = val
    74  	} else {
    75  		template = val.LookupPath(cue.ParsePath(templateFieldPath))
    76  		if !template.Exists() {
    77  			return nil, fmt.Errorf("failed to lookup value: var(path=%s) not exist, cue script: %s", templateFieldPath, c)
    78  		}
    79  	}
    80  	data, err := common.GenOpenAPIWithCueX(template)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	schema, err := ConvertOpenAPISchema2SwaggerObject(data)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	FixOpenAPISchema("", schema)
    89  	return schema, nil
    90  }
    91  
    92  // FixOpenAPISchema fixes tainted `description` filed, missing of title `field`.
    93  func FixOpenAPISchema(name string, schema *openapi3.Schema) {
    94  	t := schema.Type
    95  	switch t {
    96  	case "object":
    97  		for k, v := range schema.Properties {
    98  			s := v.Value
    99  			FixOpenAPISchema(k, s)
   100  		}
   101  	case "array":
   102  		if schema.Items != nil {
   103  			FixOpenAPISchema("", schema.Items.Value)
   104  		}
   105  	}
   106  	if name != "" {
   107  		schema.Title = name
   108  	}
   109  
   110  	description := schema.Description
   111  	if strings.Contains(description, appfile.UsageTag) {
   112  		description = strings.Split(description, appfile.UsageTag)[1]
   113  	}
   114  	if strings.Contains(description, appfile.ShortTag) {
   115  		description = strings.Split(description, appfile.ShortTag)[0]
   116  		description = strings.TrimSpace(description)
   117  	}
   118  	schema.Description = description
   119  }
   120  
   121  // ConvertOpenAPISchema2SwaggerObject converts OpenAPI v2 JSON schema to Swagger Object
   122  func ConvertOpenAPISchema2SwaggerObject(data []byte) (*openapi3.Schema, error) {
   123  	swagger, err := openapi3.NewLoader().LoadFromData(data)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	schemaRef, ok := swagger.Components.Schemas[process.ParameterFieldName]
   129  	if !ok {
   130  		return nil, errors.New(util.ErrGenerateOpenAPIV2JSONSchemaForCapability)
   131  	}
   132  	return schemaRef.Value, nil
   133  }