Skip to content

Conversation

@mwillbanks
Copy link
Contributor

@mwillbanks mwillbanks commented Dec 29, 2025

provides a means to alias collections in @@allow collections by extending the ast this allows for utilizing collections inside of @@allow like:

@@allow(
memberships?[m,
    auth().memberships?[
        tenantId == m.tenantId ...
    ]
  ]
)

Summary by CodeRabbit

  • New Features

    • Iterator bindings supported inside collection predicates, enabling use of iterator variables in predicate expressions.
    • Expression evaluation and transformation now carry iterator bindings through nested evaluations for correct predicate semantics.
  • Bug Fixes

    • Improved validation and resolution to safely handle malformed or complex reference expressions, preventing undefined names from leaking.
  • Tests

    • Added end-to-end and unit tests covering iterator-bound and unbound collection predicate syntax.

✏️ Tip: You can customize this high-level summary in your review settings.

provides a means to alias collections in @@Allow collections by extending the ast
this allows for utilizing collections inside of @@Allow like:

```
memberships?[m,
    auth().memberships?[
        tenantId == m.tenantId ...
    ]
  ]
```
Copilot AI review requested due to automatic review settings December 29, 2025 17:04
@coderabbitai
Copy link

coderabbitai bot commented Dec 29, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds optional iterator bindings for collection-predicate binary expressions and threads that binding through grammar, AST types, scope/linking, code generation, evaluation, transformation, SDK generators, and tests.

Changes

Cohort / File(s) Summary
AST & Schema Types
packages/language/src/ast.ts, packages/schema/src/expression.ts, packages/schema/src/expression-utils.ts
Added optional binding?: string to BinaryExpr/BinaryExpression and updated ExpressionUtils.binary(...) to accept/propagate the binding.
Grammar
packages/language/src/zmodel.langium
Extended ReferenceTarget union to include BinaryExpr and changed CollectionPredicateExpr to parse optional (binding=RegularID ',')? before the right expression.
Validators
packages/language/src/validators/attribute-application-validator.ts
Defensive extraction from AST lists when validating attribute targets; filters non-ReferenceExpr items and guards against missing names.
Scope & Linking
packages/language/src/zmodel-scope.ts, packages/language/src/zmodel-linker.ts
Treat binary expressions as collection-predicate targets in member-access resolution and linking; added createScopeForCollectionElement helper and use binding in node descriptions / resolved names; guards on falsy types.
Code Generation
packages/language/src/zmodel-code-generator.ts, packages/sdk/src/ts-schema-generator.ts
Emit collection predicates that include optional binding inside brackets; createBinaryExpression now passes binding into ExpressionUtils.binary.
SDK Prisma Generator
packages/sdk/src/prisma/prisma-schema-generator.ts
When emitting reference args, resolve refName from target.name or fallback to target.binding for binary targets; throw if unresolved.
Plugins — Transformer & Evaluator
packages/plugins/policy/src/expression-transformer.ts, packages/plugins/policy/src/expression-evaluator.ts
Added BindingScope type and threaded an optional scope/binding map through transformation and evaluation; evaluator uses scope entries for field access and supplies binding as item variable during collection predicate evaluation.
Tests / E2E
packages/language/test/expression-validation.test.ts, tests/e2e/orm/policy/auth-access.test.ts
Added unit tests for bound and unbound collection-predicate syntax and an e2e auth test verifying iterator-binding semantics in policies.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped into brackets, small and neat,
Named a little iterator to keep things sweet,
Scopes now carry my tiny token,
Generators and links stay unbroken,
Hooray — predicates bound and complete!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'feat: audit policy collection aliases' is vague and does not accurately reflect the primary changes, which implement iterator binding support for collection predicates in access policies, not a feature for auditing. Revise the title to clearly describe the feature being added, such as 'feat: add iterator binding support for collection predicates in access policies' or 'feat: support aliasing collection elements in policy expressions'.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/language/src/zmodel-scope.ts (1)

211-241: Reorder match cases to check isAuthInvocation before isInvocationExpr.

The isAuthInvocation check (line 237) is unreachable because isAuthInvocation is defined as isInvocationExpr(node) && node.function.ref?.name === 'auth' && isFromStdlib(node.function.ref) (utils.ts line 69). Since auth() invocations match isInvocationExpr first, they are handled by the generic invocation branch (lines 229-236), which attempts to access expr.function.ref?.returnType that may not exist for auth(). Move the isAuthInvocation check before isInvocationExpr to ensure auth() is routed to the correct handler.

🧹 Nitpick comments (2)
packages/language/test/expression-validation.test.ts (1)

102-144: Good test coverage for the new binding syntax.

Both tests appropriately validate the new iterator binding syntax and backward compatibility with the existing unbound syntax. The schema structures are valid with proper model relationships.

Consider adding negative test cases in a follow-up to validate error handling when:

  • The binding variable shadows an existing field name
  • The binding is used outside its scope (e.g., outside the collection predicate where it's defined)
packages/language/src/validators/attribute-application-validator.ts (1)

494-503: Improved defensive extraction of field types.

The refactoring adds proper guards for isReferenceExpr and safely handles missing or non-string names, which aligns with the broader AST changes that now include BinaryExpr as a possible ReferenceTarget.

Consider using a more explicit type check instead of (ref as any).name for better type safety:

🔎 Suggested improvement
         const ref = item.target.ref;
-        return ref && 'name' in ref ? (ref as any).name : undefined;
+        return ref && 'name' in ref && typeof (ref as { name?: unknown }).name === 'string'
+            ? (ref as { name: string }).name
+            : undefined;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be330ff and cb54db6.

⛔ Files ignored due to path filters (2)
  • packages/language/src/generated/ast.ts is excluded by !**/generated/**
  • packages/language/src/generated/grammar.ts is excluded by !**/generated/**
📒 Files selected for processing (12)
  • packages/language/src/ast.ts
  • packages/language/src/validators/attribute-application-validator.ts
  • packages/language/src/zmodel-code-generator.ts
  • packages/language/src/zmodel-linker.ts
  • packages/language/src/zmodel-scope.ts
  • packages/language/src/zmodel.langium
  • packages/language/test/expression-validation.test.ts
  • packages/plugins/policy/src/expression-evaluator.ts
  • packages/plugins/policy/src/expression-transformer.ts
  • packages/schema/src/expression-utils.ts
  • packages/schema/src/expression.ts
  • packages/sdk/src/prisma/prisma-schema-generator.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/e2e/**/*.{ts,tsx} : E2E tests should validate real-world schema compatibility with established projects

Applied to files:

  • packages/language/test/expression-validation.test.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/**/type*.{ts,tsx} : Ensure TypeScript inference and type coverage are validated through type coverage tests

Applied to files:

  • packages/language/test/expression-validation.test.ts
🧬 Code graph analysis (8)
packages/language/src/zmodel-code-generator.ts (1)
packages/language/src/utils.ts (1)
  • isCollectionPredicate (466-468)
packages/plugins/policy/src/expression-transformer.ts (1)
packages/schema/src/expression-utils.ts (1)
  • ExpressionUtils (19-124)
packages/language/test/expression-validation.test.ts (1)
packages/language/test/utils.ts (1)
  • loadSchema (10-21)
packages/language/src/validators/attribute-application-validator.ts (1)
packages/language/src/generated/ast.ts (3)
  • ArrayExpr (185-189)
  • ArrayExpr (191-191)
  • isReferenceExpr (698-700)
packages/language/src/zmodel-scope.ts (3)
packages/language/src/generated/ast.ts (3)
  • isBinaryExpr (267-269)
  • Expression (115-115)
  • Expression (117-117)
packages/language/src/utils.ts (1)
  • isCollectionPredicate (466-468)
packages/schema/src/expression.ts (1)
  • Expression (1-10)
packages/sdk/src/prisma/prisma-schema-generator.ts (1)
packages/language/src/generated/ast.ts (1)
  • isBinaryExpr (267-269)
packages/language/src/zmodel-linker.ts (1)
packages/language/src/generated/ast.ts (7)
  • isBinaryExpr (267-269)
  • EnumField (437-443)
  • EnumField (445-445)
  • DataField (334-341)
  • DataField (343-343)
  • FunctionParam (480-486)
  • FunctionParam (488-488)
packages/language/src/ast.ts (1)
packages/language/src/generated/ast.ts (2)
  • BinaryExpr (256-263)
  • BinaryExpr (265-265)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Agent
  • GitHub Check: build-test (22.x, sqlite)
  • GitHub Check: build-test (22.x, postgresql)
🔇 Additional comments (21)
packages/language/src/ast.ts (1)

49-54: LGTM!

The module augmentation for BinaryExpr.binding is consistent with existing patterns in this file (e.g., AttributeArg.$resolvedParam) and correctly extends the generated AST type to support the optional iterator binding for collection predicates.

packages/schema/src/expression.ts (1)

39-45: LGTM!

The optional binding property is correctly added to BinaryExpression, maintaining consistency with the AST-level changes and preserving backward compatibility for non-collection-predicate binary expressions.

packages/language/src/zmodel-code-generator.ts (1)

255-263: LGTM!

The code generator correctly handles the optional binding in collection predicates, producing [binding, expr] when a binding exists and [expr] otherwise. This aligns with the grammar definition in zmodel.langium.

packages/language/src/zmodel.langium (1)

69-69: LGTM!

The grammar changes correctly implement the collection alias feature:

  • Adding BinaryExpr to ReferenceTarget enables the linker to resolve references to binding variables
  • The optional binding syntax (binding=RegularID ',')? cleanly supports both collection?[binding, expr] and the existing collection?[expr] forms

Also applies to: 112-117

packages/sdk/src/prisma/prisma-schema-generator.ts (1)

355-367: Correct handling of BinaryExpr targets in Prisma schema generation.

The logic properly resolves reference names from either the standard name property or the binding property for BinaryExpr targets. The error handling for unsupported targets is appropriate.

One minor observation: the non-null assertion node.target.ref! on line 356 could theoretically fail if the reference is unresolved. Consider whether a guard is warranted here, though it may be acceptable if the caller guarantees resolution.

packages/language/src/zmodel-linker.ts (3)

125-126: LGTM!

The fallback chain target.name ?? target.binding ?? reference.$refText correctly handles the three cases: named targets (DataField, FunctionParam, EnumField), binding targets (BinaryExpr for collection predicates), and a final fallback to the reference text.


254-274: Correct type resolution for collection predicate bindings.

The new resolution logic properly handles BinaryExpr targets representing collection predicates:

  • It extracts the element type from the collection's left operand (collectionType.decl)
  • Sets array: false since the binding refers to a single element during iteration
  • Preserves nullable from the collection type

The operator check ['?', '!', '^'] correctly matches the collection predicate operators defined in the grammar and isCollectionPredicate utility.


522-525: Good defensive guard.

The early return for missing type prevents potential runtime errors when resolveToDeclaredType is called with an undefined type parameter.

packages/plugins/policy/src/expression-evaluator.ts (3)

18-18: LGTM: Scope addition to context type.

The optional scope property enables binding propagation during expression evaluation, which aligns with the PR's goal of supporting collection aliases.


67-72: LGTM: Scope-first field resolution.

Prioritizing scope lookup over thisValue ensures that bound aliases (e.g., m in memberships?[m, ...]) correctly resolve to the bound item rather than the current context value.


119-155: LGTM: Consistent scope propagation across all collection operators.

All three operators (?, !, ^) correctly propagate the binding into the scope when evaluating the right-hand side. The scope spreading pattern with nullish coalescing handles the case where no prior scope exists.

One minor consideration: if expr.binding shadows an existing key in context.scope, the inner binding takes precedence, which is the expected shadowing behavior for nested scopes.

packages/schema/src/expression-utils.ts (1)

42-50: LGTM: Backward-compatible extension of binary factory.

The optional binding parameter is correctly threaded through to the resulting BinaryExpression. This is backward compatible since existing callers can continue omitting the parameter.

Note: When binding is undefined, the property is still present on the object (as binding: undefined). This should be fine since downstream consumers check for truthiness (if (expr.binding)), but verify this doesn't cause issues with serialization or strict property checks.

packages/plugins/policy/src/expression-transformer.ts (6)

61-61: LGTM: Well-structured binding scope type.

The BindingScope type elegantly captures the dual nature of bindings:

  • type and alias for SQL-based transformations (relation joins)
  • value for value-based evaluations

This separation enables the transformer to handle both code paths correctly.


319-324: LGTM: Scope propagation to evaluator.

The getEvaluationScope helper correctly extracts only the value-bearing entries from the binding scope, matching the simpler Record<string, any> expected by ExpressionEvaluator.


359-371: LGTM: Binding scope construction for relation-based predicates.

When transforming collection predicates that operate on relations (not values), the binding scope correctly captures type and alias for the bound element. The alias defaults to the model name, enabling proper SQL column references.


425-438: LGTM: Binding scope construction for value-based predicates.

For value-based collection predicates (e.g., auth().memberships), the binding scope correctly captures the value of each item, enabling nested predicates to access the bound element's data.


880-893: LGTM: Evaluation scope extraction.

The helper correctly filters the binding scope to only include entries with defined value properties, returning undefined when empty. This ensures the evaluator receives a clean scope without type-only entries.


628-645: Verify rewritten context consistency — Already correctly implemented.

The code properly distinguishes between value-based and relation-based bindings. When bindingReceiver.value is undefined (relation-based), the expression is rewritten to use this and contextValue is passed as undefined through the recursive call. The subsequent if (ExpressionUtils.isThis(expr.receiver)) block at line 670 explicitly sets contextValue: undefined when delegating to relation access (line 678). Downstream code consistently checks if (context.contextValue) before treating expressions as value objects (lines 177, 283, 312), ensuring relation-based bindings follow the SQL join path rather than value evaluation.

packages/language/src/zmodel-scope.ts (3)

10-10: LGTM: Required import for StreamScope construction.

The stream function import is needed to construct the StreamScope with the binding description.


151-153: LGTM: Collection predicate handling in member access scope.

When a reference target is a BinaryExpr representing a collection predicate (e.g., accessing m.tenantId where m is bound to a collection predicate), this correctly delegates to createScopeForCollectionElement to resolve the element type's fields.


197-209: LGTM: Binding description injection into scope.

When a collection predicate has a binding, a description is created and added to a StreamScope that wraps the collection scope. This enables the binding identifier (e.g., m) to be resolved as a reference target, pointing to the BinaryExpr itself.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces support for aliasing collection elements in @@allow policy expressions, enabling more expressive access control rules. The new syntax allows binding an iterator variable to collection elements (e.g., memberships?[m, m.tenantId == id]), making it easier to reference collection items in nested predicates.

Key changes:

  • Extended the grammar to support optional iterator bindings in collection predicate syntax
  • Updated the AST to include a binding property on BinaryExpr nodes for collection predicates
  • Enhanced the expression transformer and evaluator to properly handle scoped bindings throughout policy evaluation

Reviewed changes

Copilot reviewed 12 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/language/src/zmodel.langium Added optional binding parameter (binding=RegularID ',')? to collection predicate syntax
packages/language/src/generated/ast.ts Updated AST type definitions to include BinaryExpr as a ReferenceTarget and added binding property
packages/language/src/ast.ts Added TypeScript interface extension for BinaryExpr with optional binding property and documentation
packages/language/src/generated/grammar.ts Generated grammar implementation reflecting the new binding syntax
packages/schema/src/expression.ts Added optional binding field to BinaryExpression type
packages/schema/src/expression-utils.ts Extended binary utility function to accept optional binding parameter
packages/language/src/zmodel-scope.ts Enhanced scope provider to create scope entries for collection predicate bindings and support BinaryExpr in collection element resolution
packages/language/src/zmodel-linker.ts Updated linker to handle BinaryExpr as a ReferenceTarget and resolve types for bound collection predicates
packages/language/src/zmodel-code-generator.ts Modified code generator to output binding syntax in collection predicates
packages/language/src/validators/attribute-application-validator.ts Updated validator to handle references to BinaryExpr targets
packages/plugins/policy/src/expression-transformer.ts Added BindingScope type and integrated binding support throughout expression transformation with proper scope propagation
packages/plugins/policy/src/expression-evaluator.ts Enhanced evaluator to support scoped bindings during expression evaluation
packages/sdk/src/prisma/prisma-schema-generator.ts Updated schema generator to extract binding names from BinaryExpr references
packages/language/test/expression-validation.test.ts Added tests validating both new binding syntax and backward compatibility with unbound syntax

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
tests/e2e/orm/policy/auth-access.test.ts (1)

133-175: Consider adding edge cases for more comprehensive coverage.

The test correctly validates the iterator binding feature for the basic scenario. To align with the comprehensiveness of similar tests in this file (e.g., lines 177-208), consider adding test cases for:

  • Empty memberships array: memberships: []
  • Missing memberships field: just { tenantId: 1 }
  • Multiple memberships with at least one match: memberships: [{ tenantId: 3 }, { tenantId: 1 }]
  • Multiple memberships with none matching: memberships: [{ tenantId: 3 }, { tenantId: 4 }]

These edge cases would provide stronger validation of the iterator binding semantics across different collection states.

Example test additions
// Empty memberships - should deny
await expect(
    db.$setAuth({ tenantId: 1, memberships: [] }).foo.findMany(),
).resolves.toEqual([]);

// Missing memberships field - should deny
await expect(
    db.$setAuth({ tenantId: 1 }).foo.findMany(),
).resolves.toEqual([]);

// Multiple memberships with one match - should allow
await expect(
    db.$setAuth({ 
        tenantId: 1, 
        memberships: [{ id: 20, tenantId: 3 }, { id: 10, tenantId: 1 }] 
    }).foo.findMany(),
).resolves.toEqual([
    { id: 1, tenantId: 1 },
]);
packages/language/src/zmodel-linker.ts (1)

259-278: Collection predicate resolution logic is sound.

The BinaryExpr handling correctly derives the element type from the collection type by setting array: false, which aligns with the iterator alias semantics introduced in this PR.

For improved type safety, consider using type guard functions instead of $type string comparisons where available:

🔎 Verify if type guards exist for EnumField and FunctionParam
#!/bin/bash
# Description: Check if type guard functions exist for EnumField and FunctionParam

# Search for type guard function definitions
rg -n "function isEnumField|function isFunctionParam" --type=ts packages/language/src/

# Also check in generated AST
rg -n "export function isEnumField|export function isFunctionParam" --type=ts packages/language/src/generated/ast.ts

If these type guards exist, import and use them instead of $type comparisons for better type narrowing.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb54db6 and aa4b30d.

📒 Files selected for processing (5)
  • packages/language/src/validators/attribute-application-validator.ts
  • packages/language/src/zmodel-linker.ts
  • packages/sdk/src/prisma/prisma-schema-generator.ts
  • packages/sdk/src/ts-schema-generator.ts
  • tests/e2e/orm/policy/auth-access.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/sdk/src/prisma/prisma-schema-generator.ts
  • packages/language/src/validators/attribute-application-validator.ts
🧰 Additional context used
📓 Path-based instructions (1)
tests/e2e/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

E2E tests should validate real-world schema compatibility with established projects

Files:

  • tests/e2e/orm/policy/auth-access.test.ts
🧠 Learnings (2)
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.test.{ts,tsx} : ORM package tests should include comprehensive client API tests and policy tests

Applied to files:

  • tests/e2e/orm/policy/auth-access.test.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/e2e/**/*.{ts,tsx} : E2E tests should validate real-world schema compatibility with established projects

Applied to files:

  • tests/e2e/orm/policy/auth-access.test.ts
🧬 Code graph analysis (3)
tests/e2e/orm/policy/auth-access.test.ts (1)
packages/testtools/src/client.ts (1)
  • createPolicyTestClient (258-269)
packages/language/src/zmodel-linker.ts (1)
packages/language/src/generated/ast.ts (6)
  • isBinaryExpr (267-269)
  • EnumField (437-443)
  • EnumField (445-445)
  • isDataField (345-347)
  • FunctionParam (480-486)
  • FunctionParam (488-488)
packages/sdk/src/ts-schema-generator.ts (1)
packages/language/src/generated/ast.ts (3)
  • isDataField (345-347)
  • isEnumField (447-449)
  • isBinaryExpr (267-269)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-test (22.x, sqlite)
  • GitHub Check: build-test (22.x, postgresql)
🔇 Additional comments (4)
packages/language/src/zmodel-linker.ts (2)

527-529: Good defensive guard.

The early return prevents potential null/undefined errors when accessing properties on the type parameter. This is a solid defensive programming practice.


125-131: Type safety for binding property access is properly implemented.

The binding property is explicitly defined as optional (binding?: string) in the BinaryExpr interface at packages/language/src/ast.ts:53, and the code correctly checks for property existence and type before accessing it. The implementation is type-safe.

packages/sdk/src/ts-schema-generator.ts (2)

1274-1285: LGTM! Clean conditional binding support.

The implementation correctly passes the optional binding parameter to ExpressionUtils.binary when present, aligning with the PR's goal of supporting iterator bindings in collection predicates.


1300-1323: Binding resolution through the language linker is properly implemented.

The code correctly handles binding references. The language linker (zmodel-linker.ts:257-267) resolves references to collection predicates as BinaryExpr targets, and the scoping system (zmodel-scope.ts:199-205) creates scope entries for binding names. The code properly extracts binding names from BinaryExpr targets, and the fallback behavior correctly treats unresolved references as field names for iterator bindings.

No further changes needed.

@mwillbanks
Copy link
Contributor Author

@ymc9 have you been able to take a look at this one? i was curious if you have any feedback or if this is looking correct to you.

@ymc9
Copy link
Member

ymc9 commented Jan 8, 2026

@ymc9 have you been able to take a look at this one? i was curious if you have any feedback or if this is looking correct to you.

I'm half way into reviewing it and will probably make a bit of refactor to how the binding is represented in the ZModel language definition. Will make a separate PR based on your branch soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants