-
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
c67ef0e
test(psl-parser): specify the declarative attribute-spec engine and i…
SevInf d3172fc
feat(psl-parser): add declarative attribute-spec engine and core types
SevInf ce2fa8c
feat(psl-parser): thread the active attribute diagnostic code to leaves
SevInf 7018247
feat(psl-parser): add the str/enumOf/fieldRef/list argument combinators
SevInf 319ee7c
feat(psl-parser): add identifierName leaf and unblock InferAttr on re…
SevInf 98032c8
refactor(sql-contract-psl): lower @relation through the declarative a…
SevInf de79343
docs(typed-attribute-parsers): project + slice-1 artifacts (spec, pla…
SevInf 3a0b448
fix(psl-parser): reject duplicate attribute arguments unconditionally
SevInf 906e26d
perf(psl-parser): drop the redundant list element copy
SevInf 225d2b7
fix(sql-contract-psl): reject duplicate columns in @relation fields/r…
SevInf 7cb5f75
refactor(sql-contract-psl): validate referential actions via enumOf
SevInf b917c7c
feat(psl-parser): resolve fieldRef against the scoped symbol table
SevInf 8ff2118
docs(typed-attribute-parsers): record D4 review-round-1 dispatch + pa…
SevInf d7e05ce
refactor(psl-parser): restrict enumOf to bare identifiers and number …
SevInf 6a28ef8
docs(typed-attribute-parsers): record D5 enumOf restriction + slice-3…
SevInf 003a5c8
Replace enumOf with composable oneOf + identifier combinators
SevInf d6fb2e5
docs(typed-attribute-parsers): record D6 enumOf->oneOf+identifier; fl…
SevInf 5f87537
docs(adr-231): reconcile with shipped oneOf/identifier design
SevInf be61351
docs(typed-attribute-parsers): record D7 ADR 231 reconciliation dispatch
SevInf 3ac48c8
refactor(utils): centralize Simplify/UnionToIntersection type helpers
SevInf e8ee5a9
refactor(psl-parser): require oneOf to have at least one alternative
SevInf ad54656
refactor(psl-parser): remove variadic positional support
SevInf 8fecd95
refactor(psl-parser): model optional params as a flavoured ArgType
SevInf c120b85
refactor(psl-parser): interpret attributes in a single pass
SevInf 236fe2d
refactor(sql-contract-psl): consume the relation spec output directly
SevInf 48bcda1
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.