Skip to content

feat: Implement use import#2919

Merged
tstirrat15 merged 4 commits intomainfrom
implement-use-import
Feb 26, 2026
Merged

feat: Implement use import#2919
tstirrat15 merged 4 commits intomainfrom
implement-use-import

Conversation

@tstirrat15
Copy link
Contributor

Description

Part of the puzzle of folding composableschemadsl into schemadsl. This implements import logic behind a use flag.

Changes

  • Port over code from composableschemadsl
  • Remove test from importer tests that asserted nonlocal use behavior (expiration-usage or whatever it's called)
  • Add test that asserts that import statements are disallowed in a schema written to WriteSchema
  • Fix that test

Testing

Review. See that tests pass.

@tstirrat15 tstirrat15 requested a review from a team as a code owner February 24, 2026 18:45
@github-actions github-actions bot added area/schema Affects the Schema Language area/api v1 Affects the v1 API area/tooling Affects the dev or user toolchain (e.g. tests, ci, build tools) labels Feb 24, 2026
@tstirrat15 tstirrat15 force-pushed the implement-use-import branch 3 times, most recently from 938d746 to b6a32f2 Compare February 24, 2026 18:51
Copy link
Contributor Author

@tstirrat15 tstirrat15 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments

var relationNotFoundError sharederrors.UnknownRelationError

var compilerError compiler.BaseCompilerError
var sourceError *spiceerrors.WithSourceError
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure this was wrong?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nvm it was right. I'm pretty confused as to why it is the way it is.

// Compile compilers the input schema into a set of namespace definition protos.
func Compile(schema InputSchema, prefix ObjectPrefixOption, opts ...Option) (*CompiledSchema, error) {
cfg := &config{
allowedFlags: mapz.NewSet[string](expirationFlag, selfFlag),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My LSP marked this as unnecessary

Comment on lines +270 to +271
opts := strings.Join(slices.Sorted(maps.Keys(lexer.Flags)), ", ")
p.emitErrorf("Unknown use flag: `%s`. Options are: %s", useFlag, opts)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Porting this over from composableschemadsl - should give us a stable output order.

},
},
{
"duplicate use of expiration pragmas",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uses should be declared per-file, and should be treated as file-local, so the compiler shouldn't take issue with having multiple of them in the same file.

Comment on lines +140 to +148
present, err := validateImportPresence(cfg.allowedFlags.Has(importFlag), root)
if err != nil {
// This condition should basically always be satisfied (we trigger errors off of the node),
// but we're defensive here in case the implementation changes.
var withNodeError withNodeError
if errors.As(err, &withNodeError) {
return nil, toContextError(withNodeError.Error(), withNodeError.errorSourceCode, withNodeError.node, mapper)
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is net-new - this is how we ensure that import compilation isn't attempted if it's disallowed.

}
}

if present {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then because we have information about whether imports are present, we can either run this or not - it's a small optimization but why not

@tstirrat15 tstirrat15 force-pushed the implement-use-import branch 2 times, most recently from 5619cfd to 47395a4 Compare February 24, 2026 20:14
@codecov
Copy link

codecov bot commented Feb 24, 2026

Codecov Report

❌ Patch coverage is 91.62304% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.49%. Comparing base (80b3228) to head (4a8d83c).

Files with missing lines Patch % Lines
pkg/schemadsl/compiler/importer.go 70.00% 4 Missing and 2 partials ⚠️
pkg/schemadsl/compiler/translator.go 89.84% 4 Missing and 2 partials ⚠️
pkg/schemadsl/compiler/node.go 40.00% 2 Missing and 1 partial ⚠️
pkg/schemadsl/compiler/compiler.go 98.12% 1 Missing ⚠️

❌ Your project check has failed because the head coverage (74.49%) is below the target coverage (75.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff             @@
##             main    #2919       +/-   ##
===========================================
+ Coverage   49.06%   74.49%   +25.44%     
===========================================
  Files         420      488       +68     
  Lines       54148    60397     +6249     
===========================================
+ Hits        26560    44989    +18429     
+ Misses      24871    12258    -12613     
- Partials     2717     3150      +433     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@@ -0,0 +1,2 @@
// caveat
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if i import a file that has one caveat, does it work? or is imports only for definitions 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imports is for anything - caveats, definitions, partials

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh ok; i don't think i've seen a test where the imports is for caveats

@@ -0,0 +1,8 @@
use import

import "definitions/user/user.zed"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have a test somewhere for a root with two imports, and both have the same definition sometype with different relations? it should error out

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but I can add that

@tstirrat15 tstirrat15 force-pushed the implement-use-import branch 4 times, most recently from cdfea10 to 6bc1e5e Compare February 26, 2026 14:59
}, compiler.AllowUnprefixedObjectType(),
compiler.SourceFolder(sourceFolder))

require.ErrorContains(t, err, "AAAAA")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤣

@tstirrat15 tstirrat15 force-pushed the implement-use-import branch 3 times, most recently from 86fa9b4 to 4a8d83c Compare February 26, 2026 16:05
@tstirrat15 tstirrat15 enabled auto-merge (squash) February 26, 2026 18:12
Copy link
Contributor

@barakmich barakmich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a few thoughts, mostly just positive comments

Comment on lines +66 to +73
func TestSchemaWriteImportsDisallowed(t *testing.T) {
conn, cleanup, _, _ := testserver.NewTestServer(require.New(t), 0, memdb.DisableGC, true, tf.EmptyDatastore)
t.Cleanup(cleanup)
client := v1.NewSchemaServiceClient(conn)

_, err := client.WriteSchema(t.Context(), &v1.WriteSchemaRequest{
Schema: `
use import
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct, in the context of the WriteSchema API -- however, I think that part of the overarching problem is that we don't have a WriteCompiledSchema API or similar


Every folder should have a `root.zed`. This is the target for compilation.

Every folder will have an `expected.zed`, which is the output of the compilation process.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The corollary to a WriteCompiledSchema API is that every folder would have a generated expected.proto. Again, farther in the future...


// In an import context, this is the FS containing
// the importing schema (as opposed to imported schemas)
sourceFS fs.FS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice use of fs.FS

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I ended up here accidentally 😅

Comment on lines +63 to +72
importerTests := []importerTest{
{"simple local import", "simple-local"},
{"simple local import with transitive hop", "simple-local-with-hop"},
{"nested local import", "nested-local"},
{"nested local import with transitive hop", "nested-local-with-hop"},
{"nested local two layers deep import", "nested-two-layer-local"},
{"diamond-shaped imports are fine", "diamond-shaped"},
{"multiple use directives are fine", "multiple-use-directives"},
{"many imports are correctly resolved", "many-imports"},
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're feeling saucy, this could be collected by walking the directory (and omitting the name field), but I don't feel strongly to do so either way.

It does match pkg/schemadsl/parser/parser_test.go though so there's that too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, and the other part is that I'd then need a convention for negative tests (of which there are two or three). I found that it was easier to be explicit.

@tstirrat15 tstirrat15 merged commit 68bc889 into main Feb 26, 2026
67 of 76 checks passed
@tstirrat15 tstirrat15 deleted the implement-use-import branch February 26, 2026 20:16
@github-actions github-actions bot locked and limited conversation to collaborators Feb 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area/api v1 Affects the v1 API area/schema Affects the Schema Language area/tooling Affects the dev or user toolchain (e.g. tests, ci, build tools)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants