-
Notifications
You must be signed in to change notification settings - Fork 12
tml-2956: PSL attribute-spec kit + @relation migration (1/3) #891
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
SevInf
wants to merge
26
commits into
main
Choose a base branch
from
tml-2956-typed-attribute-parsers
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
50419f9
test(psl-parser): specify the declarative attribute-spec engine and i…
SevInf 01f2770
feat(psl-parser): add declarative attribute-spec engine and core types
SevInf cb7a8e6
feat(psl-parser): thread the active attribute diagnostic code to leaves
SevInf 4ebc04e
feat(psl-parser): add the str/enumOf/fieldRef/list argument combinators
SevInf c3dd2e8
feat(psl-parser): add identifierName leaf and unblock InferAttr on re…
SevInf af25ef8
refactor(sql-contract-psl): lower @relation through the declarative a…
SevInf 58ab47f
docs(typed-attribute-parsers): project + slice-1 artifacts (spec, pla…
SevInf 1a26796
fix(psl-parser): reject duplicate attribute arguments unconditionally
SevInf d609f6e
perf(psl-parser): drop the redundant list element copy
SevInf 50c8127
fix(sql-contract-psl): reject duplicate columns in @relation fields/r…
SevInf e542700
refactor(sql-contract-psl): validate referential actions via enumOf
SevInf c92b9a9
feat(psl-parser): resolve fieldRef against the scoped symbol table
SevInf 232e5bc
docs(typed-attribute-parsers): record D4 review-round-1 dispatch + pa…
SevInf 8bb8e9a
refactor(psl-parser): restrict enumOf to bare identifiers and number …
SevInf 678b9ed
docs(typed-attribute-parsers): record D5 enumOf restriction + slice-3…
SevInf eafdb55
Replace enumOf with composable oneOf + identifier combinators
SevInf 302f1eb
docs(typed-attribute-parsers): record D6 enumOf->oneOf+identifier; fl…
SevInf dc7242e
docs(adr-231): reconcile with shipped oneOf/identifier design
SevInf 6087804
docs(typed-attribute-parsers): record D7 ADR 231 reconciliation dispatch
SevInf d3d674e
refactor(utils): centralize Simplify/UnionToIntersection type helpers
SevInf 93d0cf7
refactor(psl-parser): require oneOf to have at least one alternative
SevInf 0e5c6ca
refactor(psl-parser): remove variadic positional support
SevInf a336aa4
refactor(psl-parser): model optional params as a flavoured ArgType
SevInf b7451ad
refactor(psl-parser): interpret attributes in a single pass
SevInf 0d807aa
refactor(sql-contract-psl): consume the relation spec output directly
SevInf e120376
docs(typed-attribute-parsers): record D8 review-round-2 (engine simpl…
SevInf File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export type { Simplify, UnionToIntersection } from '../types'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| /** Flattens an intersection of mapped types into a single readable object type. */ | ||
| export type Simplify<T> = { [K in keyof T]: T[K] } & {}; | ||
|
|
||
| /** Collapses a union into the intersection of its members. */ | ||
| export type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends ( | ||
| k: infer I, | ||
| ) => void | ||
| ? I | ||
| : never; |
17 changes: 17 additions & 0 deletions
17
packages/1-framework/0-foundation/utils/test/types.test-d.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { expectTypeOf, test } from 'vitest'; | ||
| import type { Simplify, UnionToIntersection } from '../src/types'; | ||
|
|
||
| test('Simplify flattens an intersection into a single object type', () => { | ||
| type Input = { a: number } & { b: string }; | ||
| expectTypeOf<Simplify<Input>>().toEqualTypeOf<{ a: number; b: string }>(); | ||
| }); | ||
|
|
||
| test('Simplify preserves optional modifiers', () => { | ||
| type Input = { a: number } & { b?: string }; | ||
| expectTypeOf<Simplify<Input>>().toEqualTypeOf<{ a: number; b?: string }>(); | ||
| }); | ||
|
|
||
| test('UnionToIntersection collapses a union of objects into their intersection', () => { | ||
| type Input = { a: number } | { b: string }; | ||
| expectTypeOf<UnionToIntersection<Input>>().toEqualTypeOf<{ a: number } & { b: string }>(); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
packages/1-framework/2-authoring/psl-parser/src/attribute-spec/combinators/diagnostic.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast'; | ||
| import { nodePslSpan } from '../../resolve'; | ||
| import type { AstNode } from '../../syntax/ast-helpers'; | ||
| import type { InterpretCtx } from '../types'; | ||
|
|
||
| /** | ||
| * Builds a leaf diagnostic anchored to the offending `node`, stamped with the | ||
| * code threaded through `ctx`. Combinators emit through this helper so every | ||
| * leaf carries the active attribute's code rather than a hard-coded generic. | ||
| */ | ||
| export function leafDiagnostic(ctx: InterpretCtx, node: AstNode, message: string): PslDiagnostic { | ||
| return { | ||
| code: ctx.diagnosticCode, | ||
| message, | ||
| sourceId: ctx.sourceId, | ||
| span: nodePslSpan(node.syntax, ctx.sourceFile), | ||
| }; | ||
| } |
50 changes: 50 additions & 0 deletions
50
packages/1-framework/2-authoring/psl-parser/src/attribute-spec/combinators/field-ref.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast'; | ||
| import { notOk, ok, type Result } from '@prisma-next/utils/result'; | ||
| import { IdentifierAst } from '../../syntax/ast/identifier'; | ||
| import type { ArgType } from '../types'; | ||
| import { leafDiagnostic } from './diagnostic'; | ||
|
|
||
| /** | ||
| * The entity a field name resolves against: the declaring model (`'self'`) or a | ||
| * relation's target model (`'referenced'`). Carried for the language server; | ||
| * the value parsed at runtime is just the name. | ||
| */ | ||
| export type FieldRefScope = 'self' | 'referenced'; | ||
|
|
||
| /** A field-name combinator tagged with the scope its name resolves against. */ | ||
| export interface FieldRefArgType extends ArgType<string> { | ||
| readonly scope: FieldRefScope; | ||
| } | ||
|
|
||
| /** | ||
| * Parses a bare identifier into a field name and resolves it against the scoped | ||
| * model: `'self'` against the declaring model, `'referenced'` against a | ||
| * relation's target. A name absent from the resolved model emits the | ||
| * field-existence diagnostic here, anchored to the identifier. When the | ||
| * referenced model is out of scope (e.g. a cross-space target the parser cannot | ||
| * see), existence cannot be checked, so the name is carried through unchecked | ||
| * and validated where the target is known. The parsed value is always the name. | ||
| */ | ||
| export function fieldRef(scope: FieldRefScope): FieldRefArgType { | ||
| return { | ||
| kind: 'fieldRef', | ||
| label: 'field name', | ||
| scope, | ||
| parse: (arg, ctx): Result<string, readonly PslDiagnostic[]> => { | ||
| if (!(arg instanceof IdentifierAst)) { | ||
| return notOk([leafDiagnostic(ctx, arg, 'Expected a field name')]); | ||
| } | ||
| const name = arg.name(); | ||
| if (name === undefined) { | ||
| return notOk([leafDiagnostic(ctx, arg, 'Expected a field name')]); | ||
| } | ||
| const model = scope === 'self' ? ctx.selfModel : ctx.resolveReferencedModel(); | ||
| if (model !== undefined && !Object.hasOwn(model.fields, name)) { | ||
| return notOk([ | ||
| leafDiagnostic(ctx, arg, `Field "${name}" does not exist on model "${model.name}"`), | ||
| ]); | ||
| } | ||
| return ok(name); | ||
| }, | ||
| }; | ||
| } | ||
23 changes: 23 additions & 0 deletions
23
packages/1-framework/2-authoring/psl-parser/src/attribute-spec/combinators/identifier.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast'; | ||
| import { notOk, ok, type Result } from '@prisma-next/utils/result'; | ||
| import { IdentifierAst } from '../../syntax/ast/identifier'; | ||
| import type { ArgType } from '../types'; | ||
| import { leafDiagnostic } from './diagnostic'; | ||
|
|
||
| /** | ||
| * Matches a bare identifier whose name equals `name`, returning that name with | ||
| * its literal type preserved. Pinned-only: there is no open form, so several | ||
| * `identifier`s composed under `oneOf` infer the precise union of names. A | ||
| * non-identifier token, or an identifier with a different name, is rejected with | ||
| * the threaded code, anchored to the argument node. | ||
| */ | ||
| export function identifier<const N extends string>(name: N): ArgType<N> { | ||
| return { | ||
| kind: 'identifier', | ||
| label: name, | ||
| parse: (arg, ctx): Result<N, readonly PslDiagnostic[]> => { | ||
| if (arg instanceof IdentifierAst && arg.name() === name) return ok(name); | ||
| return notOk([leafDiagnostic(ctx, arg, `Expected ${name}`)]); | ||
| }, | ||
| }; | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.