75 lines
2.3 KiB
Go
75 lines
2.3 KiB
Go
package apigen
|
|
|
|
import (
|
|
"fmt"
|
|
"git.yuntuo.hk/k2safe/go-omni/contract"
|
|
"golang.org/x/mod/module"
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
type ScalarDefinition struct {
|
|
Name, GoImport, GoType, JSONInput, JSONOutput, Position string
|
|
Text bool
|
|
}
|
|
|
|
func (p *parser) parseScalar() error {
|
|
pos := p.next().position
|
|
name, err := p.ident()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p.skip()
|
|
props, err := p.metadata()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d := ScalarDefinition{Name: name, Position: pos}
|
|
for key, value := range props {
|
|
switch key {
|
|
case "goImport":
|
|
d.GoImport = value
|
|
case "goType":
|
|
d.GoType = value
|
|
case "jsonInput":
|
|
d.JSONInput = value
|
|
case "jsonOutput":
|
|
d.JSONOutput = value
|
|
case "text":
|
|
if value != "true" && value != "false" {
|
|
return p.err("text must be true or false")
|
|
}
|
|
d.Text = value == "true"
|
|
default:
|
|
return fmt.Errorf("%s: unknown scalar property %s", pos, key)
|
|
}
|
|
}
|
|
p.spec.Scalars = append(p.spec.Scalars, d)
|
|
return nil
|
|
}
|
|
func compileScalars(spec *Spec, types map[string]Type) (map[string]reflect.Type, []contract.Scalar, error) {
|
|
out := map[string]reflect.Type{}
|
|
var defs []contract.Scalar
|
|
goTypes := map[string]bool{}
|
|
for _, d := range spec.Scalars {
|
|
key := d.GoImport + "." + d.GoType
|
|
if d.Name == "ContractScalars" || !exportedName.MatchString(d.Name) || !exportedName.MatchString(d.GoType) || out[d.Name] != nil || types[d.Name].Name != "" || goTypes[key] {
|
|
return nil, nil, fmt.Errorf("%s: scalar names and Go types must be unique; names must be UpperCamelCase", d.Position)
|
|
}
|
|
if err := module.CheckImportPath(d.GoImport); err != nil || strings.Contains(d.GoImport, "\\") {
|
|
return nil, nil, fmt.Errorf("%s: invalid scalar goImport", d.Position)
|
|
}
|
|
// Unique stand-in types allow CLI schema checks without executing project code.
|
|
t := reflect.StructOf([]reflect.StructField{{Name: d.Name, Type: reflect.TypeOf(false)}})
|
|
def := contract.Scalar{Type: t, JSONInput: d.JSONInput, JSONOutput: d.JSONOutput, Text: d.Text}
|
|
probe := reflect.StructOf([]reflect.StructField{{Name: "Value", Type: t, Tag: `json:"value"`}})
|
|
if _, err := contract.Describe(probe, def); err != nil {
|
|
return nil, nil, fmt.Errorf("%s: %w", d.Position, err)
|
|
}
|
|
out[d.Name] = t
|
|
defs = append(defs, def)
|
|
goTypes[key] = true
|
|
}
|
|
return out, defs, nil
|
|
}
|