diff --git a/pkg/composableschemadsl/compiler/importer-test/circular-import/root.zed b/pkg/composableschemadsl/compiler/importer-test/circular-import/root.zed index 13c9b0fbaa..b184555916 100644 --- a/pkg/composableschemadsl/compiler/importer-test/circular-import/root.zed +++ b/pkg/composableschemadsl/compiler/importer-test/circular-import/root.zed @@ -1,4 +1,4 @@ -from .subjects import user +import "subjects.zed" definition resource { relation viewer: user diff --git a/pkg/composableschemadsl/compiler/importer-test/circular-import/subjects.zed b/pkg/composableschemadsl/compiler/importer-test/circular-import/subjects.zed index 2b6888b9e3..3a717273f3 100644 --- a/pkg/composableschemadsl/compiler/importer-test/circular-import/subjects.zed +++ b/pkg/composableschemadsl/compiler/importer-test/circular-import/subjects.zed @@ -1,3 +1,3 @@ -from .user import user +import "user.zed" definition persona {} diff --git a/pkg/composableschemadsl/compiler/importer-test/circular-import/user.zed b/pkg/composableschemadsl/compiler/importer-test/circular-import/user.zed index 0547015612..0c94540c78 100644 --- a/pkg/composableschemadsl/compiler/importer-test/circular-import/user.zed +++ b/pkg/composableschemadsl/compiler/importer-test/circular-import/user.zed @@ -1,3 +1,3 @@ -from .subjects import persona +import "subjects.zed" definition user {} diff --git a/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/left.zed b/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/left.zed index 3d52abc77f..12cd2bec6b 100644 --- a/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/left.zed +++ b/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/left.zed @@ -1 +1 @@ -from .subjects import user +import "subjects.zed" diff --git a/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/right.zed b/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/right.zed index ee675dc7a9..12cd2bec6b 100644 --- a/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/right.zed +++ b/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/right.zed @@ -1 +1 @@ -from .subjects import persona +import "subjects.zed" diff --git a/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/root.zed b/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/root.zed index 0ade575e6d..33628ceb98 100644 --- a/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/root.zed +++ b/pkg/composableschemadsl/compiler/importer-test/diamond-shaped/root.zed @@ -1,5 +1,5 @@ -from .left import user -from .right import persona +import "left.zed" +import "right.zed" definition resource { relation viewer: user diff --git a/pkg/composableschemadsl/compiler/importer-test/escape-attempt/root.zed b/pkg/composableschemadsl/compiler/importer-test/escape-attempt/root.zed new file mode 100644 index 0000000000..52f0db9e61 --- /dev/null +++ b/pkg/composableschemadsl/compiler/importer-test/escape-attempt/root.zed @@ -0,0 +1 @@ +import "../user.zed" diff --git a/pkg/composableschemadsl/compiler/importer-test/nested-local-with-hop/root.zed b/pkg/composableschemadsl/compiler/importer-test/nested-local-with-hop/root.zed index b46fc85bd4..aec7d48a24 100644 --- a/pkg/composableschemadsl/compiler/importer-test/nested-local-with-hop/root.zed +++ b/pkg/composableschemadsl/compiler/importer-test/nested-local-with-hop/root.zed @@ -1,4 +1,4 @@ -from .transitive.transitive import user +import "transitive/transitive.zed" definition resource { relation viewer: user diff --git a/pkg/composableschemadsl/compiler/importer-test/nested-local-with-hop/transitive/transitive.zed b/pkg/composableschemadsl/compiler/importer-test/nested-local-with-hop/transitive/transitive.zed index 9e48edbbc6..b80bb01ea2 100644 --- a/pkg/composableschemadsl/compiler/importer-test/nested-local-with-hop/transitive/transitive.zed +++ b/pkg/composableschemadsl/compiler/importer-test/nested-local-with-hop/transitive/transitive.zed @@ -1 +1 @@ -from .user.user import user +import "user/user.zed" diff --git a/pkg/composableschemadsl/compiler/importer-test/nested-local/root.zed b/pkg/composableschemadsl/compiler/importer-test/nested-local/root.zed index 73ecf0a3a5..3582c1791f 100644 --- a/pkg/composableschemadsl/compiler/importer-test/nested-local/root.zed +++ b/pkg/composableschemadsl/compiler/importer-test/nested-local/root.zed @@ -1,4 +1,4 @@ -from .user.user import user +import "user/user.zed" definition resource { relation viewer: user diff --git a/pkg/composableschemadsl/compiler/importer-test/nested-two-layer-local/root.zed b/pkg/composableschemadsl/compiler/importer-test/nested-two-layer-local/root.zed index bd6130372b..9cfdeac16c 100644 --- a/pkg/composableschemadsl/compiler/importer-test/nested-two-layer-local/root.zed +++ b/pkg/composableschemadsl/compiler/importer-test/nested-two-layer-local/root.zed @@ -1,4 +1,4 @@ -from .definitions.user.user import user +import "definitions/user/user.zed" definition resource { relation viewer: user diff --git a/pkg/composableschemadsl/compiler/importer-test/simple-local-with-hop/indirection.zed b/pkg/composableschemadsl/compiler/importer-test/simple-local-with-hop/indirection.zed index a4b1c018cf..e7bd78fa22 100644 --- a/pkg/composableschemadsl/compiler/importer-test/simple-local-with-hop/indirection.zed +++ b/pkg/composableschemadsl/compiler/importer-test/simple-local-with-hop/indirection.zed @@ -1 +1 @@ -from .user import user +import "user.zed" diff --git a/pkg/composableschemadsl/compiler/importer-test/simple-local-with-hop/root.zed b/pkg/composableschemadsl/compiler/importer-test/simple-local-with-hop/root.zed index ee43f81792..93fb1d6929 100644 --- a/pkg/composableschemadsl/compiler/importer-test/simple-local-with-hop/root.zed +++ b/pkg/composableschemadsl/compiler/importer-test/simple-local-with-hop/root.zed @@ -1,4 +1,4 @@ -from .indirection import user +import "indirection.zed" definition resource { relation viewer: user diff --git a/pkg/composableschemadsl/compiler/importer-test/simple-local/root.zed b/pkg/composableschemadsl/compiler/importer-test/simple-local/root.zed index 321bccb119..1c4c687837 100644 --- a/pkg/composableschemadsl/compiler/importer-test/simple-local/root.zed +++ b/pkg/composableschemadsl/compiler/importer-test/simple-local/root.zed @@ -1,4 +1,4 @@ -from .user import user +import "user.zed" definition resource { relation viewer: user diff --git a/pkg/composableschemadsl/compiler/importer.go b/pkg/composableschemadsl/compiler/importer.go index 52ff29dbdd..7636af0166 100644 --- a/pkg/composableschemadsl/compiler/importer.go +++ b/pkg/composableschemadsl/compiler/importer.go @@ -5,6 +5,7 @@ import ( "os" "path" "path/filepath" + "strings" "github.com/rs/zerolog/log" @@ -13,23 +14,23 @@ import ( ) type importContext struct { - pathSegments []string + path string sourceFolder string names *mapz.Set[string] locallyVisitedFiles *mapz.Set[string] globallyVisitedFiles *mapz.Set[string] } -const SchemaFileSuffix = ".zed" - type CircularImportError struct { error filePath string } func importFile(importContext importContext) (*CompiledSchema, error) { - relativeFilepath := constructFilePath(importContext.pathSegments) - filePath := path.Join(importContext.sourceFolder, relativeFilepath) + if err := validateFilepath(importContext.path); err != nil { + return nil, err + } + filePath := path.Join(importContext.sourceFolder, importContext.path) newSourceFolder := filepath.Dir(filePath) @@ -84,6 +85,18 @@ func importFile(importContext importContext) (*CompiledSchema, error) { ) } -func constructFilePath(segments []string) string { - return path.Join(segments...) + SchemaFileSuffix +// Take a filepath and ensure that it's local to the current context. +func validateFilepath(path string) error { + if strings.Contains(path, "..") { + return fmt.Errorf("path %s contains '..'; paths must stay within their directory and this is likely an error", path) + } + // NOTE: This is slightly overly restrictive; it should theoretically be possible + // to take a given filepath and figure out whether it's local to the context where + // the compiler is being invoked, rather than whether it's local to the source + // folder of the current context. The assumption is that that won't matter + // right now, and we can fix it if we need to. + if !filepath.IsLocal(path) { + return fmt.Errorf("import path %s does not stay within its folder", path) + } + return nil } diff --git a/pkg/composableschemadsl/compiler/importer_test.go b/pkg/composableschemadsl/compiler/importer_test.go index 8708f6e520..f190774300 100644 --- a/pkg/composableschemadsl/compiler/importer_test.go +++ b/pkg/composableschemadsl/compiler/importer_test.go @@ -110,3 +110,23 @@ func TestImportCycleCausesError(t *testing.T) { require.ErrorContains(t, err, "circular import") } + +func TestEscapeAttemptCausesError(t *testing.T) { + t.Parallel() + + workingDir, err := os.Getwd() + require.NoError(t, err) + test := importerTest{"", "escape-attempt"} + + sourceFolder := path.Join(workingDir, test.relativePath()) + + inputSchema := test.input() + + _, err = compiler.Compile(compiler.InputSchema{ + Source: input.Source("schema"), + SchemaString: inputSchema, + }, compiler.AllowUnprefixedObjectType(), + compiler.SourceFolder(sourceFolder)) + + require.ErrorContains(t, err, "must stay within") +} diff --git a/pkg/composableschemadsl/compiler/translator.go b/pkg/composableschemadsl/compiler/translator.go index f59af778f6..5e0e6663ac 100644 --- a/pkg/composableschemadsl/compiler/translator.go +++ b/pkg/composableschemadsl/compiler/translator.go @@ -697,23 +697,14 @@ func addWithCaveats(tctx translationContext, typeRefNode *dslNode, ref *core.All } func translateImport(tctx translationContext, importNode *dslNode, names *mapz.Set[string]) (*CompiledSchema, error) { - // NOTE: this function currently just grabs everything that's in the target file. - // TODO: only grab the requested definitions - pathNodes := importNode.List(dslshape.NodeImportPredicatePathSegment) - pathSegments := make([]string, 0, len(pathNodes)) - - // Get the filepath segments out of the AST nodes - for _, pathSegmentNode := range pathNodes { - segment, err := pathSegmentNode.GetString(dslshape.NodeIdentiferPredicateValue) - if err != nil { - return nil, err - } - pathSegments = append(pathSegments, segment) + path, err := importNode.GetString(dslshape.NodeImportPredicatePath) + if err != nil { + return nil, err } compiledSchema, err := importFile(importContext{ names: names, - pathSegments: pathSegments, + path: path, sourceFolder: tctx.sourceFolder, globallyVisitedFiles: tctx.globallyVisitedFiles, locallyVisitedFiles: tctx.locallyVisitedFiles, diff --git a/pkg/composableschemadsl/dslshape/dslshape.go b/pkg/composableschemadsl/dslshape/dslshape.go index 1d5a480165..a9fd101bf5 100644 --- a/pkg/composableschemadsl/dslshape/dslshape.go +++ b/pkg/composableschemadsl/dslshape/dslshape.go @@ -194,8 +194,5 @@ const ( // // NodeTypeImport // - // TODO: still need to figure out what form this should take - full path? relative path? - NodeImportPredicateSource = "import-source" - NodeImportPredicatePathSegment = "path-segment" - NodeImportPredicateDefinitionName = "imported-definition" + NodeImportPredicatePath = "import-path" ) diff --git a/pkg/composableschemadsl/lexer/lex_def.go b/pkg/composableschemadsl/lexer/lex_def.go index 5e56ea49ec..6c5be862a7 100644 --- a/pkg/composableschemadsl/lexer/lex_def.go +++ b/pkg/composableschemadsl/lexer/lex_def.go @@ -78,7 +78,6 @@ var keywords = map[string]struct{}{ "permission": {}, "nil": {}, "with": {}, - "from": {}, "import": {}, "all": {}, "any": {}, diff --git a/pkg/composableschemadsl/lexer/lex_test.go b/pkg/composableschemadsl/lexer/lex_test.go index 6d40fa1eb9..eac715f836 100644 --- a/pkg/composableschemadsl/lexer/lex_test.go +++ b/pkg/composableschemadsl/lexer/lex_test.go @@ -62,7 +62,6 @@ var lexerTests = []lexerTest{ {"keyword", "permission", []Lexeme{{TokenTypeKeyword, 0, "permission", ""}, tEOF}}, {"keyword", "nil", []Lexeme{{TokenTypeKeyword, 0, "nil", ""}, tEOF}}, {"keyword", "with", []Lexeme{{TokenTypeKeyword, 0, "with", ""}, tEOF}}, - {"keyword", "from", []Lexeme{{TokenTypeKeyword, 0, "from", ""}, tEOF}}, {"keyword", "import", []Lexeme{{TokenTypeKeyword, 0, "import", ""}, tEOF}}, {"keyword", "all", []Lexeme{{TokenTypeKeyword, 0, "all", ""}, tEOF}}, {"keyword", "nil", []Lexeme{{TokenTypeKeyword, 0, "nil", ""}, tEOF}}, diff --git a/pkg/composableschemadsl/parser/parser.go b/pkg/composableschemadsl/parser/parser.go index 3fa95d402b..82a6903328 100644 --- a/pkg/composableschemadsl/parser/parser.go +++ b/pkg/composableschemadsl/parser/parser.go @@ -62,7 +62,7 @@ Loop: case p.isKeyword("caveat"): rootNode.Connect(dslshape.NodePredicateChild, p.consumeCaveat()) - case p.isKeyword("from"): + case p.isKeyword("import"): rootNode.Connect(dslshape.NodePredicateChild, p.consumeImport()) default: @@ -586,20 +586,6 @@ func (p *sourceParser) tryConsumeIdentifierLiteral() (AstNode, bool) { return identNode, true } -// consumeIdentifierLiteral is similar to the above, but attempts and errors -// rather than checking the token type beforehand -func (p *sourceParser) consumeIdentifierLiteral() (AstNode, bool) { - identNode := p.startNode(dslshape.NodeTypeIdentifier) - defer p.mustFinishNode() - - identifier, ok := p.consumeIdentifier() - if !ok { - return identNode, false - } - identNode.MustDecorate(dslshape.NodeIdentiferPredicateValue, identifier) - return identNode, true -} - func (p *sourceParser) tryConsumeNilExpression() (AstNode, bool) { if !p.isKeyword("nil") { return nil, false @@ -615,53 +601,17 @@ func (p *sourceParser) consumeImport() AstNode { importNode := p.startNode(dslshape.NodeTypeImport) defer p.mustFinishNode() - // from ... + // import ... // NOTE: error handling isn't necessary here because this function is only - // invoked if the `from` keyword is found in the function above. - p.consumeKeyword("from") - - // Consume alternating periods and identifiers - for { - if _, ok := p.consume(lexer.TokenTypePeriod); !ok { - return importNode - } - - segmentNode, ok := p.consumeIdentifierLiteral() - // We connect the node so that the error information is retained, then break the loop - // so that we aren't continuing to attempt to consume. - importNode.Connect(dslshape.NodeImportPredicatePathSegment, segmentNode) - if !ok { - break - } - - if !p.isToken(lexer.TokenTypePeriod) { - // If we don't have a period as our next token, we move - // to the next step of parsing. - break - } - } + // invoked if the `import` keyword is found in the function above. + p.consumeKeyword("import") - if ok := p.consumeKeyword("import"); !ok { + importPath, ok := p.consumeStringLiteral() + if !ok { return importNode } - // Consume alternating identifiers and commas until we reach the end of the import statement - for { - definitionNode, ok := p.consumeIdentifierLiteral() - // We connect the node so that the error information is retained, then break the loop - // so that we aren't continuing to attempt to consume. - importNode.Connect(dslshape.NodeImportPredicateDefinitionName, definitionNode) - if !ok { - break - } - - if _, ok := p.tryConsumeStatementTerminator(); ok { - break - } - if _, ok := p.consume(lexer.TokenTypeComma); !ok { - return importNode - } - } + importNode.MustDecorate(dslshape.NodeImportPredicatePath, importPath) return importNode } diff --git a/pkg/composableschemadsl/parser/parser_impl.go b/pkg/composableschemadsl/parser/parser_impl.go index 03b005faac..8e2be784b6 100644 --- a/pkg/composableschemadsl/parser/parser_impl.go +++ b/pkg/composableschemadsl/parser/parser_impl.go @@ -198,6 +198,37 @@ func (p *sourceParser) tryConsumeKeyword(keyword string) bool { return true } +// consumeString consumes a string token and returns the unwrapped string or adds an error node. +func (p *sourceParser) consumeStringLiteral() (string, bool) { + consumedString, ok := p.tryConsumeStringLiteral() + if !ok { + p.emitErrorf("Expected quote-delimited string, found token %v", p.currentToken.Kind) + return "", false + } + return consumedString, true +} + +// tryConsumeString attempts to consume an expected string token and return the unwrapped string. +func (p *sourceParser) tryConsumeStringLiteral() (string, bool) { + wrappedStringToken, ok := p.tryConsume(lexer.TokenTypeString) + if !ok { + return "", false + } + wrappedString := wrappedStringToken.Value + + // NOTE: We can't just trim here, because a user may use a combination of + // single and double quotes to escape. + // If we have a string wrapped in singlequotes (singular or plural), + // strip those specifically. + if strings.Index(wrappedString, `'`) == 0 { + return strings.Trim(wrappedString, `'`), true + } + + // Else strip doublequotes, because the set of string delimiters is limited + // by the lexer. + return strings.Trim(wrappedString, `"`), true +} + // consumeKeywords consumes any of a set of keywords or adds an error node func (p *sourceParser) consumeKeywords(keywords ...string) (string, bool) { keyword, ok := p.tryConsumeKeywords(keywords...) diff --git a/pkg/composableschemadsl/parser/parser_test.go b/pkg/composableschemadsl/parser/parser_test.go index 066e95408c..63aa4265e9 100644 --- a/pkg/composableschemadsl/parser/parser_test.go +++ b/pkg/composableschemadsl/parser/parser_test.go @@ -123,12 +123,11 @@ func TestParser(t *testing.T) { {"arrow illegal function test", "arrowillegalfunc"}, {"caveat with keyword parameter test", "caveatwithkeywordparam"}, {"local imports test", "localimport"}, + {"local imports with singlequotes on import test", "localimport_with_singlequotes"}, + {"local imports with quotes within quotes on import test", "localimport_with_quotes_in_quotes"}, + {"local imports with unterminated string on import test", "localimport_with_unterminated_string"}, + {"local imports with mismatched quotes on import test", "localimport_with_mismatched_quotes"}, {"local imports with keyword in import path test", "localimport_import_path_with_keyword"}, - {"local imports with keyword in identifiers test", "localimport_keyword_in_identifiers"}, - {"local imports with malformed identifiers set test", "localimport_malformed_identifier_set"}, - {"local imports with malformed import path test", "localimport_malformed_import_path"}, - {"local imports with path missing leading period test", "localimport_path_missing_leading_period"}, - {"local imports with typo in import separator test", "localimport_typo_in_import_separator"}, } for _, test := range parserTests { diff --git a/pkg/composableschemadsl/parser/tests/localimport.zed b/pkg/composableschemadsl/parser/tests/localimport.zed index 43f3c04786..b58fe4bada 100644 --- a/pkg/composableschemadsl/parser/tests/localimport.zed +++ b/pkg/composableschemadsl/parser/tests/localimport.zed @@ -1,4 +1,4 @@ -from .path.to.user import user, persona +import "path/to/user.zed" definition resource { relation user: user diff --git a/pkg/composableschemadsl/parser/tests/localimport.zed.expected b/pkg/composableschemadsl/parser/tests/localimport.zed.expected index 34ff6ac77a..ae9819a8c3 100644 --- a/pkg/composableschemadsl/parser/tests/localimport.zed.expected +++ b/pkg/composableschemadsl/parser/tests/localimport.zed.expected @@ -1,96 +1,70 @@ NodeTypeFile - end-rune = 155 + end-rune = 141 input-source = local imports test start-rune = 0 child-node => NodeTypeImport - end-rune = 39 + end-rune = 24 + import-path = path/to/user.zed input-source = local imports test start-rune = 0 - imported-definition => - NodeTypeIdentifier - end-rune = 29 - identifier-value = user - input-source = local imports test - start-rune = 26 - NodeTypeIdentifier - end-rune = 38 - identifier-value = persona - input-source = local imports test - start-rune = 32 - path-segment => - NodeTypeIdentifier - end-rune = 9 - identifier-value = path - input-source = local imports test - start-rune = 6 - NodeTypeIdentifier - end-rune = 12 - identifier-value = to - input-source = local imports test - start-rune = 11 - NodeTypeIdentifier - end-rune = 17 - identifier-value = user - input-source = local imports test - start-rune = 14 NodeTypeDefinition definition-name = resource - end-rune = 154 + end-rune = 140 input-source = local imports test - start-rune = 41 + start-rune = 27 child-node => NodeTypeRelation - end-rune = 85 + end-rune = 71 input-source = local imports test relation-name = user - start-rune = 67 + start-rune = 53 allowed-types => NodeTypeTypeReference - end-rune = 85 + end-rune = 71 input-source = local imports test - start-rune = 82 + start-rune = 68 type-ref-type => NodeTypeSpecificTypeReference - end-rune = 85 + end-rune = 71 input-source = local imports test - start-rune = 82 + start-rune = 68 type-name = user NodeTypeRelation - end-rune = 115 + end-rune = 101 input-source = local imports test relation-name = persona - start-rune = 91 + start-rune = 77 allowed-types => NodeTypeTypeReference - end-rune = 115 + end-rune = 101 input-source = local imports test - start-rune = 109 + start-rune = 95 type-ref-type => NodeTypeSpecificTypeReference - end-rune = 115 + end-rune = 101 input-source = local imports test - start-rune = 109 + start-rune = 95 type-name = persona NodeTypePermission - end-rune = 152 + end-rune = 138 input-source = local imports test relation-name = view - start-rune = 121 + start-rune = 107 compute-expression => NodeTypeUnionExpression - end-rune = 152 + end-rune = 138 input-source = local imports test - start-rune = 139 + start-rune = 125 left-expr => NodeTypeIdentifier - end-rune = 142 + end-rune = 128 identifier-value = user input-source = local imports test - start-rune = 139 + start-rune = 125 right-expr => NodeTypeIdentifier - end-rune = 152 + end-rune = 138 identifier-value = persona input-source = local imports test - start-rune = 146 \ No newline at end of file + start-rune = 132 \ No newline at end of file diff --git a/pkg/composableschemadsl/parser/tests/localimport_import_path_with_keyword.zed b/pkg/composableschemadsl/parser/tests/localimport_import_path_with_keyword.zed index 0cd749f17e..0cdb125abc 100644 --- a/pkg/composableschemadsl/parser/tests/localimport_import_path_with_keyword.zed +++ b/pkg/composableschemadsl/parser/tests/localimport_import_path_with_keyword.zed @@ -1,4 +1,4 @@ -from .path.definition.user import user, persona +import "path/definition/user.zed" definition resource { relation user: user diff --git a/pkg/composableschemadsl/parser/tests/localimport_import_path_with_keyword.zed.expected b/pkg/composableschemadsl/parser/tests/localimport_import_path_with_keyword.zed.expected index 3eaa12515d..af03ef4f37 100644 --- a/pkg/composableschemadsl/parser/tests/localimport_import_path_with_keyword.zed.expected +++ b/pkg/composableschemadsl/parser/tests/localimport_import_path_with_keyword.zed.expected @@ -1,50 +1,70 @@ NodeTypeFile - end-rune = 20 + end-rune = 149 input-source = local imports with keyword in import path test start-rune = 0 child-node => NodeTypeImport - end-rune = 10 + end-rune = 32 + import-path = path/definition/user.zed input-source = local imports with keyword in import path test start-rune = 0 + NodeTypeDefinition + definition-name = resource + end-rune = 148 + input-source = local imports with keyword in import path test + start-rune = 35 child-node => - NodeTypeError - end-rune = 10 - error-message = Expected keyword import, found token TokenTypeKeyword - error-source = definition - input-source = local imports with keyword in import path test - start-rune = 11 - path-segment => - NodeTypeIdentifier - end-rune = 9 - identifier-value = path + NodeTypeRelation + end-rune = 79 input-source = local imports with keyword in import path test - start-rune = 6 - NodeTypeIdentifier - end-rune = 10 + relation-name = user + start-rune = 61 + allowed-types => + NodeTypeTypeReference + end-rune = 79 + input-source = local imports with keyword in import path test + start-rune = 76 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 79 + input-source = local imports with keyword in import path test + start-rune = 76 + type-name = user + NodeTypeRelation + end-rune = 109 input-source = local imports with keyword in import path test - start-rune = 11 - child-node => - NodeTypeError - end-rune = 10 - error-message = Expected identifier, found token TokenTypeKeyword - error-source = definition + relation-name = persona + start-rune = 85 + allowed-types => + NodeTypeTypeReference + end-rune = 109 input-source = local imports with keyword in import path test - start-rune = 11 - NodeTypeDefinition - end-rune = 20 - input-source = local imports with keyword in import path test - start-rune = 11 - child-node => - NodeTypeError - end-rune = 20 - error-message = Expected identifier, found token TokenTypePeriod - error-source = . + start-rune = 103 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 109 + input-source = local imports with keyword in import path test + start-rune = 103 + type-name = persona + NodeTypePermission + end-rune = 146 input-source = local imports with keyword in import path test - start-rune = 21 - NodeTypeError - end-rune = 20 - error-message = Unexpected token at root level: TokenTypePeriod - error-source = . - input-source = local imports with keyword in import path test - start-rune = 21 \ No newline at end of file + relation-name = view + start-rune = 115 + compute-expression => + NodeTypeUnionExpression + end-rune = 146 + input-source = local imports with keyword in import path test + start-rune = 133 + left-expr => + NodeTypeIdentifier + end-rune = 136 + identifier-value = user + input-source = local imports with keyword in import path test + start-rune = 133 + right-expr => + NodeTypeIdentifier + end-rune = 146 + identifier-value = persona + input-source = local imports with keyword in import path test + start-rune = 140 \ No newline at end of file diff --git a/pkg/composableschemadsl/parser/tests/localimport_keyword_in_identifiers.zed.expected b/pkg/composableschemadsl/parser/tests/localimport_keyword_in_identifiers.zed.expected deleted file mode 100644 index 068371eeea..0000000000 --- a/pkg/composableschemadsl/parser/tests/localimport_keyword_in_identifiers.zed.expected +++ /dev/null @@ -1,114 +0,0 @@ -NodeTypeFile - end-rune = 154 - input-source = local imports with keyword in identifiers test - start-rune = 0 - child-node => - NodeTypeImport - end-rune = 30 - input-source = local imports with keyword in identifiers test - start-rune = 0 - imported-definition => - NodeTypeIdentifier - end-rune = 29 - identifier-value = user - input-source = local imports with keyword in identifiers test - start-rune = 26 - NodeTypeIdentifier - end-rune = 30 - input-source = local imports with keyword in identifiers test - start-rune = 32 - child-node => - NodeTypeError - end-rune = 30 - error-message = Expected identifier, found token TokenTypeKeyword - error-source = caveat - input-source = local imports with keyword in identifiers test - start-rune = 32 - path-segment => - NodeTypeIdentifier - end-rune = 9 - identifier-value = path - input-source = local imports with keyword in identifiers test - start-rune = 6 - NodeTypeIdentifier - end-rune = 12 - identifier-value = to - input-source = local imports with keyword in identifiers test - start-rune = 11 - NodeTypeIdentifier - end-rune = 17 - identifier-value = user - input-source = local imports with keyword in identifiers test - start-rune = 14 - NodeTypeCaveatDefinition - end-rune = 37 - input-source = local imports with keyword in identifiers test - start-rune = 32 - child-node => - NodeTypeError - end-rune = 37 - error-message = Expected identifier, found token TokenTypeSyntheticSemicolon - error-source = - - input-source = local imports with keyword in identifiers test - start-rune = 38 - NodeTypeDefinition - definition-name = resource - end-rune = 153 - input-source = local imports with keyword in identifiers test - start-rune = 40 - child-node => - NodeTypeRelation - end-rune = 84 - input-source = local imports with keyword in identifiers test - relation-name = user - start-rune = 66 - allowed-types => - NodeTypeTypeReference - end-rune = 84 - input-source = local imports with keyword in identifiers test - start-rune = 81 - type-ref-type => - NodeTypeSpecificTypeReference - end-rune = 84 - input-source = local imports with keyword in identifiers test - start-rune = 81 - type-name = user - NodeTypeRelation - end-rune = 114 - input-source = local imports with keyword in identifiers test - relation-name = persona - start-rune = 90 - allowed-types => - NodeTypeTypeReference - end-rune = 114 - input-source = local imports with keyword in identifiers test - start-rune = 108 - type-ref-type => - NodeTypeSpecificTypeReference - end-rune = 114 - input-source = local imports with keyword in identifiers test - start-rune = 108 - type-name = persona - NodeTypePermission - end-rune = 151 - input-source = local imports with keyword in identifiers test - relation-name = view - start-rune = 120 - compute-expression => - NodeTypeUnionExpression - end-rune = 151 - input-source = local imports with keyword in identifiers test - start-rune = 138 - left-expr => - NodeTypeIdentifier - end-rune = 141 - identifier-value = user - input-source = local imports with keyword in identifiers test - start-rune = 138 - right-expr => - NodeTypeIdentifier - end-rune = 151 - identifier-value = persona - input-source = local imports with keyword in identifiers test - start-rune = 145 \ No newline at end of file diff --git a/pkg/composableschemadsl/parser/tests/localimport_malformed_identifier_set.zed.expected b/pkg/composableschemadsl/parser/tests/localimport_malformed_identifier_set.zed.expected deleted file mode 100644 index 7ef947d008..0000000000 --- a/pkg/composableschemadsl/parser/tests/localimport_malformed_identifier_set.zed.expected +++ /dev/null @@ -1,102 +0,0 @@ -NodeTypeFile - end-rune = 147 - input-source = local imports with malformed identifiers set test - start-rune = 0 - child-node => - NodeTypeImport - end-rune = 30 - input-source = local imports with malformed identifiers set test - start-rune = 0 - imported-definition => - NodeTypeIdentifier - end-rune = 29 - identifier-value = user - input-source = local imports with malformed identifiers set test - start-rune = 26 - NodeTypeIdentifier - end-rune = 30 - input-source = local imports with malformed identifiers set test - start-rune = 33 - child-node => - NodeTypeError - end-rune = 30 - error-message = Expected identifier, found token TokenTypeKeyword - error-source = definition - input-source = local imports with malformed identifiers set test - start-rune = 33 - path-segment => - NodeTypeIdentifier - end-rune = 9 - identifier-value = path - input-source = local imports with malformed identifiers set test - start-rune = 6 - NodeTypeIdentifier - end-rune = 12 - identifier-value = to - input-source = local imports with malformed identifiers set test - start-rune = 11 - NodeTypeIdentifier - end-rune = 17 - identifier-value = user - input-source = local imports with malformed identifiers set test - start-rune = 14 - NodeTypeDefinition - definition-name = resource - end-rune = 146 - input-source = local imports with malformed identifiers set test - start-rune = 33 - child-node => - NodeTypeRelation - end-rune = 77 - input-source = local imports with malformed identifiers set test - relation-name = user - start-rune = 59 - allowed-types => - NodeTypeTypeReference - end-rune = 77 - input-source = local imports with malformed identifiers set test - start-rune = 74 - type-ref-type => - NodeTypeSpecificTypeReference - end-rune = 77 - input-source = local imports with malformed identifiers set test - start-rune = 74 - type-name = user - NodeTypeRelation - end-rune = 107 - input-source = local imports with malformed identifiers set test - relation-name = persona - start-rune = 83 - allowed-types => - NodeTypeTypeReference - end-rune = 107 - input-source = local imports with malformed identifiers set test - start-rune = 101 - type-ref-type => - NodeTypeSpecificTypeReference - end-rune = 107 - input-source = local imports with malformed identifiers set test - start-rune = 101 - type-name = persona - NodeTypePermission - end-rune = 144 - input-source = local imports with malformed identifiers set test - relation-name = view - start-rune = 113 - compute-expression => - NodeTypeUnionExpression - end-rune = 144 - input-source = local imports with malformed identifiers set test - start-rune = 131 - left-expr => - NodeTypeIdentifier - end-rune = 134 - identifier-value = user - input-source = local imports with malformed identifiers set test - start-rune = 131 - right-expr => - NodeTypeIdentifier - end-rune = 144 - identifier-value = persona - input-source = local imports with malformed identifiers set test - start-rune = 138 \ No newline at end of file diff --git a/pkg/composableschemadsl/parser/tests/localimport_malformed_import_path.zed.expected b/pkg/composableschemadsl/parser/tests/localimport_malformed_import_path.zed.expected deleted file mode 100644 index d7bf922abe..0000000000 --- a/pkg/composableschemadsl/parser/tests/localimport_malformed_import_path.zed.expected +++ /dev/null @@ -1,102 +0,0 @@ -NodeTypeFile - end-rune = 151 - input-source = local imports with malformed import path test - start-rune = 0 - child-node => - NodeTypeImport - end-rune = 35 - input-source = local imports with malformed import path test - start-rune = 0 - imported-definition => - NodeTypeIdentifier - end-rune = 25 - identifier-value = user - input-source = local imports with malformed import path test - start-rune = 22 - NodeTypeIdentifier - end-rune = 34 - identifier-value = persona - input-source = local imports with malformed import path test - start-rune = 28 - path-segment => - NodeTypeIdentifier - end-rune = 9 - identifier-value = path - input-source = local imports with malformed import path test - start-rune = 6 - NodeTypeIdentifier - end-rune = 12 - identifier-value = to - input-source = local imports with malformed import path test - start-rune = 11 - NodeTypeIdentifier - end-rune = 13 - input-source = local imports with malformed import path test - start-rune = 15 - child-node => - NodeTypeError - end-rune = 13 - error-message = Expected identifier, found token TokenTypeKeyword - error-source = import - input-source = local imports with malformed import path test - start-rune = 15 - NodeTypeDefinition - definition-name = resource - end-rune = 150 - input-source = local imports with malformed import path test - start-rune = 37 - child-node => - NodeTypeRelation - end-rune = 81 - input-source = local imports with malformed import path test - relation-name = user - start-rune = 63 - allowed-types => - NodeTypeTypeReference - end-rune = 81 - input-source = local imports with malformed import path test - start-rune = 78 - type-ref-type => - NodeTypeSpecificTypeReference - end-rune = 81 - input-source = local imports with malformed import path test - start-rune = 78 - type-name = user - NodeTypeRelation - end-rune = 111 - input-source = local imports with malformed import path test - relation-name = persona - start-rune = 87 - allowed-types => - NodeTypeTypeReference - end-rune = 111 - input-source = local imports with malformed import path test - start-rune = 105 - type-ref-type => - NodeTypeSpecificTypeReference - end-rune = 111 - input-source = local imports with malformed import path test - start-rune = 105 - type-name = persona - NodeTypePermission - end-rune = 148 - input-source = local imports with malformed import path test - relation-name = view - start-rune = 117 - compute-expression => - NodeTypeUnionExpression - end-rune = 148 - input-source = local imports with malformed import path test - start-rune = 135 - left-expr => - NodeTypeIdentifier - end-rune = 138 - identifier-value = user - input-source = local imports with malformed import path test - start-rune = 135 - right-expr => - NodeTypeIdentifier - end-rune = 148 - identifier-value = persona - input-source = local imports with malformed import path test - start-rune = 142 \ No newline at end of file diff --git a/pkg/composableschemadsl/parser/tests/localimport_path_missing_leading_period.zed b/pkg/composableschemadsl/parser/tests/localimport_path_missing_leading_period.zed deleted file mode 100644 index 45ddc27060..0000000000 --- a/pkg/composableschemadsl/parser/tests/localimport_path_missing_leading_period.zed +++ /dev/null @@ -1,7 +0,0 @@ -from path.to.user import user, persona - -definition resource { - relation user: user - relation persona: persona - permission view = user + persona -} diff --git a/pkg/composableschemadsl/parser/tests/localimport_path_missing_leading_period.zed.expected b/pkg/composableschemadsl/parser/tests/localimport_path_missing_leading_period.zed.expected deleted file mode 100644 index 1638642b68..0000000000 --- a/pkg/composableschemadsl/parser/tests/localimport_path_missing_leading_period.zed.expected +++ /dev/null @@ -1,22 +0,0 @@ -NodeTypeFile - end-rune = 3 - input-source = local imports with path missing leading period test - start-rune = 0 - child-node => - NodeTypeImport - end-rune = 3 - input-source = local imports with path missing leading period test - start-rune = 0 - child-node => - NodeTypeError - end-rune = 3 - error-message = Expected one of: [TokenTypePeriod], found: TokenTypeIdentifier - error-source = path - input-source = local imports with path missing leading period test - start-rune = 5 - NodeTypeError - end-rune = 3 - error-message = Unexpected token at root level: TokenTypeIdentifier - error-source = path - input-source = local imports with path missing leading period test - start-rune = 5 \ No newline at end of file diff --git a/pkg/composableschemadsl/parser/tests/localimport_typo_in_import_separator.zed b/pkg/composableschemadsl/parser/tests/localimport_typo_in_import_separator.zed deleted file mode 100644 index 79817cba19..0000000000 --- a/pkg/composableschemadsl/parser/tests/localimport_typo_in_import_separator.zed +++ /dev/null @@ -1,7 +0,0 @@ -from .path.to.user impoort user, persona - -definition resource { - relation user: user - relation persona: persona - permission view = user + persona -} diff --git a/pkg/composableschemadsl/parser/tests/localimport_typo_in_import_separator.zed.expected b/pkg/composableschemadsl/parser/tests/localimport_typo_in_import_separator.zed.expected deleted file mode 100644 index 8271c8c14e..0000000000 --- a/pkg/composableschemadsl/parser/tests/localimport_typo_in_import_separator.zed.expected +++ /dev/null @@ -1,38 +0,0 @@ -NodeTypeFile - end-rune = 17 - input-source = local imports with typo in import separator test - start-rune = 0 - child-node => - NodeTypeImport - end-rune = 17 - input-source = local imports with typo in import separator test - start-rune = 0 - child-node => - NodeTypeError - end-rune = 17 - error-message = Expected keyword import, found token TokenTypeIdentifier - error-source = impoort - input-source = local imports with typo in import separator test - start-rune = 19 - path-segment => - NodeTypeIdentifier - end-rune = 9 - identifier-value = path - input-source = local imports with typo in import separator test - start-rune = 6 - NodeTypeIdentifier - end-rune = 12 - identifier-value = to - input-source = local imports with typo in import separator test - start-rune = 11 - NodeTypeIdentifier - end-rune = 17 - identifier-value = user - input-source = local imports with typo in import separator test - start-rune = 14 - NodeTypeError - end-rune = 17 - error-message = Unexpected token at root level: TokenTypeIdentifier - error-source = impoort - input-source = local imports with typo in import separator test - start-rune = 19 \ No newline at end of file diff --git a/pkg/composableschemadsl/parser/tests/localimport_malformed_identifier_set.zed b/pkg/composableschemadsl/parser/tests/localimport_with_mismatched_quotes.zed similarity index 78% rename from pkg/composableschemadsl/parser/tests/localimport_malformed_identifier_set.zed rename to pkg/composableschemadsl/parser/tests/localimport_with_mismatched_quotes.zed index b3b46b1d28..8c2a6f5c68 100644 --- a/pkg/composableschemadsl/parser/tests/localimport_malformed_identifier_set.zed +++ b/pkg/composableschemadsl/parser/tests/localimport_with_mismatched_quotes.zed @@ -1,4 +1,4 @@ -from .path.to.user import user, +import "path/to/user.zed' definition resource { relation user: user diff --git a/pkg/composableschemadsl/parser/tests/localimport_with_mismatched_quotes.zed.expected b/pkg/composableschemadsl/parser/tests/localimport_with_mismatched_quotes.zed.expected new file mode 100644 index 0000000000..c82ef8eca9 --- /dev/null +++ b/pkg/composableschemadsl/parser/tests/localimport_with_mismatched_quotes.zed.expected @@ -0,0 +1,24 @@ +NodeTypeFile + end-rune = 5 + input-source = local imports with mismatched quotes on import test + start-rune = 0 + child-node => + NodeTypeImport + end-rune = 5 + input-source = local imports with mismatched quotes on import test + start-rune = 0 + child-node => + NodeTypeError + end-rune = 5 + error-message = Expected quote-delimited string, found token TokenTypeError + error-source = + + input-source = local imports with mismatched quotes on import test + start-rune = 7 + NodeTypeError + end-rune = 5 + error-message = Unexpected token at root level: TokenTypeError + error-source = + + input-source = local imports with mismatched quotes on import test + start-rune = 7 \ No newline at end of file diff --git a/pkg/composableschemadsl/parser/tests/localimport_with_quotes_in_quotes.zed b/pkg/composableschemadsl/parser/tests/localimport_with_quotes_in_quotes.zed new file mode 100644 index 0000000000..cf088b4bcd --- /dev/null +++ b/pkg/composableschemadsl/parser/tests/localimport_with_quotes_in_quotes.zed @@ -0,0 +1,9 @@ +// NOTE: this is mostly to validate parser behavior; this path +// would be treated as invalid by the compiler/importer. +import """path/to/'"user.zed""" + +definition resource { + relation user: user + relation persona: persona + permission view = user + persona +} diff --git a/pkg/composableschemadsl/parser/tests/localimport_with_quotes_in_quotes.zed.expected b/pkg/composableschemadsl/parser/tests/localimport_with_quotes_in_quotes.zed.expected new file mode 100644 index 0000000000..b3dc4d261b --- /dev/null +++ b/pkg/composableschemadsl/parser/tests/localimport_with_quotes_in_quotes.zed.expected @@ -0,0 +1,75 @@ +NodeTypeFile + end-rune = 267 + input-source = local imports with quotes within quotes on import test + start-rune = 0 + child-node => + NodeTypeImport + end-rune = 150 + import-path = path/to/'"user.zed + input-source = local imports with quotes within quotes on import test + start-rune = 120 + child-node => + NodeTypeComment + comment-value = // NOTE: this is mostly to validate parser behavior; this path + NodeTypeComment + comment-value = // would be treated as invalid by the compiler/importer. + NodeTypeDefinition + definition-name = resource + end-rune = 266 + input-source = local imports with quotes within quotes on import test + start-rune = 153 + child-node => + NodeTypeRelation + end-rune = 197 + input-source = local imports with quotes within quotes on import test + relation-name = user + start-rune = 179 + allowed-types => + NodeTypeTypeReference + end-rune = 197 + input-source = local imports with quotes within quotes on import test + start-rune = 194 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 197 + input-source = local imports with quotes within quotes on import test + start-rune = 194 + type-name = user + NodeTypeRelation + end-rune = 227 + input-source = local imports with quotes within quotes on import test + relation-name = persona + start-rune = 203 + allowed-types => + NodeTypeTypeReference + end-rune = 227 + input-source = local imports with quotes within quotes on import test + start-rune = 221 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 227 + input-source = local imports with quotes within quotes on import test + start-rune = 221 + type-name = persona + NodeTypePermission + end-rune = 264 + input-source = local imports with quotes within quotes on import test + relation-name = view + start-rune = 233 + compute-expression => + NodeTypeUnionExpression + end-rune = 264 + input-source = local imports with quotes within quotes on import test + start-rune = 251 + left-expr => + NodeTypeIdentifier + end-rune = 254 + identifier-value = user + input-source = local imports with quotes within quotes on import test + start-rune = 251 + right-expr => + NodeTypeIdentifier + end-rune = 264 + identifier-value = persona + input-source = local imports with quotes within quotes on import test + start-rune = 258 \ No newline at end of file diff --git a/pkg/composableschemadsl/parser/tests/localimport_malformed_import_path.zed b/pkg/composableschemadsl/parser/tests/localimport_with_singlequotes.zed similarity index 76% rename from pkg/composableschemadsl/parser/tests/localimport_malformed_import_path.zed rename to pkg/composableschemadsl/parser/tests/localimport_with_singlequotes.zed index e15bb6713f..d908efe19c 100644 --- a/pkg/composableschemadsl/parser/tests/localimport_malformed_import_path.zed +++ b/pkg/composableschemadsl/parser/tests/localimport_with_singlequotes.zed @@ -1,4 +1,4 @@ -from .path.to. import user, persona +import 'path/to/user.zed' definition resource { relation user: user diff --git a/pkg/composableschemadsl/parser/tests/localimport_with_singlequotes.zed.expected b/pkg/composableschemadsl/parser/tests/localimport_with_singlequotes.zed.expected new file mode 100644 index 0000000000..b8abb68b0b --- /dev/null +++ b/pkg/composableschemadsl/parser/tests/localimport_with_singlequotes.zed.expected @@ -0,0 +1,70 @@ +NodeTypeFile + end-rune = 141 + input-source = local imports with singlequotes on import test + start-rune = 0 + child-node => + NodeTypeImport + end-rune = 24 + import-path = path/to/user.zed + input-source = local imports with singlequotes on import test + start-rune = 0 + NodeTypeDefinition + definition-name = resource + end-rune = 140 + input-source = local imports with singlequotes on import test + start-rune = 27 + child-node => + NodeTypeRelation + end-rune = 71 + input-source = local imports with singlequotes on import test + relation-name = user + start-rune = 53 + allowed-types => + NodeTypeTypeReference + end-rune = 71 + input-source = local imports with singlequotes on import test + start-rune = 68 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 71 + input-source = local imports with singlequotes on import test + start-rune = 68 + type-name = user + NodeTypeRelation + end-rune = 101 + input-source = local imports with singlequotes on import test + relation-name = persona + start-rune = 77 + allowed-types => + NodeTypeTypeReference + end-rune = 101 + input-source = local imports with singlequotes on import test + start-rune = 95 + type-ref-type => + NodeTypeSpecificTypeReference + end-rune = 101 + input-source = local imports with singlequotes on import test + start-rune = 95 + type-name = persona + NodeTypePermission + end-rune = 138 + input-source = local imports with singlequotes on import test + relation-name = view + start-rune = 107 + compute-expression => + NodeTypeUnionExpression + end-rune = 138 + input-source = local imports with singlequotes on import test + start-rune = 125 + left-expr => + NodeTypeIdentifier + end-rune = 128 + identifier-value = user + input-source = local imports with singlequotes on import test + start-rune = 125 + right-expr => + NodeTypeIdentifier + end-rune = 138 + identifier-value = persona + input-source = local imports with singlequotes on import test + start-rune = 132 \ No newline at end of file diff --git a/pkg/composableschemadsl/parser/tests/localimport_keyword_in_identifiers.zed b/pkg/composableschemadsl/parser/tests/localimport_with_unterminated_string.zed similarity index 74% rename from pkg/composableschemadsl/parser/tests/localimport_keyword_in_identifiers.zed rename to pkg/composableschemadsl/parser/tests/localimport_with_unterminated_string.zed index 4c2e87c804..bbf56ecc75 100644 --- a/pkg/composableschemadsl/parser/tests/localimport_keyword_in_identifiers.zed +++ b/pkg/composableschemadsl/parser/tests/localimport_with_unterminated_string.zed @@ -1,4 +1,4 @@ -from .path.to.user import user, caveat +import "path/to/user.zed definition resource { relation user: user diff --git a/pkg/composableschemadsl/parser/tests/localimport_with_unterminated_string.zed.expected b/pkg/composableschemadsl/parser/tests/localimport_with_unterminated_string.zed.expected new file mode 100644 index 0000000000..801c234c30 --- /dev/null +++ b/pkg/composableschemadsl/parser/tests/localimport_with_unterminated_string.zed.expected @@ -0,0 +1,24 @@ +NodeTypeFile + end-rune = 5 + input-source = local imports with unterminated string on import test + start-rune = 0 + child-node => + NodeTypeImport + end-rune = 5 + input-source = local imports with unterminated string on import test + start-rune = 0 + child-node => + NodeTypeError + end-rune = 5 + error-message = Expected quote-delimited string, found token TokenTypeError + error-source = + + input-source = local imports with unterminated string on import test + start-rune = 7 + NodeTypeError + end-rune = 5 + error-message = Unexpected token at root level: TokenTypeError + error-source = + + input-source = local imports with unterminated string on import test + start-rune = 7 \ No newline at end of file