-
Notifications
You must be signed in to change notification settings - Fork 278
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2101 from authzed/add-new-schema-package
Copy old schema package into new package
- Loading branch information
Showing
91 changed files
with
29,996 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
package compiler | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"google.golang.org/protobuf/proto" | ||
|
||
"github.com/authzed/spicedb/pkg/composableschemadsl/dslshape" | ||
"github.com/authzed/spicedb/pkg/composableschemadsl/input" | ||
"github.com/authzed/spicedb/pkg/composableschemadsl/parser" | ||
core "github.com/authzed/spicedb/pkg/proto/core/v1" | ||
) | ||
|
||
// InputSchema defines the input for a Compile. | ||
type InputSchema struct { | ||
// Source is the source of the schema being compiled. | ||
Source input.Source | ||
|
||
// Schema is the contents being compiled. | ||
SchemaString string | ||
} | ||
|
||
// SchemaDefinition represents an object or caveat definition in a schema. | ||
type SchemaDefinition interface { | ||
proto.Message | ||
|
||
GetName() string | ||
} | ||
|
||
// CompiledSchema is the result of compiling a schema when there are no errors. | ||
type CompiledSchema struct { | ||
// ObjectDefinitions holds the object definitions in the schema. | ||
ObjectDefinitions []*core.NamespaceDefinition | ||
|
||
// CaveatDefinitions holds the caveat definitions in the schema. | ||
CaveatDefinitions []*core.CaveatDefinition | ||
|
||
// OrderedDefinitions holds the object and caveat definitions in the schema, in the | ||
// order in which they were found. | ||
OrderedDefinitions []SchemaDefinition | ||
|
||
rootNode *dslNode | ||
mapper input.PositionMapper | ||
} | ||
|
||
// SourcePositionToRunePosition converts a source position to a rune position. | ||
func (cs CompiledSchema) SourcePositionToRunePosition(source input.Source, position input.Position) (int, error) { | ||
return cs.mapper.LineAndColToRunePosition(position.LineNumber, position.ColumnPosition, source) | ||
} | ||
|
||
type config struct { | ||
skipValidation bool | ||
objectTypePrefix *string | ||
} | ||
|
||
func SkipValidation() Option { return func(cfg *config) { cfg.skipValidation = true } } | ||
|
||
func ObjectTypePrefix(prefix string) ObjectPrefixOption { | ||
return func(cfg *config) { cfg.objectTypePrefix = &prefix } | ||
} | ||
|
||
func RequirePrefixedObjectType() ObjectPrefixOption { | ||
return func(cfg *config) { cfg.objectTypePrefix = nil } | ||
} | ||
|
||
func AllowUnprefixedObjectType() ObjectPrefixOption { | ||
return func(cfg *config) { cfg.objectTypePrefix = new(string) } | ||
} | ||
|
||
type Option func(*config) | ||
|
||
type ObjectPrefixOption func(*config) | ||
|
||
// Compile compilers the input schema into a set of namespace definition protos. | ||
func Compile(schema InputSchema, prefix ObjectPrefixOption, opts ...Option) (*CompiledSchema, error) { | ||
cfg := &config{} | ||
prefix(cfg) // required option | ||
|
||
for _, fn := range opts { | ||
fn(cfg) | ||
} | ||
|
||
mapper := newPositionMapper(schema) | ||
root := parser.Parse(createAstNode, schema.Source, schema.SchemaString).(*dslNode) | ||
errs := root.FindAll(dslshape.NodeTypeError) | ||
if len(errs) > 0 { | ||
err := errorNodeToError(errs[0], mapper) | ||
return nil, err | ||
} | ||
|
||
compiled, err := translate(translationContext{ | ||
objectTypePrefix: cfg.objectTypePrefix, | ||
mapper: mapper, | ||
schemaString: schema.SchemaString, | ||
skipValidate: cfg.skipValidation, | ||
}, root) | ||
if err != nil { | ||
var errorWithNode errorWithNode | ||
if errors.As(err, &errorWithNode) { | ||
err = toContextError(errorWithNode.error.Error(), errorWithNode.errorSourceCode, errorWithNode.node, mapper) | ||
} | ||
|
||
return nil, err | ||
} | ||
|
||
return compiled, nil | ||
} | ||
|
||
func errorNodeToError(node *dslNode, mapper input.PositionMapper) error { | ||
if node.GetType() != dslshape.NodeTypeError { | ||
return fmt.Errorf("given none error node") | ||
} | ||
|
||
errMessage, err := node.GetString(dslshape.NodePredicateErrorMessage) | ||
if err != nil { | ||
return fmt.Errorf("could not get error message for error node: %w", err) | ||
} | ||
|
||
errorSourceCode := "" | ||
if node.Has(dslshape.NodePredicateErrorSource) { | ||
es, err := node.GetString(dslshape.NodePredicateErrorSource) | ||
if err != nil { | ||
return fmt.Errorf("could not get error source for error node: %w", err) | ||
} | ||
|
||
errorSourceCode = es | ||
} | ||
|
||
return toContextError(errMessage, errorSourceCode, node, mapper) | ||
} | ||
|
||
func toContextError(errMessage string, errorSourceCode string, node *dslNode, mapper input.PositionMapper) error { | ||
sourceRange, err := node.Range(mapper) | ||
if err != nil { | ||
return fmt.Errorf("could not get range for error node: %w", err) | ||
} | ||
|
||
formattedRange, err := formatRange(sourceRange) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
source, err := node.GetString(dslshape.NodePredicateSource) | ||
if err != nil { | ||
return fmt.Errorf("missing source for node: %w", err) | ||
} | ||
|
||
return ErrorWithContext{ | ||
BaseCompilerError: BaseCompilerError{ | ||
error: fmt.Errorf("parse error in %s: %s", formattedRange, errMessage), | ||
BaseMessage: errMessage, | ||
}, | ||
SourceRange: sourceRange, | ||
Source: input.Source(source), | ||
ErrorSourceCode: errorSourceCode, | ||
} | ||
} | ||
|
||
func formatRange(rnge input.SourceRange) (string, error) { | ||
startLine, startCol, err := rnge.Start().LineAndColumn() | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return fmt.Sprintf("`%s`, line %v, column %v", rnge.Source(), startLine+1, startCol+1), nil | ||
} |
Oops, something went wrong.