Skip to content

Commit

Permalink
fix: populate schema positional information everywhere (#699)
Browse files Browse the repository at this point in the history
  • Loading branch information
alecthomas authored Dec 5, 2023
1 parent 1507bc8 commit c25f6f6
Show file tree
Hide file tree
Showing 10 changed files with 469 additions and 261 deletions.
2 changes: 1 addition & 1 deletion backend/schema/jsonschema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var jsonSchemaSample = &Schema{
{Name: "string", Type: &String{}, Comments: []string{"Field comment"}},
{Name: "int", Type: &Int{}},
{Name: "float", Type: &Float{}},
{Name: "optional", Type: &Optional{&String{}}},
{Name: "optional", Type: &Optional{Type: &String{}}},
{Name: "bool", Type: &Bool{}},
{Name: "time", Type: &Time{}},
{Name: "array", Type: &Array{Element: &String{}}},
Expand Down
2 changes: 1 addition & 1 deletion backend/schema/normalise.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package schema

// Normalise a Node.
// Normalise normalises (zeroes) positional information in schema Nodes.
func Normalise[T Node](n T) T {
var zero Position
var ni Node = n
Expand Down
33 changes: 27 additions & 6 deletions backend/schema/protobuf_dec.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,21 @@ func moduleListToSchema(s []*schemapb.Module) ([]*Module, error) {
return out, nil
}

func PosFromProto(pos *schemapb.Position) Position {
if pos == nil {
return Position{}
}
return Position{
Line: int(pos.Line),
Column: int(pos.Column),
Filename: pos.Filename,
}
}

// ModuleFromProto converts a protobuf Module to a Module and validates it.
func ModuleFromProto(s *schemapb.Module) (*Module, error) {
module := &Module{
Pos: PosFromProto(s.Pos),
Name: s.Name,
Comments: s.Comments,
Decls: declListToSchema(s.Decls),
Expand Down Expand Up @@ -73,6 +85,7 @@ func declListToSchema(s []*schemapb.Decl) []Decl {

func VerbToSchema(s *schemapb.Verb) *Verb {
return &Verb{
Pos: PosFromProto(s.Pos),
Name: s.Name,
Comments: s.Comments,
Request: dataRefToSchema(s.Request),
Expand All @@ -83,6 +96,7 @@ func VerbToSchema(s *schemapb.Verb) *Verb {

func DataToSchema(s *schemapb.Data) *Data {
return &Data{
Pos: PosFromProto(s.Pos),
Name: s.Name,
Fields: fieldListToSchema(s.Fields),
Comments: s.Comments,
Expand All @@ -99,6 +113,7 @@ func fieldListToSchema(s []*schemapb.Field) []*Field {

func fieldToSchema(s *schemapb.Field) *Field {
return &Field{
Pos: PosFromProto(s.Pos),
Name: s.Name,
Comments: s.Comments,
Type: typeToSchema(s.Type),
Expand All @@ -112,47 +127,51 @@ func typeToSchema(s *schemapb.Type) Type {
case *schemapb.Type_DataRef:
return dataRefToSchema(s.DataRef)
case *schemapb.Type_Int:
return &Int{}
return &Int{Pos: PosFromProto(s.Int.Pos)}
case *schemapb.Type_Float:
return &Float{}
return &Float{Pos: PosFromProto(s.Float.Pos)}
case *schemapb.Type_String_:
return &String{}
return &String{Pos: PosFromProto(s.String_.Pos)}
case *schemapb.Type_Time:
return &Time{}
return &Time{Pos: PosFromProto(s.Time.Pos)}
case *schemapb.Type_Bool:
return &Bool{}
return &Bool{Pos: PosFromProto(s.Bool.Pos)}
case *schemapb.Type_Array:
return arrayToSchema(s.Array)
case *schemapb.Type_Map:
return mapToSchema(s.Map)
case *schemapb.Type_Optional:
return &Optional{Type: typeToSchema(s.Optional.Type)}
return &Optional{Pos: PosFromProto(s.Optional.Pos), Type: typeToSchema(s.Optional.Type)}
}
panic("unreachable")
}

func verbRefToSchema(s *schemapb.VerbRef) *VerbRef {
return &VerbRef{
Pos: PosFromProto(s.Pos),
Name: s.Name,
Module: s.Module,
}
}

func dataRefToSchema(s *schemapb.DataRef) *DataRef {
return &DataRef{
Pos: PosFromProto(s.Pos),
Name: s.Name,
Module: s.Module,
}
}

func arrayToSchema(s *schemapb.Array) *Array {
return &Array{
Pos: PosFromProto(s.Pos),
Element: typeToSchema(s.Element),
}
}

func mapToSchema(s *schemapb.Map) *Map {
return &Map{
Pos: PosFromProto(s.Pos),
Key: typeToSchema(s.Key),
Value: typeToSchema(s.Value),
}
Expand All @@ -170,11 +189,13 @@ func metadataToSchema(s *schemapb.Metadata) Metadata {
switch s := s.Value.(type) {
case *schemapb.Metadata_Calls:
return &MetadataCalls{
Pos: PosFromProto(s.Calls.Pos),
Calls: verbRefListToSchema(s.Calls.Calls),
}

case *schemapb.Metadata_Ingress:
return &MetadataIngress{
Pos: PosFromProto(s.Ingress.Pos),
Method: s.Ingress.Method,
Path: s.Ingress.Path,
}
Expand Down
3 changes: 2 additions & 1 deletion backend/schema/protobuf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package schema
import (
"testing"

schemapb "github.com/TBD54566975/ftl/protos/xyz/block/ftl/v1/schema"
"github.com/alecthomas/assert/v2"

schemapb "github.com/TBD54566975/ftl/protos/xyz/block/ftl/v1/schema"
)

func TestProtoRoundtrip(t *testing.T) {
Expand Down
24 changes: 13 additions & 11 deletions backend/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,50 +61,52 @@ type Type interface {

// Optional represents a Type whose value may be optional.
type Optional struct {
Type Type `parser:"@@" protobuf:"1"`
Pos Position `parser:"" protobuf:"1,optional"`

Type Type `parser:"@@" protobuf:"2,optional"`
}

type Int struct {
Pos Position `parser:"" protobuf:"-"`
Pos Position `parser:"" protobuf:"1,optional"`

Int bool `parser:"@'Int'" protobuf:"-"`
}

type Float struct {
Pos Position `parser:"" protobuf:"-"`
Pos Position `parser:"" protobuf:"1,optional"`

Float bool `parser:"@'Float'" protobuf:"-"`
}

type String struct {
Pos Position `parser:"" protobuf:"-"`
Pos Position `parser:"" protobuf:"1,optional"`

Str bool `parser:"@'String'" protobuf:"-"`
}

type Bool struct {
Pos Position `parser:"" protobuf:"-"`
Pos Position `parser:"" protobuf:"1,optional"`

Bool bool `parser:"@'Bool'" protobuf:"-"`
}

type Time struct {
Pos Position `parser:"" protobuf:"-"`
Pos Position `parser:"" protobuf:"1,optional"`

Time bool `parser:"@'Time'" protobuf:"-"`
}

type Array struct {
Pos Position `parser:"" protobuf:"-"`
Pos Position `parser:"" protobuf:"1,optional"`

Element Type `parser:"'[' @@ ']'" protobuf:"1"`
Element Type `parser:"'[' @@ ']'" protobuf:"2"`
}

type Map struct {
Pos Position `parser:"" protobuf:"-"`
Pos Position `parser:"" protobuf:"1,optional"`

Key Type `parser:"'{' @@" protobuf:"1"`
Value Type `parser:"':' @@ '}'" protobuf:"2"`
Key Type `parser:"'{' @@" protobuf:"2"`
Value Type `parser:"':' @@ '}'" protobuf:"3"`
}

type Field struct {
Expand Down
2 changes: 1 addition & 1 deletion backend/schema/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var (
}
)

// Validate performs semantic validation of a schema.
// Validate normalises and performs semantic validation of a schema.
func Validate(schema *Schema) error {
modules := map[string]bool{}
verbs := map[string]bool{}
Expand Down
64 changes: 56 additions & 8 deletions frontend/src/protos/xyz/block/ftl/v1/schema/schema_pb.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c25f6f6

Please sign in to comment.