Skip to content

v8.0.0-rc.17-dev.15

@StevenMcClankerton StevenMcClankerton tagged this 09 Oct 14:22
## Linked issue

n/a. First slice of the PSL mixins project; the project spec and plan
are in `projects/psl-mixins/`.

## At a glance

```ts
export interface BlockSymbol {
  readonly kind: 'block';
  readonly name: string;
  readonly keyword: string;
  readonly node: GenericBlockDeclarationAst;
  readonly span: PslSpan;
  readonly entries: readonly KeyValuePairAst[];
  readonly attributes: readonly ResolvedAttribute<ModelAttributeAst>[];
}
```

```diff
- for (const entry of block.node.entries()) {
+ for (const entry of block.entries) {
```

Before this PR a generic block symbol (an `enum`, a `policy_select`, any
extension block) carried only its name, keyword and syntax node, and
every consumer read the block's entries and attributes from the node.

## Summary

A consumer of the PSL symbol table now reads a declaration's members
from its symbol and never from the symbol's syntax node. This makes
`buildSymbolTable` the one place that decides which members a block has,
which the mixins work needs: a mixin's members will be added to a block
there, and every consumer has to see them. This PR changes no behaviour
and does not mention mixins in code.

## Decision

1. `BlockSymbol` gains `entries` and `attributes`, filled once by
`buildBlock` in source order. `entries` is a list, not a record, because
a map-mode block may repeat a key.
2. All 23 production sites that read members through `symbol.node` read
the symbol's records: the binder, the block-spec interpreter and the
enum-member check in `psl-parser`; the SQL interpreter and attribute
specs; the Prisma 7 and Prisma 6 interpreters; the language server's
rename provider.

## Reviewer notes

- **Two places paired lists by index and no longer do.**
`bindAttributes` in
[`binder.ts`](packages/1-framework/2-authoring/psl-parser/src/binder.ts)
and the model-attribute loop in the SQL
[`interpreter.ts`](packages/2-sql/2-authoring/contract-psl/src/interpreter.ts)
walked `node.attributes()` and the resolved attribute list side by side.
Each now takes the syntax node from the resolved attribute's own `node`.
The six `if (node === undefined) continue;` guards removed from the SQL
interpreter were unreachable: `model.attributes` is built from
`node.attributes()`, so the two lists always had the same length and
order.
- **Node identity is preserved.** The binder keys its tables by
syntax-node identity. Red nodes are cached per parent slot, so
`block.entries[i]` and `attribute.node` are the same objects a fresh
traversal returns.
- **`interpretExtensionBlockAttributes`** in
[`block-spec/interpret.ts`](packages/1-framework/2-authoring/psl-parser/src/block-spec/interpret.ts)
reads `name`, `span` and `args` from the resolved attribute. They are
computed by the same expressions it used inline before.
- **Deliberately not changed:** code that walks the syntax tree with no
symbol in hand (completion, semantic tokens, the formatter), and
`fieldTakesMap` in `rename.ts` finding a field's owner through
`field.node.syntax.parent`.
- **Project artifacts.** `projects/psl-mixins/` is added in this PR: the
project spec and plan, a brief used for the team's syntax discussion,
and this slice's spec, plan and dispatch briefs. The folder is removed
at project close-out.

## Testing performed

- `pnpm --filter @internal/psl-parser test`: 67 files, 1405 tests pass,
including six new symbol-table tests (source order, repeated keys, enum
members with `@` attributes, block `@@` attributes, a block inside a
namespace, an empty block). No existing assertion was edited.
- `pnpm lint:deps`, `pnpm fixtures:check` (no fixture changed), and
`lint` for the four touched packages: pass.
- `pnpm typecheck`: 170 of 171 tasks pass. `prisma7-adoption#typecheck`
fails on my machine because Prisma 7 publishes no schema engine for the
`linux-nixos` platform.
- `pnpm test:packages`: 1735 of 1738 files pass (24824 tests). Three
tarball-install tests (`@prisma/orm-framework` `all-shells-tarball` and
`module-identity`, `@prisma/orm-target-postgres` `cross-shell-tarball`)
fail locally with pnpm's `ERR_PNPM_TRUST_DOWNGRADE` for
`@vercel/detect-agent@1.2.5`.
- The four local failures reproduce with this PR's changes stashed. CI
is the check for them.
- `rg "\.node\.(fields|members|attributes|entries)\(\)" packages -g
'*.ts' --glob '!**/test/**' --glob '!**/dist/**'` returns nothing.

## Skill update

n/a — internal only.

## Alternatives considered

- **Leave consumers reading the node and teach each one about mixins
later.** That would put mixin knowledge into two family interpreters,
two legacy-schema interpreters, the binder and the language server.
Reading from the symbol keeps it in the symbol table.
- **`entries` as a record keyed by entry name.** Rejected because
map-mode blocks allow a repeated key, and order matters to consumers.

## Checklist

- [x] All commits are signed off (`git commit -s`) per the
[DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco).
- [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is
scoped to one logical concern.
- [x] Tests are updated (or `n/a` if the change is doc-only / refactor
with no behavioural delta).
- [ ] The PR title is in `TML-NNNN: <sentence-case title>` form. No
Linear ticket is used for this project.
- [x] The **Skill update** section above is filled in (or stated `n/a —
internal only`).

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Schema blocks and attributes are interpreted consistently across
authoring tools, language services, and database integrations. Block
entries retain source order and repeated keys, while attribute
diagnostics continue to use accurate source locations.
* **Documentation**
* Clarified that symbols expose their declaration members, including
block entries and attributes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Steven McClankerton <tatarintsev@prisma.io>
Co-authored-by: Steven McClankerton <tatarintsev@prisma.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Assets 2
Loading